Jan 23, 2018 - POP_part16

사상 - 프로그래밍 이데올로기

UNIX 사상

복구의 원칙

소프트웨어 동작중에 오류복구에 실패 했다고 하면 처리는 계속하면 안된다 그리고 오류는 한눈에 띄도록 발생시킨다. 소프트웨어 동작은 평상시 뿐만 아니라 오류시에도 투명해야 한다.

오류를 복구하지 못했는데 계속 동작시키면 피해를 확대시킨다. 그리고 오류는 가능한 요란하게 통지를 하자

소프트 웨어 입출력에 관한 받아드릴때는 자유로이 내보낼때는 보수적으로 라는 사고방식이 있다.

경제성의 원칙

프로그래머의 시간을 소중히 하자 설비와 프로그래머의 비용을 따졌을때 후자의 비용이 비싸다 그래서 프로그래머가 쓸때 없는데 시간을 보내는것을 방지하자.

  • 빈약한 하드웨어
  • 사용 소프트웨어에 대한 제한
  • 환경에 관한 규제와 제한

생성의 원칙

코드를 작성하기 위한 코드를 작성하자. 반복되는 작업은 실수를 하기 마련 반복 작업을 없에는 코드 생성기를 만들자.

최적화의 원칙

빠른 코드 보단 바른코드를 작성하자. 투명성과 단순성이 희생된다. 성능 튜닝을 위해 하나씩 잡다보면 많은 시간을 낭비하게 된다. 그리고 부분적인 어중간한 최적화가 전체의 최적화를 방해한다. 바르게 동작하게 만든후에 최적화를 하자.

다양성의 원칙

선택적 다향성을 수용한다. 소프트웨어에서는 유일하게 바른방법이 있다는 주장을 믿으면 안된다. 더좋은 방식을 계속 찾는다.

확장성의 원칙

확장할 수 있게 설계한다. 코드에는 항상 성장의 여지를 남겨 놓아야 된다. 자신의 코드를 나중에 보수할 사람이 이미 내용을 잊어 버린 자기자신일수도 있다. 장래를 내다 보고 설계를 하면 자기 자신을 구제 할수도 있다.

UNIX 철학

작은것이 아름답다.

작은 소프트웨어은 아름답다. 작은 소프트웨어는 다루기 쉽다.

  • 이해가 쉽다.
  • 유지보수가 쉽다.
  • 하드웨어에 부담을 주지 않는다.
  • 다른 소프트웨어와 조합하기 쉽다.

큰 소프트웨어는

  • 복잡하고 코드를 이해라기 어렵다.
  • 예측하지 못한 사태에 대응할 수 없다.

작게 만들어서 작게 유지를 하자.

한번에 하나의 작업

하나의 소프트웨어는 하나의 작업을 시키자 가장 좋은 소프트웨어는 생애중 단 하나의 작업만을 제대로 완수하는 소프트웨어이다. 하나의 작업만 진행하면 소프트웨어는 순수해진다.

즉시 프로토타입 진행

가능한 빨리 프로토타입을 만든다. 시행착오 없이 좋은것을 만들수는 없다.

프로토 타입의 장점은

  • 전체의 착오를 조기에 발견할 수 있다.
  • 요구사항 불충분에 따른 재작업을 줄일 수 있다.
  • 조기에 착오를 바로 잡는 작업을 시작할 수 있다.

제1시스템 : 성능은 매우 높지만 필요한 기능이 몇가지 빠져있다. 제2시스템 : 시계추가 반대로 돌아가 이번에는 기능은 많지만 성능이 희생되어 있다. 제3시스템 : 양자 간에 최적의 균형을 모색한 결과 정말로 필요한 기능만 남고 적정 자원으로 대부분 목표달성

프로토 타입의 목표는 제3시스템으로 해야된다.

참조


Jan 18, 2018 - POP_part15

사상 - 프로그래밍 이데올로기

UNIX 사상

표현성의 원칙

정보는 데이터에 모아 표현 정보를 데이터에 표현하면 로직은 읽기 쉬워진다. 왜냐고 하면 데이터는 로직보다 다루기 쉽다.그래서 데이터가 복잡해야 되는지 아니면 로직이 복잡해야 되는지 고민하지 말고 데이터를 복잡하게 하자.

충격 최소의 원칙

인터페이스는 예상대로 동작하도록 만든다. 즉 사용자의 충격을 최소로 설계해야 된다. 학습에 대한 비용이 낮아지게 된다 새롭게 배워야 되는 부분이 있는데 기존에 있는 지식과 연결이 되서 쉽게 학습이 가능해진다. 그리고 인터페이스를 설계 할때는 사용자의 기존지식들을 활용한다.

  • 유사점이 많은 소프트웨어의 인터페이스를 모델로 삼는다
  • 예상 사용자의 특성을 고려한다.
  • 전통에 주의를 기울인다.
  • 언뜻 보면 비슷하지만 미묘하게 다른 상황을 피한다.

침묵의 원칙

소프트웨어는 과묵해야 된다. 표시를 최대한 줄이고 과묵하게 작업을 진행해야 된다. 왜냐하면 메시지 출력이 많으면 중요한 정보를 찾기가 어렵다. 그래서 중요한 정보만 표시해서 출력해야 된다.

참조


Jan 17, 2018 - codespitz73_part4

코드스피츠73 part4

ABSTRACT LOOP & LAZY EXECUTION

단순한 루프


{
    [Symbol.iterator](){return this;},
    data : [1,2,3,4],
    next() {
        return {
            //계속 반복할지 판단 
            done : this.data.length === 0,
            //반복시마다 처리할 것
            value : this.data.shift()
           
        };
    }
}

복잡한 루프


{
    [Symbol.iterator](){return this;},
    data : [{a:[1,2,3,4], b:'-'},[5,6,7],8,9],
    next() {
        let v;
        while (v = this.data.shift()){
            switch (true){
                case Array.isArray(v):{
                    this.data.unshift(...v);
                    break;
                }
                case v && typeof v == 'object':{
                    for(let k in v) this.data.unshift(v[k]);
                    break;
                }
                default : return {value: v, done:false}
            }
        }
        return {done:true}
    }
}

ABSTRACT LOOP

다양한 구조의 루프와 무관하게 해당 값이나 상황만 개입만 하고 싶은경우

(data, f) => {
    let v;
    while (v = data.shift()){
        if(!(v instanceof Object)) f(v);
        else {
            if(!Array.isArray(v)) v = Object.values(v);
            data.unshift(...v);
        }
    }
}

위에 함수에서 console.log 만 추가 할려고 해도 아래 처럼 수정 할수 밖에 없다.


(data, f) => {
    let v;
    while (v = data.shift()){
        if(!(v instanceof Object)){
            console.log(v);
            f(v);
        } else {
            if(!Array.isArray(v)) v = Object.values(v);
            data.unshift(...v);
        }
    }
}

코드는 고정 되어 있고 변수가 상태를 바꾼다. 위에 함수를 객체화로 바꾸면 아래 처럼 된다.

팩토리 + 컴포지트


const Operator = class{
    static factory(v){
        if(v instanceof Object){
              if(!Array.isArray(v)) v = Object.values(v);
              return new ArrayOp(v.map(v=> Operator.factory(v)));
        }else{
            return new PrimaOp(v);
        }
    }
    constructor(v){
        this.v = v;
    }
    operation(f){throw 'override';}
};

const PrimaOp = class extends Operator{
        constructor(v){
            this.v = v;
        }
        operation(f){
            f(this.v);
        }
};

const ArrayOp class extends Operator{
    constructor(v){
        this.v = v;
    }
    operation(f){
        for(const v of this.v){
            v.operation(f);
        }
    }
};

Operator.factory([1,2,3,{a:4,b:5},6,7]).operation(console.log);

팩토리 + 컴포지트 + ES6 Iterable



const Operator = class{
    static factory(v){
        if(v instanceof Object){
              if(!Array.isArray(v)) v = Object.values(v);
              return new ArrayOp(v.map(v=> Operator.factory(v)));
        }else{
            return new PrimaOp(v);
        }
    }
    constructor(v){
        this.v = v;
    }
    *gene(){throw 'override';}
};

const PrimaOp = class extends Operator{
        constructor(v){
            this.v = v;
        }
        *gene(){
           yield this.v;
        }
};

const ArrayOp class extends Operator{
    constructor(v){
        this.v = v;
    }
    *gene(){
        for(const v of this.v){
            yield * v.gene()
        }
    }
};

for(const v of Operator.factory([1,2,3,{a:4,b:5},6,7]).gene()) console.log(v);

LAZY EXECUTION

YIELD


const odd = function*(data) {
  for (const v of data){
      console.log('odd',odd.cnt ++);
      if(v % 2) yield v;
  }
};

odd.cnt =0;
for(const v of odd([1,2,3,4])) console.log(v);

const take= function*(data, n) {
    for (const v of data){
        console.log('take',take.cnt ++);
        if(n--) yield v; else break;
    }
};

take.cnt =0;
for(const v of take([1,2,3,4], 2)) console.log(v);

for(const v of take(odd([1,2,3,4]), 2)) console.log(v);


YIELD*


const Stream = class{
    static get(v){return new Stream(v);}
    constructor(v){
        this.v = v;
        this.filters = [];
    }
    add(gene, ...arg){
        this.filters.push(v=>gene(v, ...arg));
        return this;
    }
    *gene(){
        let v = this.v;
        for(const f of this.filters) v = f(v);
        yield* v;
    }
};

const odd = function*(data){
    for(const v of data) if(v % 2) yield v;
};

const take = function*(data, n){
    for(const v of data) if(n--) yield v; else break;
};

for(const v of Stream.get([1,2,3,4]).add(odd).add(take, 2).gene()) console.log(v);

어렵네요… ㅜㅜ

참조