2.1어떤 버그든 고치는 방법
Dan Abramov의 디버깅 원칙
TL;DR
Korean FE Article에서 번역한 글을 통해 알게된 글로, React 팀 및 Redux 팀에서 활동한 Dan Abramov의 블로그에 비교적 최근 작성된 글이다.
1. 재현(repro)의 중요성
재현은 일정한 절차를 따를 때 그 버그가 여전히 발생하는지 신뢰할 수 있게 알려주는 지침의 모음으로, 이를 '테스트'라고도 부른다.
- 재현을 통해 우리는 아래와 같은 것들을 알 수 있다:
- 무엇을 해야하는지
- 무엇이 기대되는지
- 무엇이 실제로 일어나는지
Dan Abramov는 클로드를 사용한 바이브 코딩 중이었는데(개인적으론 이 말을 당당히 공개하면서 글을 시작할 수 있다는게 이 사람의 위상과 자신감을 보여준다고 생각한다), “스크롤이 흔들린다”라는 현상을 클로드에게 설명하였으나, 클로드는 제대로 이해하지 못하고 고쳤다고 피드백했다.
클로드는 "스크롤이 흔들리는" 현상을 볼 수 없으니 따를 수 없는 것이다. AI를 통한 코딩에서만 이런 문제가 있는 것은 아니다. 사실, 사람간의 협업에서도 버그가 특정 사용자, 특정 설정, 특정 환경에서만 발생할 수도 있다. 따라서 재현 가능하게 문제를 정의하고 설명할 줄 아는 능력은 아주 중요하다.
2. 재현을 좁히기
재현 사례를 바꾸는 것은 원래 버그와 관련이 없어질 위험이 있어 조심해야하지만, 어떤 때는 재현 사례를 바꾸는 것이 불가피하다.
- 예를 들어, 클로드의 경우 화면을 볼 수 없으니 다른 방법을 찾아야 한다.
- Dan Abramov의 경우 문서의 스크롤 위치를 측정하고, 버튼을 클릭한 후 다시 스크롤 위치를 측정한 후 위치에 변화가 있는지 여부에 대해 클로드에게 알려주었다.
- 10분 걸리는 재현보다 10초 걸리는 재현이 훨씬 가치가 크다.
- 명확히 가설을 세우고 빠르게 루프로 검증한다면 디버깅이 훨씬 빨라질 수 있다.
따라서, 재현을 바꾸는 기술 또한 매우 중요하다.
재현 사례를 좁힐 때에는, 새로운 재현 사례로도 정상 동작을 여전히 재현할 수 있는지도 반드시 확인해야한다.
- 예를 들어, 간소화한 재현에서도 원래 문제가 되던 코드를 주석처리한다거나 하면 정상 동작해야 한다.
3. 다른 모든 것을 제거하기
재현 과정을 줄이기 위해, 다음과 같은 순서를 따른다.
- 재현을 실행해 버그가 있는지 확인
- 코드에서 무언가 제거하기(컴포넌트, 이벤트 핸들러, 조건문, 스타일, import 등)
- 재현을 다시 실행해 버그가 발생하는지 확인
- 버그가 여전히 발생하면 변경 사항 커밋
- 버그가 발생하지 않으면 무엇이 해결되었는지에 대한 가설을 생각 후, 마지막 커밋으로 롤백해 더 작은 부분 삭제
4. 근본 원인 찾기
“코드를 하나씩 제거하면서도 버그가 여전히 남아 있는지 확인하는” 접근법으로 Dan Abramov는 모든 버그를 해결할 수 있었다고 한다.
- 한 예로, 그가 React를 개발할때, 한번은 Facebook의 리액트 트리 절반을 지우며 버그를 쫓았는데 최종 재현은 단 50줄이었다고 한다.
느낀 점
이 글을 번역한 유경상 님이 쓰셨듯, 버그 해결의 본질적인 절차는 최근 AI 기반 디버깅을 더 잘 활용하는데도 도움이 된다. 사실 디버깅 툴이 발전하든, 프레임워크가 발전하든, AI가 발전하든 이런 본질적인 이해와 해결은 변하지 않을 것이라 생각한다. 프로그래밍의 문제를 올바르게 이해하고 해결한다라는 기본 원칙은, 실전적으론 문제를 간결하며 정확하게 재현하고 분해한다로 약간의 변형이 있을지언정 흔들리지 않는 대원칙일 것이기 때문이다.