2 minute read

5. 구현 설계

5. 구현 설계

5.1 설계의 어려움

5.2 핵심 설계 개념

5.3 설계 빌딩 블록: 발견적 학습

5.4 설계 실천법

5.5 잘 알려진 방법론에 대한 의견

6. 클래스 다루기

6.1 클래스의 토대: 추상 데이터형(ADT)

6.2 좋은 클래스 인터페이스

6.3 설계와 구현 문제

6.4 클래스를 작성하는 이유

6.5 프로그래밍 언어와 관련된 이슈

6.6 클래스를 넘어서: 패키지

7. 고급 루틴

7.1 루틴을 작성하는 이유

7.2 루틴 수준의 설계

7.3 좋은 루틴 이름

7.4 루틴의 길이에 대한 문제

7.5 루틴 매개변수 처리

7.6 함수를 사용할 때 특별히 고려해야 할 사항

7.7 매크로 루틴과 인라인 루틴

8. 방어적인 프로그래밍

8.1 잘못된 입력으로부터 프로그램 보호

  • 기본적으로 모든 인풋을 검사할 것.
  • 쓰레기를 넣으면 쓰레기가 나온다 (X)
  • 쓰레기를 넣으면 아무것도 안 나온다 / 에러를 낸다, 쓰레기 자체가 허용되지 않는다 (O)

8.2 어설션

  • 오류 처리는 예상이 되었고 코드에 의해 처리되어야 하는 것, 어설션은 절대 발생하면 안 되는 조건을 위해 사용한다.
  • 프로그램이 클수록 유용하다
  • 선행/후행 조건을 문서화하는 용도로 사용하기 좋다.
  • 개발/유지보수를 목적으로 한다. 릴리즈용이 아니다!

8.3 오류 처리 기법

  • 오류의 성격에 따라 적절한 처리방식이 다 다를 것. 선택적으로 사용하면 된다.
    • 중립값, 다음 값/이전과 동일한 값/가장 가까운 값, 오류 코드 등을 리턴하기
    • 에러 파일에 기록하기, 아예 종료하기 등
  • 오류 처리를 하이레벨에서 할지, 로우레벨에서 할지 결정하고, 일관성 있게 따르라.

8.4 예외

  • 무시되어서는 안 되는 오류를 위해 사용한다. 절대로 일어나서는 안 되는 경우.
  • 생성자와 소멸자에서는 쓰지 말 것.
  • 신중하게 사용하면 복잡성을 줄일 수 있고, 무분별하게 쓰면 이해하기가 거의 불가능해진다. 그러니 다른 방법이 정말 없는지 한번 더 생각해 보자.

8.5 오류로 인한 손상을 막기 위한 방책

  • validation!

8.6 디버깅 보조 도구

  • 공격적인 프로그래밍 : 릴리즈에서는 젠틀하게, 개발에서는 파괴적으로.
  • 전처리기, make 등을 잘 활용하기.

8.7 제품 코드를 얼마나 방어적으로 프로그래밍할 것인지 정하기

  • 눈에 띄는 디버깅 멧지ㅣ/충돌코드 코드 지우기.
  • 그럼에도 치명적인 오류를 감지해야 한다면 “젠틀하게” 종료될 수 있게 만들어 남겨두기.

8.8 방어적인 프로그래밍에 대해서 한 번 더 고민하기

  • 방어를 위한 코드가 너무 많으면 트레이드오프가 있다 당연히.

9. 의사코드 프로그래밍 프로세스

9.1 클래스 및 루틴 개발 단계 요약

  • 클래스 작성 : 뭘 숨길거냐 ? 뭘 추상화할거냐 ? 핵심 인터페이스는 뭐냐 ? 중요한 멤버 변수는 ?
  • 함수 작성 : 생각했던 함수 구현 - 만들다가 필요해지는 함수도 구현 - 때로 문제 발생 및 해결 - 구현..
  • 점검과 테스트

9.2 전문가를 위한 의사코드

  • 프로그래밍 문법적인 요소는 아예 배재하고, 한글/영어로만 쭉 써본다. ‘이정도면 코드로 바로 변환해도 되겠다’ 싶을 정도로 낮은 수준에서 쓴다.
  • 코드를 보지 않아도 설계 검토가 쉬워지고, 변경이 쉬워진다. 그리고 의사코드가 바로 주석이 된다.

9.3 PPP를 이용한 루틴 구현

  • 의사코드 작성 > 코드로 변환 > 머릿속에서 검사 > 컴파일 > 반복

9.4 PPP 대안

  • TDD, 리팩토링 계약에 의한 설계 등

인상깊은 구절

  • 루틴이 맞다는 확신이 되기 전까지는 컴파일을 늦추라. ‘한번만 더 컴파일하면 제대로 작동하게 할 수 있을거야’라는 생각은 조급하게 코드를 만들게 되고 실수하기 쉬워져 결국 시간이 더 걸린다.
  • 여러분이 생각한 첫 번째 설계로 결정하지 않는다. 의사코드에서 여러 접근법을 이용해 반복하고 작성한다.