•
디버깅은 오류의 근본적인 원인을 규명하고 수정하는 과정으로 오류를 감지하는 테스트와는 반대되는 개념이다.
1. 디버깅 이슈 소개
소프트웨어 품질에서의 디버깅의 역할
•
테스트처럼 디버깅은 본질적으로 소프트웨어의 품질을 향상시키는 방법이 아니라 결함을 진단하는 기법이다.
•
소프트웨어 품질은 처음부터 정립해야 한다. 고급 제품을 만드는 가장 좋은 방법은 요구사항을 주의 깊게 정의하고 잘 설계하여 좋은 코드를 작성하는 것이다.
기회로서의 결함
•
개발 중인 프로그램에 관해 배울 수 있다.
◦
프로그램에 결함이 있다면 거기에서 뭔가를 배울 수 있다. 프로그램을 보다 정확하게 이해하고 코드를 잘 작성할 수 있다.
•
자신이 저지른 실수에 관해 배울 수 있다.
◦
프로그램의 버그를 발견했다면 보통은 자신이 넣어놓은 실수다. 어떻게 실수를 덜 할수 있을지 고민해볼 수 있다.
•
자신의 코드를 읽어야 하는 사람의 관점으로부터 코드의 품질에 대해서 배울 수 있다.
◦
결함을 찾으려면 코드를 읽어야 한다. 자신이 작성한 코드의 품질을 비판적으로 바라볼 수 있는 기회다.
•
문제를 해결하는 방법을 배울 수 있다.
•
디버깅은 가독성, 설계, 코드 품질 등 모든 구현 관련 사항이 집중되어 다뤄지는 곳이기도 하다. 좋은 개발자가 되기 위한 기회로 여기자.
비효과적인 접근 방법
•
추측으로 결함을 찾아라.
◦
여기 저기에 출력 명령문을 뿌리고 결함을 찾는다.
•
문제를 이해하는 데 시간을 쓰지 않는다.
•
가장 명백한 수정으로 오류를 수정하라.
◦
특정 케이스에서 문제가 발생한다고 해당 케이스만 예외로 처리하는 코드를 집어넣는 것은 안 된다.
•
프로그램에 문제가 있다면 그것은 작성자의 잘못이다.
◦
컴퓨터나 컴파일러는 죄가 없다. 프로그램은 매번 다르게 행동하지 않으며 스스로 코딩을 하지도 않는다. 작성한 사람이 책임져야 한다.
2. 결함 발견
과학적인 디버깅 방법
•
다음은 결함을 찾는 효과적인 접근 방법이다.
1.
오류를 재현한다.
•
결함이 신뢰할 수 있을 정도로 발생하지 않는다면 찾아내는 것은 거의 불가능하다. 간헐적인 결함을 예측가능할 수 있을 정도로 발생시키는 것은 가장 어려운 작업이다.
◦
보통 예측 불가능할 정도로 드문드문 발생하는 오류는 초기화 오류나 시간 관련 오류, 허상 포인터 문제다.
2.
오류의 원인을 찾아낸다.
•
매개변수를 경계의 아래쪽, 위쪽, 내로 변경해보고 가설이 옳은지 결정할 수 있다.
•
외에도 추가적인 테스트 케이스를 사용해서 이 가설을 검증한다.
a.
결함을 만들어내는 데이터를 수집한다.
b.
수집된 데이터를 분석하고 결함에 대한 가설을 세운다.
c.
프로그램을 테스트하거나 코드를 살펴봄으로써 가설을 증명하거나 반증할 방법을 결정한다.
d.
c에서 규명한 절차를 사용하여 가설을 증명하거나 반증한다.
3.
결함을 수정한다.
4.
수정 내용을 테스트한다.
5.
유사한 오류를 찾는다.
결함을 찾는 데 도움이 되는 팁
•
가설을 세우고 검증하기 위해 가용한 데이터를 모두 사용하라.
•
오류를 만드는 테스트 케이스를 찾는데 멈추지 않고 개선하라.
•
단위 테스트에서 코드를 다루어라.
•
도구를 사용하라.
•
여러 가지 방법으로 오류를 발생시켜라.
•
더 많은 가설을 세우고 검증하기 위해 더 많은 데이터를 만들어라.
•
부정적 테스트의 결과를 사용하라.
•
가능한 가설에 대해서 브레인 스토밍하라.
•
연습장을 준비하여 시도할 목록을 정리하라.
•
의심스러운 코드 영역을 좁혀나가라.
•
이전에도 결함이 있었던 클래스와 메소드를 의심해보라.
•
최근에 변경한 코드를 검사하라.
•
의심스러운 코드 영역을 확장하라.
•
점진적으로 통합하라.
•
일반적인 결함을 검사하라.
•
프로그램에 대해 다른 사람과 이야기를 나누어라.
•
잠깐 쉬었다가 다시 보라.
3. 결함 수정
•
수정하기 전 문제와 프로그램을 충분히 이해하라.
◦
문제와 프로그램을 충분히 이해하지 못한 해결법은 결함을 다시금 야기한다.
•
결함 분석을 확인하라.
•
긴장을 풀어라.
•
코드를 백업해두라.
•
증상이 아니라 문제를 해결하라.
•
타당한 이유가 있을때만 코드를 변경하라.
•
한 번에 한 가지만 변경하라.
•
수정한 내용을 검사하라.
•
결함을 노출하는 단위 테스트를 추가하라.
•
유사한 결함을 찾아라.
◦
결함 하나를 찾았을 때, 유사한 결함이 있는지 찾아보라는 의미다.
5. 디버깅 도구 - 분명한 도구와 그렇지 않은 도구
소스코드 비교 도구
•
Github의 diff와 같은 소스코드 비교 도구는 오류에 대해서 프로그램을 수정하고 있을 때 유용한다.
•
기억나지 않는 변경 사항을 정확하게 지적하여 알려주며 이전 버전에서 본적없는 새로운 결함 사항이 등장했다면 이를 통해 효과적으로 확인할 수 있다.
컴파일러 경고 메시지
•
컴파일러의 경고 수준을 가장 까다로운 수준으로 설정하고 컴파일러가 나타내는 오류를 수정하라.
◦
컴파일러를 작성한 사람들이 당신보다 언어에 대해서 훨씬 잘 알고 있다고 가정하라. 컴파일러가 뭔가를 경고한다면 보통 뭔가를 더 배울 수 있는 기회다.
•
경고를 오류로 취급하라.
•
컴파일 시간 설정에 대한 프로젝트 전반적인 표준을 제안하라.
◦
팀에 있는 모든 사람이 같은 컴파일러 설정을 사용하여 코드를 컴파일할 수 있도록 표준을 정하라.
확장된 문법과 논리 검사
•
eslint같은 도구 사용하라
실행 프로파일러
•
실행 프로파일러의 출력 결과를 조사해 궁금증을 풀어라.
◦
프로그램의 여러 부분이 얼마나 자주 그리고 얼마나 오랫동안 실행되었는지를 기술하는 통계 집합이다.
테스트 프레임워크/비계
•
문제가 있는 코드 부분을 테스트하는 코드를 작성한 다음 테스트 코드를 실행하는 것이 문제를 해결하는 가장 효과적인 방법일 수 있다.
디버거
•
디버거는 적절히 고민하고 수행하는 두뇌 활동을 대신할 수 없다. 하지만 어떤 때는 두뇌 활동이 디버거를 대체할 수 없다.
•
머리로 생각하고 디버거를 적절히 도구로 사용하는 것이 가장 효과적이다.
요점 정리
•
디버깅은 소프트웨어 개발의 성패를 좌우한다. 가장 좋은 접근 방법은 이 책에서 소개하는 다른 기법을 사용해 결함을 처음부터 피하는 것이다.
◦
디버깅 기술을 향상하는데 시간을 투자할 가치는 충분히 있다. 디버깅을 잘하는 사람과 못하는 사람 사이의 수행 능력이 크기 때문이다.
•
오류를 찾고 수정하는 데 체계적으로 접근하는 것은 좋은 코드의 품질을 작성하는데 매우 중요하다. 각 테스트가 한 걸음 더 나아갈 수 있도록 디버깅에 초점을 맞추고 과학적인 디버깅 방법을 사용하라.
•
문제를 수정하기 전에 문제와 프로그램을 이해하라. 오류의 원인을 임의로 추측하고 수정하면 프로그램은 악화될 것이다.
•
컴파일러의 경고를 가장 까다로운 수준으로 설정하고 컴파일러가 보고하는 오류를 수정하라.
•
디버깅 도구는 소프트웨어 개발에 도움이 되는 아주 강력한 도구다. 그러한 도구를 찾아서 사용하는 동시에 너무 의존하지 않도록한다. 도구는 도구다.