Files
2nd/10_Wiki/Topics/Architecture/레거시 코드 (Legacy Code).md
T

4.8 KiB

레거시 코드 (Legacy Code)

📌 Brief Summary

레거시 코드는 전통적으로 다른 사람이 작성했거나 이해하고 변경하기 어려운 복잡한 코드를 의미하기도 하지만, 마이클 페더스(Michael Feathers)의 정의에 따르면 "테스트가 없는 코드"를 뜻합니다[1-3]. 아무리 구조가 좋고 객체지향적으로 잘 작성되었더라도 테스트가 없다면 동작의 변경을 빠르고 검증 가능하게 수행할 수 없으므로 나쁜 코드로 간주됩니다[4]. 이러한 레거시 코드는 변경 시 즉각적인 피드백을 받을 수 없어 소프트웨어 개발에 소요되는 시간과 비용을 고갈시키는 주된 원인이 됩니다[5].

📖 Core Content

  • 레거시 코드의 딜레마와 의존성 문제 레거시 코드를 안전하게 수정하려면 테스트가 필요하지만, 테스트를 작성하기 위해서는 기존 코드의 강한 의존성을 끊어내기 위해 코드를 먼저 수정해야 하는 모순적인 상황이 발생하며 이를 '레거시 코드의 딜레마'라고 부릅니다[6, 7]. 레거시 코드의 가장 핵심적인 문제는 코드가 서로 너무 강하게 결합되어 있어 독립적인 테스트가 불가능하다는 점입니다[7].

  • 레거시 코드 개선 알고리즘 레거시 시스템을 점진적으로 개선하기 위해서는 최소한의 안전한 리팩토링을 수행해야 하며, 다음의 알고리즘을 따릅니다[6, 8].

    1. 변경 지점 및 테스트 지점 식별: 수정이 필요한 로직의 위치와 해당 로직을 보호할 수 있는 테스트 작성 위치를 찾습니다.
    2. 접점(Seams) 활용 및 의존성 제거: 접점이란 소스 코드를 직접 수정하지 않고도 프로그램의 동작을 바꿀 수 있는 지점(예: 인터페이스 추상화 및 가짜 객체 주입)을 의미합니다[7, 9, 10]. 이를 통해 테스트 실행을 방해하는 의존성을 끊어냅니다.
    3. 테스트 작성: 현재 어떻게 동작하는지를 기록하는 승인 테스트(Approval Tests) 또는 캐릭터리제이션 테스트(Characterization Tests)를 작성하여 안전망을 확보합니다[8].
    4. 기능 수정 및 리팩토링: 테스트가 확보된 후 요구사항을 반영하고 코드를 리팩토링합니다[6, 8].
  • 시간이 부족할 때의 대처 기법 (Sprout & Wrap) 테스트가 없는 방대한 코드를 전면적으로 리팩토링할 시간이 없을 때 사용할 수 있는 기법입니다[11].

    • 스프라우트 기법(Sprout Technique): 기존의 거대한 메서드에 코드를 덧붙이는 대신, 새로운 로직을 별도의 독립되고 검증된 함수(또는 클래스)로 작성한 후 기존 코드의 삽입 지점에서 이를 호출하는 방식입니다[8, 12].
    • 랩 기법(Wrap Technique): 기존 메서드와 동일한 이름의 새 메서드를 만들고, 그 안에서 기존 메서드를 호출하기 전이나 후에 새로운 테스트 가능한 로직을 배치하여 감싸는 방식입니다[13].
  • 스크래치 리팩토링 (Scratch Refactoring) 이해하기 어렵고 테스트가 없는 코드를 파악하기 위해 사용하는 기법입니다. 변수명을 바꾸거나 함수를 추출하는 등 코드를 자유롭게 변경하며 구조를 이해한 뒤, 파악이 끝나면 작성한 변경 사항을 모두 되돌리고(revert) 적절한 테스트와 함께 처음부터 다시 작업을 시작합니다[14, 15].

⚖️ Trade-offs & Caveats

  • 초기 테스트 도입의 위험성: 레거시 코드에 테스트를 도입하기 위해 의존성을 끊는 작업 자체는 아직 테스트 안전망이 없는 상태에서 코드를 변경해야 하므로 상당한 위험을 수반합니다[3]. 따라서 아주 국소적이고 안전한 최소한의 변경만을 수행해야 합니다[6].
  • 미학적 타협의 필요성: 레거시 코드를 테스트 가능한 상태로 만드는 과정(예: 의존성 분리를 위한 임시 조치 등)에서 일시적으로 코드의 형태가 기존보다 다소 더 지저분해질 수 있습니다[16]. 이는 외과 수술을 위해 절개를 하는 것과 같으며, 코드를 더 건강한 상태로 옮기기 위해 미학적 판단을 유보해야 할 때가 있습니다. 완벽함('best')을 추구하느라 더 나아짐('better')을 포기해서는 안 됩니다[16].
  • 스프라우트와 랩 기법의 한계: 스프라우트(Sprout)와 랩(Wrap) 기법은 기존 레거시 코드를 건드리지 않고 안전하게 새 기능을 추가할 수 있게 해주지만, 이상적인 해결책은 아닙니다[17]. 이 기법들만을 남용할 경우 원래의 레거시 코드는 리팩토링되지 않은 채 계속 방치될 수 있으므로 주의해야 합니다[11, 17].

Last updated: 2026-05-03