Feb 19, 2018 - CodeSpitz74_Part4

코드스피츠 74 4회차

프로그램 짤때는 권한과 책임이 일치하게 짜야 된다. 권한과 책임이 일치하면 그것을 역활이라고 한다.

TETRIS 객체후보

  • STAGE(현재 스테이지 정보)
  • SCORE(점수 및 계산법)
  • BLOCK(범용 블록정의) - 색깔, 회전
  • 게임본체
  • 범용 패널
  • 시작화면
  • 스테이지 종료
  • 죽음
  • 클리어
  • 결과 화면

추상화

  • 일반화(카테고라이즈) - 기준점은 역활이다
  • 모델링 - 기억해야만 하는것
  • 그룹핑 - 랜덤하게 묶이는것(권한)

직접 통신 방법 보다 인터페이스를 통해서 통신해야 된다. 수정에 열려있다.


const Stage = class{
    init(listener){
        this.listener = listener;
    }
    clear(){
        this.stage = 0;
        this.next();
    }
    next(){
        if(this.stage++ < Stage.maxStage){
            this.speed = 500 - 450 * this.stage / Stage.maxStage;
            this.listener();
        }
    }
    [Symbol.toPrimitive](hint){
        return `<div>Stage ${this.stage}</div>`;
    }
};

Stage.maxStage = 20;

const Score = class{
        init(listener){
            this.listener = listener;
        }
        clear(){
            this.curr = this.total = 0;
        }
        add(line, stage){
            const score = parseInt((stage * 5) * (2 * line));
            this.curr += score, this.total += score;
            this.listener();
        }
        [Symbol.toPrimitive](hint){
            return `<div>Stage ${this.curr} / ${this.total}</div>`;
        }
};

블록 부모 클래스 정의


const Block  = class{
    constructor(color){
        Object.assign(this,{color, rotate:0});
    }
    left(){
        if(--this.rotate <0){
            this.rotate = 3;
        }
    }
    right(){
        if(++this.rotate <3){
            this.rotate = 0;
        }
    }
    getBlock(){
        throw 'override!';
    }
};

블록 자식클래스 정의


const blocks = [class extends Block, ....];

class extends Block{
    constructor(){
        super('#f8cbad');
    }
    getBlock(){
        return this.rotate % 2 ? [[1],[1],[1],[1]] : [[1,1,1,1]] 
    }

};


class extends Block{
    constructor(){
        super('#ffe699');
    }
    getBlock(){
        switch (this.rotate){
            case 0:return [[0,1,0],[1,1,1]];
            case 1:return [[1,0],[1,1],[1,0]];
            case 2:return [[1,1,1],[0,1,0]];
            case 3:return [[0,1],[1,1],[0,1]];
        }
    }

};

위에서 자식 클래스에서 중복이 생김 부모 클래스에 추가작업


const Block  = class{
    constructor(color){
        Object.assign(this,{color, rotate:0});
    }
    left(){
        if(--this.rotate <0){
            this.rotate = 3;
        }
    }
    right(){
        if(++this.rotate <3){
            this.rotate = 0;
        }
    }
    getBlock(){
        return this.blocks[this.rotate];
    }
};

랜더러 생성


const Renderer = class{
    constructor(col, row, base, back){
        Object.assign(this,{col, row, base, back, blocks:[]});
    }
    
    clear(){
        throw 'override!';
    }
    
    render(data){
        if(!(data instanceof Data)) throw 'invalid data';
        this._render(data);
    }
    _render(data){
        throw 'override!';
    }
};

데이터 생성


const Data = class extends Array{
    constructor(col, row,){
        Object.assign(this,{col, row});
    }
    
    cell(row,col,color){
        if(row > this.row || col > this.col) throw 'invalid';
        (this[row] || (this[row] = []))[col] = color;
    }
    
    row(row, ...color){
        color.forEach((v, i)=> this.cell(row,i,v));
    }
    
    all(...rows){
        rows.forEach((v, i)=> this.row(i, ...v));
    }
};

랜더러 상속후 구현


const el = el=>document.createElement(el);
const back = (s, v){
    s.backgroundColor = v;
};

const TableRenderer = class extends Renderer{
    constructor(col, row, base, back, style){
        super(col, row, el('table'), back)
        const {col, base, blocks} = this;
        base.style.cssText = style;
        let i = this.row;
        while (i--){
            const tr = base.appendChild(el('tr'));
            const curr = [];
            let j = col;
            blocks.push(curr);
            while (j--) curr.push(tr.appendChild(el('td')).style);
        }
    }
    clear(){
        this.blocks.forEach(curr=>curr.forEach(s=>back(s,this.back)));
    }
    _render(v){
        this.blocks.forEach((curr,i)=>curr.forEach((s,j)=>back(s, v[i][j])));
    }
    
};

캔버스


const el = el=>document.createElement(el);
const back = (s, v){
    s.backgroundColor = v;
};

const CanvasRenderer = class extends Renderer{
    constructor(col, row, back, style){
        super(col, row, el('canvas'))
        const {col, base, blocks} = this;
        base.style.cssText = style;
        Object.assign(this, {
            width:base.width = parseInt(base.style.width),
            height:base.height = parseInt(base.style.height),
            cellSize:[base.width/col,base.height/row],
            ctx:base.getContext('2D')
        });
    }
    clear(){
        this.ctx.clearRect(0,0,this.width, this.height);
    }
    _render(v){
      this.clear();
      const {col, ctx, cellSize:[w,h]} = this;
      let {row:i} = this;
      while (i--){
          let j = col;
          while (j--){
              ctx.fillStyle = v[i][j];
              ctx.fillRect(j*w,I*h,w,h);
          }
      }
    }
    
};

참조


Feb 14, 2018 - POP_part22

관점 - 프로그래머가 보는 시각

비자아적 프로그래밍

프로그래밍 할때는 자아를 버려야 된다. 자존심과 자만을 버리고 동료에게 협력을 구하자 코드를 작성할때는 자기 능력을 뽐내는것이 아니라 코드가 더 좋아지는 것에 초점을 맞추어야 한다.

  • 자기 자신도 실수를 저지른다는 점을 이해하고 받아들인다.
  • 작성한 코드는 자기 자신이 아니다.
  • 아무리 끝까지 간 것 같아도 위에는 그이상이 있다.
  • 상담 없이 코드를 재작성하지 않는다.
  • 자기보다 기술이 떨어지는 사람에게도 존경과 경의, 인내를 가지고 대한다.
  • 세상에서 유일하게 변하지 않는 것은 변한다는 사실뿐이다.
  • 진정한 권위는 지위가 아니라 지식에서 생겨난다.
  • 신념을 위해 싸운다. 다만 패배는 깨끗이 수용한다.
  • 방에 틀어박혀 있어서는 안 된다.
  • 사람에게는 관대하고 코드에는 엄격하게, 사람이 아닌 코드를 비평한다.

한걸음씩 조금씩

하나씩 작은 단위에 일을 수행하자. 한번에 여러작업을 하지않고 하나의 일만 하자.

TMTOWTDI(There’s more than one way to do it)

방법은 하나가 아니다. 여러가지 선택지를 준비해야 한다.

기법 - 프로그래머의 도구 상자

예광탄

최종 형태에도 남는 골격 코드 실제 환경과 똑같은 제약 조건에서 발사할 수 있기 때문에 그만큼 얻어지는 정보의 정밀도는 높아진다.

  • 사용자에게 피드백을 얻을수 있다.
  • 프로그래머가 할약할 수 있는 무대를 조기에 정비할 수 있다.
  • 디버깅과 테스트를 빠르고 정확하게 할 수 있다.
  • 데모 가능한 소프트웨어를 확보할 수 있다.
  • 진척 상태가 명확해진다.

프로토타입과의 차이

프로토타입이란 실제 동작하지 않아도 되고 유사하게 동작만 인식시켜주면 된다. 예광탄은 소프트웨어 전체가 어떤식으로 연계되는지 명확히 한다.

프로토타입은 견본품이자 시제품

견본품- 사용자의 요구사항을 정확하게 파악하는것이 목적 시제품 - 개발 방법을 검토하는 것이 목적

참조


Feb 12, 2018 - POP_part21

관점 - 프로그래머가 보는 시각

프로그래머의 3대 미덕

  • 태만 - 반복적인 작업은 시스템화 하자
  • 성급 - 일어날수 있는 일은 먼저 작업하자
  • 오만할것 - 남에게 부끄럽지 않게끔 작업하고 보수하자.

프로그래머는 중노동에 대해서는 보상받지 못한다. 자기가 일하는 시간이나 노력을 줄이면 줄일수록 프로젝트에 대한 기여는 커진다.

보이 스카우트 규칙

보이스카우트의 규칙은 자기가 머물렀던 자리를 떠날 때는 자기가 왔을때보다 깨끗이 치워야 한다는 규칙이다. 코드도 마찬가지고 깨끗하게 하고 떠나야 된다. 코드에 부패를 막기위해서이다.

코드에서 지름길을 택하면 나중에 시간이 더걸릴수도 있다.

성능튜닝에 관한 금언

최적화의 규칙

  • 해서는 안된다.
  • 아직 해서는 안된다.

빠른코드는 트레이드 오프가 있다.

  • 가독성 저하
  • 품질의 저하
  • 복잡성의 증가
  • 보수의 저해
  • 환경 간의 경합
  • 작업량의 증대

소프트웨어의 성능

  • 실행환경
  • 배치 또는 설치 설정
  • 사용하고 있는 미들웨어
  • 사용하고 있는 라이브러리
  • 상호 운용하고 있는 구 시스템
  • 아키텍처

아키텍처를 설계할때 성능을 고혀하는 쪽이 좋은 경우도 있다.

성능튜닝의 순서

  • 최적화의 필요성을 증명한다.
  • 성능을 계측하고 병목을 특정한다.
  • 병목 코드를 최적화한다.
  • 성능을 계측하고 최적화 효과를 확인한다.
  • 최적화한 코드의 동작에 문제가 없음을 검증한다.

참조