중복처럼 보이는 코드를 함부로 합치면 안 되는 이유
오래 운영한 코드베이스를 점검하다 보면 비슷하게 생긴 코드 뭉치를 발견하고 "이거 중복이네, 합치자"라는 충동이 듭니다. 중복 제거는 리팩토링의 기본이라고 배우기도 했고, 지우는 작업은 손도 빠릅니다. 저는 얼마 전 그 충동대로 갔다가 큰일 날 뻔했습니다.
운영 중인 서비스의 API 폴더를 점검하는데 /api/admin/docs와 /api/admin/documents라는 두 트리가 있었습니다. 하위 구조까지 거의 판박이였습니다. 둘 다 [id]가 있고, snapshots가 있고, restore가 있습니다. 파일을 열어 보면 핸들러 구성도 비슷합니다. 이 정도면 한쪽이 레거시라고 거의 확신했습니다. 예전에 경로를 정리하면서 옛날 트리를 지우다 만 흔적이겠거니 했습니다.
지우기 전에 한 가지만 확인하기로 했습니다. 프론트엔드에서 실제로 누가 어느 경로를 부르는가. 문서 관리 화면 코드를 열어 보니 스페이스별로 endpoint를 매핑하는 부분이 있었고, 거기서 확신이 무너졌습니다. 전역 문서 공간은 /api/admin/docs를 부르고, 프로젝트별 문서 공간은 /api/admin/documents를 부르고 있었습니다. 둘 다 현역이었습니다.
더 파 보니 겉모양만 닮은 남남이었습니다. 한쪽은 정수 autoincrement id를 쓰는 전역 문서 모델이고, 다른 쪽은 cuid 문자열 id를 쓰는 프로젝트 소속 문서 모델입니다. 필드 구성이 다르고, 한쪽만 zod로 입력을 검증하고 있었습니다. 구조가 닮은 건 복붙의 흔적이 아니라 같은 패턴으로 두 도메인을 각각 만든 결과였습니다. CRUD에 스냅샷과 휴지통 복구가 붙는 문서 관리라면 어느 도메인이든 이 모양이 나옵니다.
만약 호출자 확인을 건너뛰고 한쪽 트리를 지웠다면 프로젝트 문서 기능이 통째로 죽었을 겁니다. 무리해서 하나로 합치는 쪽을 택했어도 id 타입부터 충돌합니다. 정수와 문자열 id를 한 라우트에서 받으려면 분기가 생기고, 그 분기는 두 트리를 따로 두는 것보다 읽기 어려웠을 겁니다. 결국 그대로 두는 것이 정답인 중복이었습니다. 정확히는 중복이 아니었던 거지만.
이날 이후로 저는 중복 판단 기준을 코드 모양에서 두 가지 질문으로 바꿨습니다. 실제 호출자가 같은가, 그리고 다루는 데이터 모델이 같은가. 둘 다 예일 때만 중복입니다. 모양이 닮았다는 것은 판단 근거가 못 됩니다. 잘 만든 코드일수록 같은 패턴을 반복하기 때문에, 오히려 닮은 코드가 많이 나옵니다. 중복 제거가 목표가 되는 순간 이 구분이 흐려지니, 지우는 손보다 확인하는 눈이 먼저 가야 한다고 이제는 생각합니다.
같은 점검에서 겪은 다른 이야기:
함께 읽기
- 반복 코드 131줄을 정규식으로 한 번에 바꿔도 괜찮았던 이유혼자 운영하는 서비스는 점검을 자꾸 미루게 됩니다. 기능이 돌아가고 있으면 코드를 다시 들여다볼 이유가 생기지 않고, 그 사이에 같은 패턴이 계속 복사됩니다. 저도 얼마 전 하루를 잡고 운영 중인 서비스 코드를 전체 점검했는데, 관리자 API 라우트 파일 70개에 완전히 똑같은 인증 가드 한 줄이 131번 반복되고 있었…
- git push 후 자동 검사가 시작되는 이유: Continuous Integration(CI) 입문코드를 수정하고 로컬에서 잘 동작하는 것까지 확인했습니다. 이제 아래처럼 GitHub에 올립니다.
- Next.js 앱에서 클릭이 한 박자 느리게 느껴질 때 살펴본 것들서버가 멀면 응답이 느린 건 어쩔 수 없습니다. 제 경우 오리진 응답 지연에 CDN 우회 경로까지 겹쳐 페이지 응답에 1초 가까이 걸리는 상황이었고, 네트워크 쪽은 당장 손댈 수 없었습니다. 그래서 응답 속도 대신 "눌렀을 때 반응하는 속도"를 올리는 쪽으로 방향을 잡았습니다. 느린 것과 느리게 느껴지는 것은 생각보다 …
- Cloudflare를 붙였는데 한국에서 오히려 느려진 이유한국 사용자를 대상으로 운영 중인 데모 사이트에서 응답 지연을 점검했습니다. 도메인은 Cloudflare 프록시를 거치게 해뒀고, 원본 IP와 오리진을 보호하기 위해 켜둔 상태였습니다. 그러다 사이트를 손보는 중에 "버튼이 한 박자 늦게 눌리는 것 같다"는 얘기가 나왔고, 확인해 보니 앱 코드가 아니라 이 프록시 경로가…
- RAG 챗봇이 "그건 언제 바뀐 거야?"에 답하게 만들기사내 문서를 근거로 답하는 RAG 챗봇을 도입하면 대부분 비슷한 지점에서 막힙니다. 첫 질문에는 그럴듯하게 답하는데, 이어서 "그럼 그건 언제 바뀐 거야?" 같은 질문을 던지면 갑자기 엉뚱한 문서를 근거로 들고 옵니다. 사용자는 "AI가 헛소리를 한다"고 느끼고, 도입은 거기서 멈춥니다.