감사의 목적은 번들 축소가 아니었다
- 흔한 동기(번들 크기, 파일 수)가 아님
- 목적: “죽은 코드를 살아있다고 착각하고 거기에 작업하는 사고” 방지
- 계기: 그 사고가 이미 여러 번 발생
- 조사 결과: 2주 동안 같은 패턴 5회 반복
원인: git log가 거짓말을 한다
가장 인상적인 사례:
- 라우터가 import하지 않아 어떤 경로로도 도달 불가한 파일
- 그 파일의 마지막 커밋: 7일 전
-
실제로 화면에 그려지는 살아있는 파일의 마지막 커밋: 1년 4개월 전
- 파일을 고치러 들어온 사람의 판단 근거: 파일명이 비슷한 게 둘이면 최근에 손댄 쪽이 현행
- 이 경우 죽은 파일이 훨씬 최신으로 보였다
- 살아있는 파일은 1년 넘게 안정적으로 돌아가서 손댈 일이 없었을 뿐
한 번 착각이 발생하면 자기강화된다.
- 누군가 죽은 파일 수정 → 그 파일의 타임스탬프 재갱신
- 다음 사람은 더 강한 확신으로 같은 파일 수정
- 5회 반복의 누적 경로로 추정
실사용자 버그로도 이어졌다
- 죽은 파일에 작업하면 보통 “아무 일도 안 일어남”으로 종료
-
그런데 이번엔 실제 버그 발생
- 문제 커밋: 죽은 파일에
data-guide앵커 추가 - 이 프로젝트의 가이드 투어 방식:
data-guide속성을 타겟팅해 화면 위에 툴팁 표시 - 투어 정의가 새 앵커를 가리키게 됨
- 그 앵커가 붙은 컴포넌트는 렌더링되지 않음
-
결과: 투어가 영원히 타겟을 못 찾음
- 검출: 정합성 테스트
- 방식:
data-guide를 소스에서 정규식으로 스캔 → 투어가 가리키는 타겟의 실재 여부 확인
여기서 한 가지 더 배운 것:
- 앵커를 prop으로 전달하는 방식(
treeGuideAnchor등)으로 리팩터링 시 정규식 스캔이 인식 불가 → 테스트 오탐 - 따라서 앵커는 JSX 리터럴로 유지하는 쪽이 이 테스트와 정합
정리한 것
- 진행 방식: PR 여러 건에 분할
| 대상 | 규모 |
|---|---|
| 도달 불가 파일 | 누적 102개 |
| 미사용 폰트·아이콘 | 약 11MB |
| 배럴 파일에만 남은 고아 아이콘 | 49개 (약 522KB) |
| 주석 처리된 죽은 코드 블록 | 수천 줄 |
| 도달 불가 분기 | TEST_MODE 분기 158줄 |
부수 발견: 애초에 동작할 수 없던 API 2건
죽은 API 정의를 찾다가 발견한 “죽지는 않았는데 동작할 수 없는” 사례:
1) 405가 확정인 API
- 프론트:
POST전송 - 백엔드:
@PutMapping만 존재 - 호출 시 무조건 405 Method Not Allowed
- 신고 0건 → 이 기능이 실사용되지 않았다는 정황
2) 템플릿 리터럴 보간이 빠진 API
- 경로 조립 시 백틱 미사용 또는
${}누락 -
결과:
BASE_PATH라는 문자열 자체가 URL로 전송 - 공통점: “코드가 존재한다”와 “코드가 동작한다” 사이의 간극
지우면 안 되는 것들도 있었다
감사를 무작정 밀면 사고가 난다. 만난 반례 두 가지:
동명 함수 함정
-
postUnitProcess엔드포인트가 두 파일에 존재 - 위치:
unit-process/api.ts,data-management/api.ts -
이름만 보고 “중복” 판단해 삭제 시 화면 사망
- 실제 소비자가 있는 쪽:
data-management - 그쪽이 만드는
usePostLcaUnitProcessMutation을useUnitProcess.tsx가 사용 -
unit-process쪽의usePostUnitProcessMutation은 소비자 0건 → 그것만 제거 - 판단 기준: 함수 이름이 아니라 생성된 훅의 소비자 수
참조가 없는데 지우면 안 되는 진입점
- 참조 0건이라 죽은 것처럼 보이는 파일
- 삭제 시 테스트 173개가 한꺼번에 붕괴
- 실체: 프로덕션 코드에서 참조되지 않을 뿐, 테스트의 진입점
“정적 참조 0건 = 죽음”이라는 규칙이 항상 맞지는 않는다.
남는 교훈
죽은 코드 정리를 “청소”로 생각하면 우선순위가 낮아진다. 실제 위험은 용량이 아니라 판단 근거를 오염시키는 것이다. 죽은 파일이 최신 타임스탬프를 달고 있으면, 다음 사람이 어디를 고쳐야 하는지 판단하는 근거 자체가 거짓이 된다. 그리고 그 오류는 한 번 발생하면 스스로를 강화한다.
동시에 감사 자체도 검증이 필요했다. 동명 함수와 무참조 진입점 두 사례에서 “참조가 없다”는 신호가 각각 다른 이유로 틀렸다. 삭제는 되돌리기 쉽지만, 삭제 후 CI가 통과하는지까지는 확인하고 넘어가야 했다.