Item 1. Issue Tracking (모든 문제를 이슈 추적 시스템으로 관리하기) Github, GitLab JIRA, Bugzilla, Launchpad, OTRS, Redmine, Trac 장점 디버깅 작업 과정을 명확하게 파악할 수 있다. 릴리즈 일정을 수립하게 추적할 수 있다. 작업의 우선순위를 정할 수 있다. 자주 발생하는 이슈나 해결책을 문서로 정리할 수 있다. 해결해야 할 문제를 실수로 빼먹지 않을 수 있다. 릴리즈 노트를 자동으로 생성할 수 있다. 결함을 측정하고, 이를 되돌아보며 교훈을 얻을 수 있는 저장소로 활용할 수 있다. 문제를 재현하는 방법을 기록해라 버그리포트 작성법 정확한 제목 버그의 우선순위와 심각한 정도 해당 버그에 관련된 이름 버그가 발생한 환경에 대한 상세 정보 장단점 제목을 정확하고 간결하게 작성하면 요약 리포트만 봐도 어떤 버그인지 쉽게 알아볼 수 있다. 가장 나쁜 예는 프로그램이 갑자기 뻗었음
과 같이 적는 것이다. 저장하는 동안 리프레시 버튼을 누르면 프로그램이 뻗음
과 같이 구체적으로 적는 것이 바람직하다. 심각한 정도를 명시하면 버그의 우선순위를 정하는 데 도움이 된다. 데이터가 손실되는 버그는 당연히 심각한 문제로 봐야하지만, 미적인 문제나 대안이 알려진 문제는 이보다 심각한 정도가 낮다. 이처럼 버그의 심각한 정도를 명시하면 이슈 목록을 작성할 때 당장 해결해야 하는 이슈, 나중에 처리해도 되는 이슈, 무시해도 되는 이슈 등과 같이 우선순위에 따라 분류할 수 있다. 이렇게 정해진 우선순위는 이슈의 우선순위 항목에 기록한다. … 책에 내용이 더 있지만 굳이 전부 적는건 필요 없고 여기까지가 필요한 정보이니 여기까지만 기억할 사항 모든 문제를 이슈 추적 시스템으로 처리한다. 이슈를 작성할 때 문제를 재현하는 방법으로 정확하고, 간결하고, 관련된 사항을 모두 담아서, 구체적인 예제와 함께 기록한다. 이슈의 심각한 정도와 우선순위를 정해서 이에 맞게 작업 일정을 짠다. 이슈 추적 시스템을 통해 작업 현황을 문서화 한다. Item 2. 해결책을 웹에서 검색할 때 검색어를 구체적으로 표현하기 SSCCE(short, self-contained, correct (compilable and runnable) example) 기억할 사항 발생한 에러에 대한 해결책을 웹에서 검색할 때 에러 메시지를 큰따옴표로 묶어서 입력한다. StackExchange, StackOverflow에 올라온 답변을 참고한다. 직접 질문을 올리거나 버그 리포팅 시스템에 이슈를 등록한다. Item 3. 선행 조건과 후행 조건 만족 여부 확인하기 선행조건 (precondition), 후행조건(postcondition) 주의해아할 상황 값이 null이 아니여야하는 부분이 null인지 살펴본다. 수학 함수에 전달한 값이 그 함수에서 다루는 범위 안에 있는지 확인한다.(ex. log 함수에 전달한 값이 0보다 큰지 확인한다.) 루틴에 전달한 객체나 구조체, 배열의 내부를 살펴보고 그 안에 필요한 내용이 담겨 있는지 확인한다. 변순의 값이 정상 범위 안인지 확인한다. 간혹 변수를 초기화 하지 않으면 이상한 값이 들어 있는 경우가 있다. 무작위 추출 검사(epot-check)를 통해 데이터 구조의 무결성을 검사한다. 계산된 결과가 적합한지, 예상 범위 안에 있는지 확인한다. 값이 정상 범위에 있다면 실제로 결과가 정확한지 확인한다. 직접 손으로 계산해보거나, 이미 알려진 정상 값과 비교해보거나, 다른 도구로 계산해보면 된다. Side Effect가 예상된 결과인지, 의심 스러운 코드로 인해 데이터가 손상됬는지 엉뚱한 값으로 설정되어 있지 않은지 확인한다. 알고리즘에서 사용하는 자원(File Handle, Lock 등)이 정상 반환 되었는지 확인한다. Item 4. 문제 발생 지점부터 버그를 추적하거나 프로그램 시작 지점부터 버그를 찾아나가기 1. 프로그램이 갑자기 죽는 문제 디버거로 실행해보거나 메모리 덤프를 보자 Magic Number를 확인하자 변수 초기화 여부 확인(0xBAADF00D) 2. 프로그램이 멈춘 뒤 아무 반응이 없다면… 원인을 추적하는 상향식 방식을 조금 다르게 진행한다. - 루프 바깥쪽부터 껍질식으로 탐색해나간다. 3. 에러 메시지가 명확할때 fgrep -r
을 사용해서 복잡한 계층 구조 속에서 원하는 단어를 찾아내자.어느 코드에서 문제가 발생하는지 알 수 없을 때, 프로그램의 처음부터 추적하는 하향식 방식을 사용하는 것이 좋다. 이런 에러를 창발적 속성(에러) Emergent property라고 부른다. 기억해야할 사앙 프로그램이 갑자기 종료하거나, 아무런 응답 없이 멈추거나, 에러 메시지를 출력될 떄와 같이 문제가 명확히 드러날 떄는 상향식 방식으로 원인을 찾는다. 성능과 보안, 신뢰성 등과 같이 문제가 명확하게 드러나지 않을 때는 하향식 방식으로 원인을 찾는다. Item 5. 정상 시스템과 비정상 시스템의 차이점 분석하기 로그파일을 찬찬히 읽자. 로그가 원하는 만큼 자세하지 않을 경우 Tracing Tool로 Runtime 을 분석해야한다.DTrace, SystemTap을 사용(범용 도구) strace, truss, Procmon(운영체제 호출과정 추척) Itrace, Procmon (동적으로 링크된 라이브러리 호출과정) tcpdump, Wireshark (네트워크 패킷 추적) SQL 은 db 분석 도구를 사용한다.(흐음… 책에서 안알려준다. 찾아봐야겠다.) R Project, 유닉스 어플리케이션은 보통 오류 찾기 힘들다. -x
옵션으로 추적할수도 있지만… 눈물 환경을 잘 구성하자최소한 파일 해쉬(MD5)값 정도는 확인하자. 흐음… binary file md5 값 보는 명령어 찾아봐야할듯 ldd
를 이용하거나 dumpbin
을 실행할 때 /dependents
옵션을 켜서 코드를 실행하는동안 동적 라이브러리도 함께 확인해보자.코드에서 사용하고 있는 기호(Symbol을 이렇게 번역한듯?)는 nm, Visual Studio는 dumpbin에서 /exports /imports 옵션을 켜서 확인하자 자바라면 javap로 확인하자. 환경변수는 간과하기 쉬운 요인이다. git bisect
명령을 통해 버그가 나는 버전을 찾아내자.cut
이나 awk
명령으로 쓸데 없는 부분은 잘라내자 기억할 사항 정상 시스템과 오류가 발생한 시스템을 비교하여 문제의 원인을 찾는다. 코드, 입력값, 함수를 호출할 때 전달한 인수, 환경변수, 서비스, 동적 라이브러리 등을 비롯한 시스템 동작에 영향을 미치는 요인을 모두 고려한다. Item 6. 소프트웨어에서 제공하는 디버깅 기능 활용하기 백그라운드 실행 또는 멀티스레드 기능을 꺼서 프로그램을 디버깅하기 쉽게 만들 수 있다. 원하는 부분만 선택해서 실행함으로써 문제의 원인을 정확히 겨냥한 테스트 케이스를 작성할 수 있다. 성능에 관련된 리포트나 고급 기능을 제공할 수 있다. 부가적인 로깅 기능을 제공할 수 있다. SQL에서 분석 기억할 사항 문제가 발생한 소프트웨어에서 자체적으로 디버깅 기능을 제공하는지 확인한다. 디버깅 기능을 제공하면 이를 활용하여 문제를 분석한다. Item 7. 빌드 및 실행 환경을 다양하게 구성하기 환경 구성 방법 가상 머신 소프트웨어 사용 저렴한 소형 컴퓨터 (ex. raspberry pi) Cloud기반 호스트 컴파일러도 다양하게 구성하자 .NET Framework에서 개발할때 Mono도 함께 봐보자 Ada, C, C++, Objective C로 개발할때 LLVM과 GCC 를 함께 사용한다. 자바에선 OpenJDK와 Oracle JDK, GNU Classpath를 함께 사용한다. 자바 런타임도 다양하게 하자 루비 프로그램을 작성할 때 레퍼런스 구현인 CRuby와 별도로 JRuby, Rubinius, mruby와 같은 다른 VM 도 활용하자. 기억할 사항 컴파일 환경과 실행 플랫폼을 다양하게 구성하면 다양한 시각으로 디버깅 작업을 수행할 수 있다. 난해한 알고리즘에 관련한 문제는 고수준 언어로 구현하여 해결한다. Item 8. 가장 중요한 문제에 집중하기 높은 우선순위 데이터 손실 보안 서비스 가용성 저하 안전 충돌 또는 멈춤 현상 코드 위생 낮은 우선순위 레거시 지원 하위 호환성 미적인 이슈 우회 방법 문서화 거의 사용하지 않는 기능 기억할 사항 모든 문제를 해결할 필요는 없다. 우선순위가 낮은 이슈를 해결하는 작업은 우선순위가 높은 작업을 해결하는 데 필요한 시간을 빼앗을 수 있다.