← 모든 글

legacy 라는 단어를 쓰지 않는 이유

결제·정산 자동화를 운영하는 HEDVION이 "레거시"를 내부에서 금지한 이유. 모호한 단어가 기술 부채를 숨기고 행동을 막는 방식, 4가지 구체적 분류와 실전 사례를 소개한다.

단어 하나가 결제 장애를 숨긴다

결제·정산 시스템을 직접 운영하는 팀에서 "레거시"라는 단어는 단순한 형용사가 아니다. 그것은 면죄부다. "이 모듈은 레거시라서요"라는 한 마디가 나오는 순간, 그 코드는 더 이상 질문을 받지 않는다. 왜 이번 정산 오류가 그 모듈에서 났는지, 왜 매달 말일이면 정산 배치가 3시간씩 늦어지는지—질문이 사라지고 "언젠가 교체해야 할 것"이라는 막연한 문장만 남는다.

HEDVION에서 정산 파이프라인을 처음 체계적으로 진단했을 때, 팀이 "레거시"라고 부르는 영역은 전체 코드베이스의 약 40%였다. 그런데 그 40%를 실제로 분류해보니 이야기가 달라졌다. 테스트 커버리지 0%인 함수, 3년 전 담당자가 퇴사한 뒤 아무도 수정한 적 없는 모듈, 특정 리눅스 커널 버전에서만 실행되는 배치 스크립트, 설계는 멀쩡하지만 현재 요구사항과 어긋난 API—이 네 가지는 전혀 다른 문제다. 그런데 모두 "레거시"라는 한 단어로 처리되고 있었다.

결제 현장에서 모호함의 실제 비용

추상적인 단어는 추상적인 의사결정을 낳는다. 결제와 정산 자동화 현장에서 이것이 특히 위험한 이유는 명확하다. 오류의 파급이 실시간으로 금전적 손실과 연결되기 때문이다. "나중에 고치면 된다"는 판단이 실제로 얼마의 비용을 만들어내는지는, 정산 수치로 봐야 비로소 실감이 된다.

HEDVION 정산 자동화 파이프라인에 "레거시 모듈"로 분류된 중복 트랜잭션 필터링 로직이 있었다. 이 모듈은 "언젠가 교체 대상"이라는 딱지가 붙어 스프린트마다 우선순위에서 밀렸다. 결과적으로 해당 로직의 엣지 케이스—특정 PG사의 부분 취소 후 재승인 패턴—가 처리되지 않은 채 약 6주간 운영됐고, 그 기간 동안 약 0.3%의 트랜잭션에서 이중 정산 시도가 발생했다. 수작업 대사(reconciliation)로 잡아냈지만, 이 수작업에 매주 4~5시간이 소요됐다. "레거시라서 나중에"라는 말 한 마디가 팀 전체로 보면 30시간 이상의 누적 낭비로 이어진 것이다. 만약 그 단어 대신 "특정 취소-재승인 패턴에 대한 분기 처리 없음"이라고 불렀다면, 그것은 스프린트에 태울 수 있는 카드가 됐을 것이다.

대신 쓰는 표현들—그리고 각각에 따르는 다음 행동

우리가 "레거시"라고 부르려는 상황은 실제로 서로 다른 네 가지 문제다. 각각을 정확하게 분리해 부르면, 각각에 맞는 다음 행동이 생긴다.

  • 테스트 부재(Zero coverage): "이 함수는 테스트가 없어서 변경 영향 범위를 추적하기 어렵다." → 핵심 경로 스모크 테스트 작성, 또는 변경 범위를 테스트 가능한 단위로 분리.
  • 지식 소멸(Knowledge vacuum): "이 모듈을 마지막으로 수정한 사람이 팀에 없고 인라인 코멘트도 없다." → 코드 읽기 세션 예약, 또는 동작 역공학 문서화.
  • 설계 부채(Design debt): "이 API는 지금 기준으로 설계했다면 이렇게 만들지 않았을 것이다. 현재 요구사항과 마찰이 발생한다." → 어댑터 레이어 도입 여부 검토, 또는 리팩토링 비용 대비 유지 비용 정량화.
  • 환경 의존성(Environment lock): "이 배치는 특정 서버 설정이 없으면 실행되지 않는다." → 환경 변수 명시적 선언, 컨테이너화, 또는 실패 조건 문서화.

이 분류에서 중요한 것은, 각각이 이틀에서 1주일 안에 처리 가능한 크기라는 점이다. 테스트 부재는 테스트 스프린트 한 번으로 해결 가능하고, 환경 의존성은 Dockerfile 몇 줄로 잡힌다. 그런데 이것들이 "레거시"라는 이름 아래 있는 한, 전부 "대규모 교체 프로젝트"의 일부로만 존재한다. 대규모 교체 프로젝트는 분기마다 우선순위에서 밀리고, 그 안의 이틀짜리 문제들은 해결되지 않은 채 누적된다.

자동화 파이프라인에서의 실전 시나리오

HEDVION 정산 자동화 파이프라인 안에 "레거시"로 불리던 CSV 파싱 모듈이 있었다. 어느 날 그 모듈을 직접 진단하기로 했다. 목적은 전체 교체가 아니라, 실제로 무엇이 문제인지를 확인하는 것이었다.

진단 결과 실제 문제는 두 가지였다. 첫째, 특정 PG사의 헤더 포맷 변경에 대응하는 예외 처리가 없었다—이것은 설계 부채가 아니라 누락된 기능이었다. 둘째, 파싱 결과를 검증하는 어서션이 전혀 없었다—이것은 테스트 부재였다. 두 문제 모두 각각 이틀 안에 처리 가능한 크기였다. "레거시 모듈"이라는 이름표가 없었다면 이미 처리됐을 문제들이었다. 이 경험 이후 팀 내 규칙이 하나 생겼다. 어떤 코드가 스프린트 논의에 올라왔을 때 "레거시라서요"라는 발언이 나오면, 그 자리에서 반드시 위 네 분류 중 어디에 해당하는지 말해야 한다. 분류가 안 된다면, 해당 코드를 직접 열어보기 전까지는 판단을 유보한다.

트레이드오프: 이 접근이 항상 효율적이지 않은 이유

이 방식에도 비용이 있다는 걸 인정해야 한다. "레거시"라고 넘기면 30초지만, "테스트 커버리지 0%, 설계 부채 있음, 환경 의존성 3개"로 분류하는 것은 15분짜리 대화다. 팀이 바쁠 때, 혹은 해당 코드가 앞으로 수개월간 건드릴 일이 없을 때, 이 비용이 현실적으로 느껴진다.

우리가 취한 타협은 이렇다. 모든 코드를 매번 해부할 필요는 없다. 다만 두 조건 중 하나에 해당하면 반드시 구체화한다. 첫째, 해당 코드가 스프린트 논의에 올라왔을 때. 둘째, 그 코드에 연관된 장애나 이슈가 발생했을 때. "지금 안 건드릴 코드"와 "건드려야 하는데 레거시라 안 된다는 코드"는 다르다. 전자는 그냥 두어도 된다. 후자만 구체화하면 된다. 그 구분 자체가 이미 "레거시"라는 단어로는 만들 수 없는 생각이다.

지금 당장 적용할 수 있는 시사점

팀에 바로 도입할 수 있는 세 가지 행동을 제안한다.

1. "레거시" 발언을 후속 질문으로 받아라. 다음번에 누군가 "레거시라서요"라고 말하면, "구체적으로 어떤 부분이 문제인가요? 테스트 없음, 문서 없음, 설계 부채, 환경 의존성 중 어디에 해당하나요?"라고 즉시 물어라. 두 번 이상 반복하면 팀이 자연스럽게 스스로 분류하기 시작한다. 별도의 프로세스 도입 없이, 질문 하나만으로 시작할 수 있다.

2. 기술 부채를 분류 태그로 관리하라. Jira든 Linear든 Notion이든, 기술 부채 이슈에 [no-test], [no-doc], [design-debt], [env-lock] 같은 태그를 붙여라. 태그가 쌓이면 어떤 종류의 부채가 많은지 패턴이 보이고, 한 번에 처리할 수 있는 묶음이 생긴다. 특히 [no-test] 태그가 결제·정산 핵심 경로에 집중돼 있다면, 그것은 "대규모 교체 프로젝트"가 아니라 "테스트 스프린트 1회"로 해결 가능한 문제다.

3. "나중에 교체"를 결정으로 만들어라. "레거시니까 언젠가"는 결정이 아니다. 대신 명시적으로 선택하라: "이 모듈은 다음 분기까지 현 상태 유지, 단 [no-test] 이슈 2개는 이번 스프린트에서 처리한다." 유지든 교체든, 결정에는 일정과 책임이 따른다. "레거시"라는 단어는 결정이 아니다—결정 회피다.

결제와 정산 자동화를 직접 운영하는 팀에서 코드에 대한 발언 방식은 시스템 신뢰성과 직결된다. 정확한 언어는 정확한 조치를 만들고, 정확한 조치는 장애를 줄인다. 단어 하나를 바꾸는 것으로 시작하는 엔지니어링 문화의 변화—작게 보이지만 쌓이면 실제로 달라진다.

— by slecs

* 위 링크는 인프런 affiliate 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

📚 추천 강의
한 입 크기로 잘라먹는 바이브코딩 (with Claude Code)
Claude Code로 바이브코딩, 개발자라면 꼭 들어야 할 필수 강의
강의 보러가기 →

* 위 추천 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.