Tooling · Documentation

경로 존재 여부만 확인하는 스크립트가
첫날 실제 버그를 잡았다

문서에 백틱으로 적힌 경로를 실제 파일 트리와 대조하는 일만 하는 휴리스틱 스크립트가 있다. 파싱도 하지 않고, 스니펫 안 코드가 무슨 일을 하는지도 모른다. 그런데 첫 실행에서 kotlin 문서 4곳의 버그를 잡았다. 돌아보면 검사 로직보다 오탐을 막으려고 내린 설계 결정이 더 중요했다.

문서에 적힌 파일 경로가 있는지만 묻는 검사는 돌려 볼 가치도 없을 만큼 단순해 보인다. 그래도 만들었고, 이유가 분명했다. 같은 백엔드 설계를 5개 언어로 나란히 구현해 둔 내 예제 프로젝트에서, 문서와 코드가 어긋난 이슈를 한꺼번에 닫고 난 참이었다. 그 이슈들이 모두 같은 식으로 발견됐다. 사람이든 에이전트든 문서를 읽고, 그 문서가 설명하는 코드를 따로 읽다가, 둘이 더는 맞지 않는다는 걸 알아챘다. 매번 같은 방식이라면 싸고 단순하게라도 자동화할 만하다.

일부러 싸고 단순하게

scripts/check_docs_drift.py가 확인하는 건 두 가지뿐이다. 둘 다 실제 파일 트리를 상대로 문자열만 맞춰 보고, 코드가 무슨 일을 하는지는 전혀 모른다.

  • STALE-ABSENCE는 문서에는 "아직 없다"고 적혀 있는데 파일이 이미 있는 경우다.
  • PHANTOM-PRESENCE는 문서가 스니펫에 "실제 코드"라고 붙이고 그럴듯한 경로까지 적었는데, 그런 파일이 없는 경우다.

잡아내는 범위는 이게 전부다. 스니펫을 파싱하지도 않고, 적힌 파일과 diff를 떠 보지도 않는다. 보여 준 코드가 그 파일 내용과 같은지도 따지지 않는다. 옆에 적힌 경로가 있는지 없는지만 본다. 솔직히 말하면 코드 리뷰 흉내를 내는 경로 존재 검사기다.

재미있는 부분은 예외 규칙에 다 있었다

이렇게 글자 그대로 읽는 검사기는 무엇을 걸러 내지 말아야 하는지 가르치기 전까지는 거의 오탐 생성기다. 예외 규칙은 하나같이 실제 문서에 돌려 보다가 단순한 버전이 틀린 지점에서 나왔다.

  • 코드 블록 헤더에 "추가 필요", "제안", "목표 형태" 같은 말이 있으면 STALE-ABSENCE로 읽지 않는다. 이 문서들에서 그런 표현은 거의 언제나 "이미 있는 파일에 이걸 추가한다"는 뜻이다. 늘 있는 파일(build.gradle, main.go, application.yml)로 시험해 보니 "아직 없음"으로 읽으면 매번 틀렸다.
  • pkg.path.TypeName 같은 전체 이름 참조는 대소문자로 가려낸다. 마지막 점 뒤가 대문자로 시작하면 파일 경로가 아닌 타입 참조로 보고 건너뛴다.
  • ...가 들어간 경로나 헤더는 무조건 건너뛴다. 생략 표시일 뿐 경로가 아니다.
  • 문서끼리 걸어 둔 .md 참조는 존재 검사에서 아예 뺀다. 문서 간 링크는 거의 언제나 살아 있어서 확인해 봐야 증명되는 게 없다.

영리한 규칙은 하나도 없다. 전부 실제로 오탐이 난 뒤에야 규칙으로 적었다.

첫날 잡은 것

**/*.md나 implementations/*/examples/**를 건드리는 푸시마다 돌도록 CI에 붙였다. 처음 제대로 돌린 날 잡을 만한 걸 잡았다. kotlin 문서 4개(config.md, module-pattern.md, observability.md, secret-manager.md)가 모두 코드 블록 헤더에 notification/infrastructure/X.kt라고 적고 있었다. 실제 경로는 account/infrastructure/notification/X.kt였다. 도메인 접두어가 빠졌고 두 세그먼트의 순서도 뒤집혀 있었다. 문서 4개에 같은 잘못된 경로가 있었고, 검사기를 넣은 커밋에서 함께 고쳤다.

일부러 확인하지 않는 것

백틱 경로 없이 문장으로만 적은 어긋남은 이 도구 눈에 보이지 않는다. "app 서비스가 compose에 없다"를 경로 없이 문장으로 쓴 경우가 그렇다. 스니펫 안쪽도 마찬가지다. 보여 준 코드가 적힌 파일 내용과 아직 같은지는 이 도구로는 물어볼 방법이 없다. 이 도구가 아는 건 경로가 있느냐 하나뿐이고, 거기에만 답한다.

싼 버전이 그래도 밥값을 하는 이유

이런 코드베이스에서 문서가 어긋나는 건 대개 로직이 미묘하게 바뀌어 설명이 틀어져서가 아니다. 파일을 옮기거나 이름을 바꿨는데, 문서에서 그 파일을 가리키던 한 줄을 고치지 않아서다. 기계적인 실수이고, 기계적인 검사라면 대상 코드를 한 줄도 이해하지 않고 잡아낼 수 있다. 공은 탐지 규칙 2개보다 예외 규칙 4개에 거의 다 들어갔다. 글자 그대로 읽는 스크립트에게 무엇을 무시할지 가르치는 일이, 결과를 믿고 쓸 수 있느냐를 갈랐다.

더 볼 자료

scripts/check_docs_drift.py(같은 백엔드 설계를 5개 언어로 구현해 둔 내 예제 프로젝트에 있는, 250줄이 안 되는 검사기 전체) · docs/docs-drift-check.md(이 도구가 확인하는 것과 일부러 확인하지 않는 것)