2014년 10월 21일 화요일

명령어/쿼리 분리

명령어/쿼리 분리는 버트란드 메이어Bertrand Meyer에 의해 처음 기술된 설계 원칙으로, 간단히 말하면 다음과 같다. 하나의 메소드는 하나의 명령어이거나 쿼리여야 한다는 것이고, 두 가지 기능을 모두 가져서는 안 된다는 원리이다. 명령어는 객체의 상태를 수정할 수 있는 메소드이지만 값은 반환하지 않는다. 쿼리는 값을 반환하지만 객체를 변화시키지는 않는다.

이러한 원칙은 왜 중요할까? 여러가지 이유가 있겠지만 가장 중요한 것은 통신 때문이다. 임의의 메소드가 쿼리라면 부작용을 일으키지 않으면서 여러 번 그 메소드를 사용할 수 있을지 없을지를 확인하기 위해 그 메소드의 바디를 살펴볼 수밖에 없다.

출처: 레거시 코드 활용 전략 - 마이클 C. 페더스

책임 찾기

단일 책임 원칙

모든 클래스는 단일 책임을 가진다. 즉, 모든 클래스는 시스템에서 단일 목적을 가지고 그 클래스를 변경하는 이유는 단 하나만 있어야 한다

인터페이스 분리 원칙

큰 클래스에서는 모든 클라이언트들이 해당 클래스에 있는 모든 메소드들을 사용하게 되는 경우가 드물다. 우리는 특정 클라이언트가 주로 사용하는 메소드들을 다른 방식으로 그룹화 하는 경우를 종종 볼 수 있다. 이러한 그룹화된 것들에 대한 각각의 인터페이스를 생성하고 그러한 인터페이스들을 구현하는 하나의 큰 클래스를 가지면, 모든 클라이언트는 특정 인터페이스를 통해 큰 클래스를 볼 수 있게 된다. 이렇게 함으로써 정보를 감출 수 있고 시스템 내의 의존관계를 줄일수 있다. 이제 클라이언트들은 그 큰 클래스가 재컴파일 할 때마다 자신들도 재 컴파일해야 했던 번거로움에서 벗어날 수 있다.

책임 찾기

  1. 메소드들을 그룹화 하라
    비슷한 메소드 명들을 찾아보자. 접근 방식(퍼블릭, 프라이빗 등)과 함께 클래스 상의 모든 메소드들을 적어 보고, 묶을 만한 메소드들이 있는지 찾아보자
  2. 숨겨진 메소드들을 살펴보라
    프라이빗 메소드들과 프로텍티드 메소드들에 주의하라. 하나의 클래스가 이런 프라이빗이나 프로텍티드 메소드들을 많이 가지고 잇다면, 해당 클래스 내에 간절히 밖으로 나오고 싶어하는 또 다른 클래스가 있다고 보면 된다
  3. 변경할 수 있는 결정사항들을 찾아라
    결정사항들을 찾아야 한다. 코드 내에서 내리고 있는 결정사항들이 아니라 당신이 이미 해놓은 결정사항들을 의미한다. 데이터베이스와의 대화, 다른 객체들과의 대화 등 하드 코딩된 것처럼 보이는 작업을 수행하는 다른 방법이 있을까? 아울러 코드가 변경된다는 생각을 할 수 있을까?
  4. 내부 관계들을 찾아내라
    인스턴스 변수들과 메소드들 사이의 여러 관계를 찾아라. 어떤 메소드는 특정 인스턴스 변수를 사용하는 반면에, 다른 메소드는 그 인스턴스 변수를 사용하지 않는 것은 아닌가?
  5. 주된 책임을 찾아라
    클래스의 책임을 한 문장으로 기술하도록 하라
  6. 다른 모든 방법이 실패할 경우, 스크래치 리팩토링을 어느 정도 사용하라
    한 클래스 내에 있는 책임들을 찾아내기가 쉽지 않다면 스크래치 리팩토링을 어느 정도 사용해 보는 것도 좋은 방안이다
  7. 현재 작업에 집중하라
    지금 당장 처리해야 하는 작업에 주의를 기울여라. 어떤 작업을 수행하는 다른 방식을 제공하고 있다면 추출해야 할 책임 하나를 먼저 식별한 후에 그것에 필요한 대체를 허용하는 순으로 작업하라
출처: 레거시 코드 활용 전략 - 마이클 C. 페더스

헤더 파일에 헤더 파일 추가하지 않는 법

  1. 프리컴파일 해더에는 표준, 써드파티 또는 거의 변경되지 않는 라이브러리의 해더만 포함하자
  2. #include보다는 forward declaration을 사용하자
    1. class
    2. struct
    3. function
    4. enum 
    5. typedef
  3. value 맴버보다 reference 맴버를 사용하라
  4. inner 클래스나 enum을 만들지 마라
  5. 구현부를 숨겨라
  6. 인터페이스로 만들어라
참고자료
  1. Effective C++, 항목 31

기획이 불확실한 경우에 프로그래밍 절차

프로젝트의 기획이 명확하지 않은 경우 - 게임의 경우, 항상 그런것 같다 - 나에게는 잘 맞는 개발 절차다.

기본 철학

  1. 실용주의 - 할 일만 최소한으로 한다
  2. 빠른 피드백 루프 - 만들고, 보여주고, 수정한다 
  3. 좋은 코드 - 읽기 쉽고 요구사항을 충족한다

절차

  1. 핵심기능을  단순하고 빠르게 구현한다
  2. 피드백을 받아서 코드를 수정한다
  3. 다음 작업을 시작하기 전에 리팩토링을 한다
  4. 1번으로 돌아간다

설명

핵심기능을  단순하고 빠르게 구현한다

요구사항에 있는 선에서 최대한 빠르게 실행해볼 수 있는 구조로 코드를 작성한다. 이 때는 좋은 코드에 대해서 고민하지 않는다. 그저 적은 코드로 빠르게 테스트 하는 것에 집중한다.
좋은 코드란, 읽기 쉽고 요구사항을 최대한 충족하는 것이다. 요구 사항의 핵심 기능만 분명할 뿐, 나머지는 변경의 여지가 있다. 그래서 핵심 기능만 단순하게 구현하여 변경 사항을 확인하고 코드에 대비한다.

피드백을 받아서 코드를 수정한다

빠른 피드백 루프의 핵심을 빠른 수정이다. 빠른 수정을 위해서 가장 좋은 대비 방법은 단순한 개념과 코드다. 개념과 코드를 단순하게 유지하면, 수정하기 쉽다. 개념이 단순하면 사고도 유연해 진다.

다음 작업을 시작하기 전에 리펙토링을 한다

리펙토링을 아무런 기준없이 하는 것은 끝이 없는 일을 하는 것과 같다. 리펙토링은 좋은 코드를 만들기 위해서 한다. 좋은 코드란 읽기 쉽고 요구사항을 최대한 충족하는 것이다. 따라서, 다음 추가할 작업은 리펙토링의 좋은 기준이 된다.

1번으로 돌아간다

3번과 4번은 동시에 진행된다. 다음 요구사항을 빠르고 구현하기 위해서 리펙토링을 중간중간에 하는 것이다.

결론

리펙토링은 다음 수정사항을 목표로 코드 작성 중간중간에 해야된다. 따라서, 프로그래머에게 충분한 작업 시간을 주는 것이 무엇보다도 중요하다

10가지 Visual Studio 디버거 팁

출처: 10 More Visual Studio Debugging Tips for Native Development

  1. 예외 시에 멈추기
  2. 조사식 창에서 가상 변수(Pseudo-variables)
  3. 영역을 빠져나간 후에 힙 객체 보기
  4. 배열을 영역으로 보기
  5. 원하지 않는 함수로 한단계 들어가서 실행 안하기
  6. 코드에서 디버거 실행하기
  7. 출력 창에 프린트
  8. 메모리 누수 고립 시키기
  9. 릴리즈 빌드에서 디버깅하기
  10. 원격 디버깅하기


추상 데이터 형(ADT)

출처: Code Complete2 6.1절 요약

효율적인 프로그래머가 되기 위한 핵심 요소는 다른 코드를 작업하는 동안 무시해도 좋은 프로그램의 부분을 최대화하는 것이다
  1. ADT는 데이터와 연산의 집합이다. 그러나 "데이터"는 느슨하게 사용된다
  2. ADT를 먼저 생각하고 클래스를 두 번째로 생각하는 것은 언어로의 프로그래밍과 언어에서의 프로그래밍의 한 예이다
  3. 저수준 구현 도메인보다 문제 도메인에서 작업할 수 있는 힘을 사용하도록 하라!

ADT 예

  1. 선박제어
    1. 속력을 설정한다
    2. 현재 설정을 얻는다
    3. 이전 속력으로 달린다
    4. 사용을 중지한다
  2. 전구
    1. 켠다
    2. 끈다

ADT 혜택

  1. 세부적인 구현 사항을 감출 수 있다
  2. 변경이 전체 프로그램에 영향을 미치지 않는다
  3. 인터페이스가 보다 많은 정보를 제공하도록 만들 수 있다
  4. 성능을 향상시키기가 쉽다
  5. 외관상으로 프로그램이 정확하다는 것을 더 잘 알 수 있다
  6. 프로그램이 보다 더 스스로를 설명하게 된다
  7. 프로그램에 모든 데이터를 넘길 필요가 없다
  8. 저수준 구현 구조체 대신 실세계의 개체들을 다룰 수 있다

ADT 사용지침

  1. 전형적인 저수준 데이터 형을 ADT로  만들어라
  2. 파일과 같은 일반적인 객체들을 ADT로 취급하라
  3. 간단한 항목이라도 ADT로 취급하라

ADT와 클래스

  • 클래스에 대해서 생각하는 한 가지 방법은 ADT에 상속과 다형성을 더한 것으로 생각하는 것이다

AStyle과 Google Cpplint로 C++ 코드 스타일 자동화하기

코드 스타일을 잘 지키는 것도 중요하지만, 스타일을 지키는 비용도 중요하다. 구글 스타일 가이드를 지향하되 20/80 법칙에 따라 비용을 최소화하기 위해 절충했다.

준비물

  1. AStyle Extension
  2. Cpplint
  3. Python2.7 이상

AStyle Extension

AStyle Extension을 설치한다. Visual Studio 설정에서 AStyle Formatter를 선택하고 C/C++에서 구글 스타일 가이드에 맞는 설정을 한다.

--style=google --indent=spaces=2 --max-code-length=80 --pad-header --unpad-paren --keep-one-line-blocks --mode=c
그리고, "Format on save"옵션을 체크하면된다.

이제 문서를 수정하다가 저장하면 자동으로 포맷을 수정해준다.

Python2.7

그냥 설치하면된다.

Cpplint

Cpplint.py는 그냥 파이썬 스크립트이다. 따라서 대강 어딘가에 저장한다. - 솔수션 파일과 같은 위치 -. Visual Studio에서 자동으로 사용하기 위해서는 외부도구로 연결 시켜줘야 한다.

제목: cpplint
명령: c:\python27\python.exe
인수: cpplint.py --output=vs7 --verbose=0 --verbose=1 --verbose=2 --verbose=3 --verbose=4 --extensions=h,cpp $(ItemPath)
초기 디렉토리: $(SolutionDir)
출력 창 사용 : 체크
그리고 솔루션 폴더에 CPPLINT.cfg라는 파일을 만들고 다음 내용을 입력한다

set noparent
exclude_files=resource.h
exclude_files=targetver.h
filter=-legal/copyright.h
filter=-build/c++11
filter=-build/include_what_you_use
filter=-readability/multiline_comment
filter=-build/header_guard
filter=-whitespace/comments

각자 편한데로 설정해서 쓰면된다.