Effective Debugging/Chapter 1. 고차원 전략
created : 2020-04-07T11:44:40+00:00
modified : 2020-09-26T14:26:50+00:00
Item 1. Issue Tracking (모든 문제를 이슈 추적 시스템으로 관리하기)
- Github, GitLab
- JIRA, Bugzilla, Launchpad, OTRS, Redmine, Trac
장점
- 디버깅 작업 과정을 명확하게 파악할 수 있다.
- 릴리즈 일정을 수립하게 추적할 수 있다.
- 작업의 우선순위를 정할 수 있다.
- 자주 발생하는 이슈나 해결책을 문서로 정리할 수 있다.
- 해결해야 할 문제를 실수로 빼먹지 않을 수 있다.
- 릴리즈 노트를 자동으로 생성할 수 있다.
- 결함을 측정하고, 이를 되돌아보며 교훈을 얻을 수 있는 저장소로 활용할 수 있다.
문제를 재현하는 방법을 기록해라
버그리포트 작성법
- 정확한 제목
- 버그의 우선순위와 심각한 정도
- 해당 버그에 관련된 이름
- 버그가 발생한 환경에 대한 상세 정보
장단점
- 제목을 정확하고 간결하게 작성하면 요약 리포트만 봐도 어떤 버그인지 쉽게 알아볼 수 있다. 가장 나쁜 예는
프로그램이 갑자기 뻗었음
과 같이 적는 것이다.저장하는 동안 리프레시 버튼을 누르면 프로그램이 뻗음
과 같이 구체적으로 적는 것이 바람직하다. - 심각한 정도를 명시하면 버그의 우선순위를 정하는 데 도움이 된다. 데이터가 손실되는 버그는 당연히 심각한 문제로 봐야하지만, 미적인 문제나 대안이 알려진 문제는 이보다 심각한 정도가 낮다. 이처럼 버그의 심각한 정도를 명시하면 이슈 목록을 작성할 때 당장 해결해야 하는 이슈, 나중에 처리해도 되는 이슈, 무시해도 되는 이슈 등과 같이 우선순위에 따라 분류할 수 있다.
- 이렇게 정해진 우선순위는 이슈의 우선순위 항목에 기록한다. …
책에 내용이 더 있지만 굳이 전부 적는건 필요 없고 여기까지가 필요한 정보이니 여기까지만
기억할 사항
- 모든 문제를 이슈 추적 시스템으로 처리한다.
- 이슈를 작성할 때 문제를 재현하는 방법으로 정확하고, 간결하고, 관련된 사항을 모두 담아서, 구체적인 예제와 함께 기록한다.
- 이슈의 심각한 정도와 우선순위를 정해서 이에 맞게 작업 일정을 짠다.
- 이슈 추적 시스템을 통해 작업 현황을 문서화 한다.
Item 2. 해결책을 웹에서 검색할 때 검색어를 구체적으로 표현하기
SSCCE(short, self-contained, correct (compilable and runnable) example)
- SourceLair 나 JSFiddle과 같은 온라인 IDE를 통해서 질문하자.
- How To Ask Questions The Smart Way, http://www.ctab.org/~esr/faqs/smart-qustions.html
기억할 사항
- 발생한 에러에 대한 해결책을 웹에서 검색할 때 에러 메시지를 큰따옴표로 묶어서 입력한다.
- 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
명령으로 쓸데 없는 부분은 잘라내자
- 최소한 파일 해쉬(MD5)값 정도는 확인하자.
기억할 사항
- 정상 시스템과 오류가 발생한 시스템을 비교하여 문제의 원인을 찾는다.
- 코드, 입력값, 함수를 호출할 때 전달한 인수, 환경변수, 서비스, 동적 라이브러리 등을 비롯한 시스템 동작에 영향을 미치는 요인을 모두 고려한다.
Item 6. 소프트웨어에서 제공하는 디버깅 기능 활용하기
- 백그라운드 실행 또는 멀티스레드 기능을 꺼서 프로그램을 디버깅하기 쉽게 만들 수 있다.
- 원하는 부분만 선택해서 실행함으로써 문제의 원인을 정확히 겨냥한 테스트 케이스를 작성할 수 있다.
- 성능에 관련된 리포트나 고급 기능을 제공할 수 있다.
- 부가적인 로깅 기능을 제공할 수 있다.
SQL에서 분석
explain
키워드를 사용하자.
기억할 사항
- 문제가 발생한 소프트웨어에서 자체적으로 디버깅 기능을 제공하는지 확인한다. 디버깅 기능을 제공하면 이를 활용하여 문제를 분석한다.
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. 가장 중요한 문제에 집중하기
높은 우선순위
- 데이터 손실
- 보안
- 서비스 가용성 저하
- 안전
- 충돌 또는 멈춤 현상
- 코드 위생
낮은 우선순위
- 레거시 지원
- 하위 호환성
- 미적인 이슈
- 우회 방법 문서화
- 거의 사용하지 않는 기능
기억할 사항
- 모든 문제를 해결할 필요는 없다.
- 우선순위가 낮은 이슈를 해결하는 작업은 우선순위가 높은 작업을 해결하는 데 필요한 시간을 빼앗을 수 있다.