본문 바로가기
Topos Uranos

요약

이 수업은 8단원을 마무리하고, 그와 함께 강좌를 마무리한다. 단원의 세 수업에서 이룬 것을 모으고, 모듈의 인터페이스에서 방법으로서의 디버깅에 이르는 개념의 사슬을 다시 세우고, 그 가운데 어느 언어에서나 통하는 것을 C++에 고유한 것과 구별하고, 아무도 진단하지 않는 단일 정의 규칙 위반을 보여 주고, 강좌의 정의되지 않은 동작 전부를 하나의 목록으로 모아 각 경우를 무엇이 검출하는지 덧붙인다. 마무리 평가에서는 입문 평가의 기량을 다시 묻고, 단원을 엮는 여섯 가지 도전 과제를 내고, 마지막으로 강좌의 최종 프로젝트로 끝맺는다. 프로젝트는 명세가 정확하고, 루브릭을 갖추고, 네 단계로 이루어지며, 단계마다 검증된 참고 답안이 있다.

학습 목표

  1. 프로그램을 헤더, 인클루드 가드, 계약을 갖춘 여러 모듈로 구성하고, 분할 컴파일하고, 링커의 메시지를 진단한다.
  2. 모듈을 명세로부터 테스트한다. 새니타이저 아래에서 실행하는 자동 테스트 프로그램을 쓰고, 일어날 수 없는 일을 단언으로 확인한다.
  3. 방법(재현하기, 축소하기, 가설 세우기, 이분 탐색으로 좁히기)과 디버거로 결함의 위치를 찾고, 조사 과정을 기록한다.
  4. 강좌에서 보여 준 정의되지 않은 동작과 각 경우를 무엇이 검출하는지, 그리고 아무도 진단하지 않는 단일 정의 규칙 위반을 알아본다.
  5. 강좌 전체를 하나의 프로젝트로 통합한다. 표 형식의 데이터를 관리하는 프로그램을 명세하고, 분해하고, 구축하고, 테스트하고, 비용을 재고, 디버깅한다.

단원에서 이룬 것

이 단원은 이제 한 파일에도, 머릿속에도 들어가지 않는 프로그램을 구성하고, 검증하고, 디버깅하는 법을 가르치려 했다. 그 목적은 도입에서 이미 아는 것으로 밝힌 내용, 곧 선언과 정의, 컴파일과 링크, 계약, 불변식, 이진 탐색에 기대어 이루어졌다. 단원을 연 도서 목록 프로그램은 한 파일에 들어가는 크기였지만, parseInt 함수를 또 한 번 복사했고, 명세가 “양 끝 포함”이라고 한 곳에 < 기호를 써서 『백년 동안의 고독』을 소리 없이 빠뜨렸다. 이 프로그램은 이 수업의 마지막 절에서 최종 프로젝트로 다시 쓰인다. 계약을 갖춘 네 모듈, 명령에 응답하는 주 프로그램, 그리고 스물다섯 개의 케이스로 된 테스트 프로그램이다. 그 가운데 두 케이스, “범위, 경계”와 “범위, 한 해”는 원래 프로그램의 조건으로는 실패하므로, 그 오류가 아무도 모르게 되돌아오는 일은 없다.

여러 파일과 자체 라이브러리

여러 파일과 자체 라이브러리 수업은 프로그램을 선언하는 헤더, 정의하는 구현 파일, 그것을 쓰는 main.cpp 파일로 나누었다. 한 번역 단위 안에서 이중 포함을 막는 인클루드 가드, “multiple definition”과 “undefined reference”를 설명하고 inline 키워드에 허가라는 오늘날의 의미를 주는 단일 정의 규칙, 소스나 헤더가 바뀐 오브젝트만 재컴파일하는 -c 옵션에 의한 분할 컴파일, 그리고 앞선 수업들의 함수로 만든 자체 라이브러리를 소개했다.

프로그램 테스트

프로그램 테스트 수업은 아래의 것들을 가르쳤다. 명세로부터 영역, 경계, 특수한 경우별로 케이스를 이끌어 내고, 기대 결과를 다른 길로 계산하는 것. 실패만 보고하고 종료 코드 0이나 1로 끝나는 자동 테스트 프로그램을 쓰는 것. 일어날 수 없는 일에 assert 매크로를 쓰되, -DNDEBUG 옵션이 그것을 조건째 지운다는 것을 아는 것. static_assert 선언과 constexpr 키워드로 컴파일할 때 테스트하는 것. 그리고 새니타이저(메모리 오류 새니타이저인 AddressSanitizer와 정의되지 않은 동작 새니타이저인 UndefinedBehaviorSanitizer) 아래에서 테스트를 실행하는 것. 그 모두가 다익스트라의 경고에 기대고 있다. 테스트는 오류의 존재를 보여 줄 뿐, 그 부재는 결코 보여 주지 못한다.

프로그램 디버깅

프로그램 디버깅 수업은 디버깅을 실험적 방법으로 소개했다. 장애를 재현하고, 반증 가능한 가설을 세우고, 실험으로 가설 사이에서 판정하고, 의심스러운 구간을 이분 탐색으로 좁힌다. 도구(최적화 없는 -g 옵션, 세 운영체제에서의 Visual Studio Code 설정, 실제 GDB 세션, 단순 중단점과 조건부 중단점, 단계별 실행과 호출 스택)와, 도구보다 값진 전략을 전개했다. 사례를 축소하기, 단언으로 마지막으로 올바른 지점을 찾기, 새니타이저 보고서에서 첫 번째 자기 프레임부터 시작하기이다.