Effective Debugging/Chapter 2. 범용적인 디버깅 기법

created : 2020-04-07T11:44:40+00:00
modified : 2020-09-26T14:27:16+00:00

Item 9. 성공적인 디버깅을 위한 마음가짐

  • 소프트웨어에서 발생한 문제는 항상 찾아서 고칠수 있다고 믿는다.
  • 시간을 충분히 판단한다.
  • 고도로 집중한다.
  • 어려운 문제를 만나면 잠을 자는것도 좋다.

기억할 사항

  • 모든 문제는 찾아서 고칠 수 있다고 믿는다.
  • 디버깅 작업에 필요한 시간을 충분히 확보한다.
  • 작업에 최대한 집중할 수 있도록 환경을 마련한다.
  • 힘든 문제를 해결할 때는 효과적인 수면을 취한다.
  • 포기하지 않는다.
  • 디버깅 환경, 도구, 기법을 익히는 데 꾸준히 노력한다.

Item 10. 효율적으로 문제 상황 재현하기

효율적으로 문제 상황을 재현하는 것이 가지는 장점

  • 오류를 만들어 내기 위해 시간을 낭비할 필요 없이 곧바로 원인을 해결하는데 집중할 수 있다.
  • 다른 사람들에게 도움을 청하기 좋다.
  • 오류를 해결한 뒤에 검증하기 쉽다.

문제를 단순화 해라

  • SSCCE라고 부르는 기준에 따라 간결하게 작성한다.
  • 코드의 의존 관계가 많다면 상향식으로 접근하여 처음부터 새로 시작하는 것이 바람직하다.
  • 문제를 파악하기 힘들 때에는 하향식으로 접근하여 경우의 수를 줄여나가는 것이 좋다.

중요 키워드

  • 독립적인 형태
  • 반복적으로 실행할 수 있는 환경
  • 오류가 발생하는 버전에 대한 복사본을 언제든지 만들 수 있는 기능

기억할 사항

  • 문제 상황을 재현할 수 있다면 디버깅 작업이 쉬워진다.
  • 문제를 재현할 수 있는 예제를 최대한 간결하고 독립적으로 실행할 수 있는 형태로 만든다.
  • 반복적으로 실행할 수 있는 환경을 구축한다.
  • 버전 관리 시스템을 활용하여 소프트웨어에 버전을 지정해서 원하는 버전을 언제든지 불러 올 수 있도록 구성한다.

Item 11. 코드 수정 후 결과 확인까지의 시간 최소화하기

기억할 사항

  • 수정한 코드의 결과를 확인하는 데 걸리는 시간을 최소화하여 효율을 높인다.
  • 빠르게 빌드하고 배치하는 프로세스를 마련한다.
  • 오류가 발생하면 최대한 빠르게 멈추게 한다.

Item 12. 복잡한 테스트 시나리오 자동화하기

  • 루아를 배워보자ㅠ

기억할 사항

  • 복잡한 테스트 케이스를 실행하는 작업은 스크립트 언어를 이용하여 자동화한다.

Item 13. 디버깅 관련 데이터를 한눈에 볼 수 있는 환경 구축하기

  • 최대한 넓은 화면 확보
  • 프린터로 출력해서 보자

기억할 사항

  • 많은 데이터를 한눈에 볼 수 있다면 작업에 좀 더 집중할 수 있고 데이터의 패턴이나 상관관계를 파악하기도 쉽다.
  • 화면 공간을 최대한 넓게 확보한다.
  • 변경할 일이 거의 없는 데이터는 프린터로 출력해서 본다.

Item 14. 소프트웨어 업데이트 고려하기

  • 디버깅에 들어가기 앞서 환경을 최신 버전으로 업데이트한다.
  • 업데이트에 너무 큰 기대는 하지 않는다.
  • 서드파티 모듈에서 버그가 발생할 수 있다는 점도 염두에 둔다.

Item 15. 서드파티 소스 코드 분석을 통해 문제 해결하기

  • 작성하는 소프트웨어에서 사용하는 서드파티 모듈에 대한 소스 코드를 확보한다.
  • 서드파티 API에 문제가 발생하거나 알 수 없는 에러 메시지가 출력되면 서드파티 소스 코드를 분석한다.
  • 서드파티 라이브러리를 디버깅 버전으로 빌드해서 사용한다.
  • 다른 대안이 없을 경우에만 서드파티 코드를 직접 수정한다.

Item 16. 전문 모니터링 및 테스팅 장비 활용하기

  • 로직, 버스, 프로토콜 분석기를 활용하면 하드웨어 수준에서 발생하는 문제를 정확히 분석할 수 있다.
  • 하드웨어에 관련된 문제를 분석할 때는 적절한 장치를 직접 제작하는 것도 도움된다.
  • 네트워크 패킷을 모니터링할 때는 와이어샤크나 이더넷 허브, 매니지드 스위치, 또는 명령줄 기반의 패킷 수집프로그램을 활용한다.

Item 17. 오류의 효과 극대화하기

  • 항상 참, 혹은 거짓이 되도록 소스코드를 수정한다.

      if (fileds.time > apr_time_now() || 1) {
      	...
      }
    
      if (0) {
      	...
      }
    
  • 환경을 수정해본다.
    • 웹 요청을 처리하는 프로그램이라면, Apache JMeter와 같은 부하 테스트(load test)나 스트레스 테스트(stress test) 도구를 이용해본다.
    • 싸구려 장비를 이용해서 제약을 줘본다.
  • 데이터 유효성 또는 데이터 손상 문제를 분석할 떄는 퍼징(fuzzing)이라는 테스트 기법을 사용해본다.
    • zzuf 와 같은 도구를 활용하자

기억할 사항

  • 의심스런 실행 경로를 인위적으로 따라가게 한다.
  • 분석하려는 문제 현상이 눈에 잘 띄도록 그 효과를 극대화한다.
  • 소프트웨어의 실행 영역이 정상 범위를 벗어나도록 스트레스를 준다.
  • 모든 작업을 버전관리 시스템의 별도의 가지(Branch)에서 수행한다.

Item 18. 원격 디버깅 환경 구축하기

  • 하드웨어에 밀접한 문제에 대한 디버깅 작업을 자신이 사용하는 컴퓨터의 화면과 키보드로 작업할 수 있도록 장치 에뮬레이터를 설치한다
  • 임베디드 소프트웨어를 디버깅할 때는 자신이 사용하는 개발 머신에서 제공하는 도구를 활용할 수 있게 해주는 쐬기 모듈을 활용한다.
  • 고객의 PC에 발생한 문제를 해결할 때는 원격에서 접속할 수 있는 환경을 구축한다.
  • 서버에 대한 디버깅 작업을 원격에서 수행할 수 있도록 IP 기반 KVM 스위치를 설치한다.

Item 19. 디버깅 작업 자동화 하기

  • 오류의 원인에 대한 모든 경우의 수를 탐색하는 작업을 자동화한다. 컴퓨터에게 시간은 별 것 아니지만 여러분의 시간은 소중하기 떄문이다.

Item 20.디버깅 전과 후에 정리하기

  • 디버깅 작업을 수행할 때 쉬운 영역부터 공략하는 것이 좋다.
    • 도구를 사용하여 쉽게 찾을 수 있는문제
    • 수정 가능한 Assertion 실패처럼 프로그램 실행 과정에서 발생하는 경고 메시지
    • 읽기 힘들게 작성된 코드에서 문제가 발생한 경우
    • 주석에 XXX, FIXME, TODO와 같은 문구가 표기되어 있거나 should, think, must와 같이 뭔가 책임을 회피하는 듯한 문장이 담긴 미심쩍은 코드
    • 그 밖에 무시했던 사소한 버그

기억할 사항

  • 본격적인 디버깅에 들어가기 전에 작업 환경에서 오류가 발생하지 않도록 정리한다.
  • 작업이 끝나면 임시로 수정한 코드를 제거하고 나중에 필요한 부분은 커밋한다.

Item 21. 비슷한 문제 모두 고치기

  • 오류 하나를 수정한 뒤에는 이와 비슷한 유형의 오류도 찾아서 해결하고, 향후에도 발생하지 않도록 적절히 조치한다.