개발자로 커리어를 이어오면서 가장 많이 들은 단어 중 하나를 꼽으라면, 단연 '레거시(Legacy)'일 것이다. 그리고 종종 아래와 같은 이야기를 듣곤 한다.
"이 시스템은 너무 오래됐어요." "이번에는 V2로 새로 갑니다." "차세대 프로젝트를 시작합니다." "이번엔 처음부터 다시 만들겠습니다."
IT 업계에서 일하면서 이런 이야기를 한 번도 들어보지 못한 개발자가 있을까 싶다. 그리고 이런 말들은 마치 레거시는 반드시 제거해야 할 문제인 것처럼 들린다.
그렇다면 레거시란 무엇일까. 단순히 오래된 코드를 의미하는 것일까.
회사에서 데브 위클리나 커피챗을 하다 보면 레거시에 대한 이야기는 빠지지 않는다. 대부분은 비슷한 특징을 가진 시스템을 떠올린다. 의존성 버전이 오랫동안 업데이트되지 않은 시스템, 수년간 운영되며 구조가 복잡해진 시스템, 또는 누구도 선뜻 수정하려 하지 않는 코드. 이러한 시스템 때문에 개발 속도가 느려지고, 온보딩 비용이 증가하며, 작은 수정에도 긴장하게 되는 경험을 한 개발자는 적지 않을 것이다.
하지만 나는 여기에서 종종 아쉬움을 느낀다.
레거시 시스템
내가 생각하는 레거시는 단순히 오래된 코드가 아니다. 레거시는 오랜 기간 서비스를 운영하며 수많은 장애를 해결하고, 고객의 요구사항을 반영하고, 비즈니스 정책의 변화를 받아들이며 살아남은 결과물이다. 코드 한 줄 한 줄에는 당시의 문제를 해결하기 위해 고민했던 흔적과 운영 경험이 녹아 있다.
물론 지금의 관점에서는 비효율적으로 보이는 구현도 있을 수 있다. 하지만 그것이 항상 잘못된 선택이었다고 단정할 수는 없다. 당시에는 가장 현실적인 선택이었을 수도 있고, 서비스를 멈추지 않고 회사가 성장하기 위해 불가피했던 결정이었을 수도 있다. 어쩌면 레거시 시스템은 지금까지 조직을 지탱해 온 가장 든든한 자산인지도 모른다.
물론 모든 시스템을 끝없이 유지할 수 있는 것은 아니다. 구조적인 한계에 도달했고, 점진적인 개선보다 새로운 설계가 더 합리적인 경우도 분명 존재한다. 새로운 아키텍처와 기술 스택, 더 나은 사용자 경험을 위해 전면 재구성이 필요한 순간도 있다. 하지만 내가 아쉬움을 느끼는 것은 전면 재작성 자체가 아니다.
왜 그 시스템은 그 지경에 이를 때까지 조금씩 개선되지 못했을까?
왜 새로운 구조는 작은 단위로 도입되지 못했을까. 왜 복잡한 로직은 계속해서 복잡한 채로 남겨졌을까. 왜 우리는 그 복잡성을 당연한 것으로 받아들였을까.
레거시는 하루아침에 만들어지지 않는다
대부분의 개발자는 하루를 이런 흐름으로 보낸다.
에러를 발견한다. 문제의 원인을 찾는다. 수정해야 할 로직을 분석한다. 예상보다 훨씬 복잡한 구조를 마주한다. 하지만 서비스는 빨리 복구되어야 한다. 결국 문제가 발생한 부분만 최소한으로 수정한다.
이 선택은 대부분 옳다. 이러한 선택을 비판할 수 없다. 서비스는 멈추면 안 되고, 고객은 기다려주지 않는다. 문제는 다양한 이유로 인해 개선작업 혹은 리팩토링 작업을 미루고 미뤘던 우리의 선택 이었을지도 모른다. 이런 작은 선택들이 수없이 반복되면서 코드베이스는 점점 복잡성을 축적한다. 그리고 몇 년 뒤 누군가는 그 시스템을 바라보며 말한다.
"이건 레거시 시스템입니다."
하지만 그 레거시는 어느 날 갑자기 나타난 것이 아니다. 우리 모두가 서비스를 지키기 위해 내렸던 수많은 작은 선택들이 모여 만들어진 결과다. 레거시는 우리의 실패가 아니라, 우리가 남긴 역사다.
리팩토링은 코드의 아름다움을 위한 작업이 아니다
나는 데브 위클리에서 늘 같은 이야기를 한다.
- 누가 봐도 이해하기 쉬운 코드로 작성할 것.
- 변경의 영향 범위를 최소화할 것.
- 추상화를 했다면 반드시 테스트 코드로 최소한의 방어책을 마련할 것.
- 좋은 아키텍처를 도입했다면, 시간이 지나도 그 구조가 유지될 수 있도록 시스템적인 장치를 마련할 것.
이런 이야기들은 코드를 예쁘게 만들기 위한 기준이 아니다. 미래의 개발자가 안심하고 변경할 수 있는 환경을 만들기 위한 기준이다. 좋은 코드의 가치는 작성하는 순간보다 변경하는 순간에 드러난다. 누군가 기능을 추가할 때, 버그를 수정할 때, 장애를 해결할 때 "이 정도는 건드려도 괜찮겠다."라는 신뢰를 줄 수 있는 코드. 나는 그것이 좋은 코드라고 생각한다.
리팩토링은 고가용성을 위한 투자다
많은 사람들이 리팩토링을 생산성과 반대되는 활동이라고 생각한다. 또한 프로덕트 입장에서는 굳이 건드려서 사고내는 일을 하는 것처럼 보일 수도 있다. 하지만 나는 오히려 그 반대라고 강력히 믿는다. 복잡한 코드는 작은 수정도 어렵게 만들고, 작은 수정은 곧 큰 장애로 이어질 가능성을 높인다. 반대로 변경하기 쉬운 구조는 작은 단위의 배포를 가능하게 하고, 테스트를 쉽게 만들며, 문제가 생겼을 때 빠르게 원인을 찾고 롤백할 수 있도록 돕는다. 결국 리팩토링은 코드를 예쁘게 만드는 작업이 아니라 서비스를 오래 운영하기 위한 투자다.
AI 시대에 더 중요해진 코드베이스
AI는 이제 놀라울 정도로 빠르게 코드를 작성한다. 새로운 기능을 만드는 비용은 점점 낮아지고 있다. 하지만 AI가 대신하기 어려운 것이 있다. 수년간 운영된 코드베이스를 이해하는 일. 왜 이 구조가 만들어졌는지 이해하는 일. 어떤 변경이 어떤 장애를 만들 수 있는지 판단하는 일. 그리고 서비스를 멈추지 않은 채 안전하게 발전시키는 일.
AI 시대의 경쟁력은 얼마나 많은 코드를 생성하느냐가 아니라, 얼마나 건강한 코드베이스를 유지하고 발전시킬 수 있느냐에 달려 있을지도 모른다.
V2, V3 그리고 언제까지 계속 새로운 것을 만들 것인가
개발을 하다 보면 다음과 같은 이야기를 자주 듣곤 한다. 이번에는 새로운 버전을 만들어서 해당 버전을 새로운 기능 추가 시 도입해 보겠다는 이야기. 해당 의사결정은 틀린 결정도 아니다. 어쩌면 장기적으로 더욱 좋은 결정 이었을지도 모르며 훗날 시스템을 좋게 유지하는데 있어 큰 터닝 포인트 일지도 모른다.
우리는 종종 V2를 만들면 V1을 완전히 종료(Fade-out)할 수 있을 것이라고 기대한다. 하지만 현실은 조금 다르다. 서비스는 무중단으로 운영되어야 하며, 고객은 하루아침에 모두 새로운 시스템으로 이동하지 않는다. 결국 V1의 일부는 남고, 그 위에 V2가 올라가고, 또 시간이 지나 V3가 만들어진다. 그렇게 조직은 세 개의 버전을 동시에 이해해야 하는 상황을 맞이한다. 문제는 레거시가 존재한다는 사실이 아니라, 레거시를 점진적으로 진화시키는 능력을 잃었을 때 비로소 시작된다.
실제로 대부분의 V2 프로젝트는 생각보다 오래 지속된다. 초기에는 "핵심 기능만 먼저 이전하자."라는 목표로 시작하지만, 운영 중인 서비스는 새로운 요구사항을 기다려주지 않는다. 기존 시스템에도 기능을 추가해야 하고, 새로운 시스템에도 동일한 기능을 구현해야 하는 상황이 반복된다. 어느 순간 두 시스템은 함께 성장하기 시작하고, 마이그레이션은 점점 더 어려워진다. 결국 우리는 하나의 코드베이스를 관리하는 대신 두 개의 코드베이스를 관리하게 된다. 그리고 시간이 지나면 V2 역시 또 다른 레거시가 되고, 새로운 V3를 이야기하기 시작한다.
나는 여기서 한 가지 질문을 던지고 싶다.
만약 우리가 처음부터 코드베이스를 조금씩 건강하게 유지해 왔다면, 정말 V2가 필요했을까?
물론 모든 시스템이 점진적인 개선만으로 해결될 수 있다는 이야기는 아니다. 비즈니스의 방향이 완전히 바뀌거나, 기존 아키텍처가 더 이상 요구사항을 감당할 수 없는 순간도 분명 존재한다. 그런 경우 새로운 시스템을 만드는 것은 충분히 합리적인 선택이다. 하지만 V2를 만드는 가장 큰 이유가 "기존 시스템을 아무도 건드릴 수 없기 때문"이라면, 그것은 기술의 문제가 아니라 코드베이스를 관리해 온 방식의 문제일 가능성이 크다. 나는 이러한 이유 때문에 V2가 여럿 생기는 것을 현 회사에서 경험 했고, 현재는 V3까지 나온 상황에 이르렀다.
그래서 위와 같은 이유로 나는 리팩토링을 코드의 아름다움을 위한 작업이라고 생각하지 않는다. 리팩토링은 미래의 변경 비용을 줄이는 작업이다. 오늘 발견한 복잡성을 오늘 조금이라도 줄이는 것. 새로운 기능을 추가하면서 함께 테스트 코드를 보강하는 것. 의존성을 꾸준히 관리하는 것. 구조가 무너지기 시작하면 작은 단위로 바로잡는 것.
이런 작은 선택들이 반복될수록 코드베이스는 건강해지고, 시스템은 새로운 요구사항을 자연스럽게 받아들일 수 있는 힘을 갖게 된다. 즉 가용성이 높아진다. 좋은 코드베이스는 처음부터 완벽하게 설계된 코드베이스가 아니다. 지속적으로 리팩토링되며 변화에 적응할 수 있는 코드베이스다. 결국 리팩토링은 과거를 정리하는 작업이 아니라 미래를 준비하는 작업이다. 그리고 내가 생각하는 좋은 조직은 V2를 자주 만드는 조직이 아니라, 하나의 코드베이스를 오랫동안 건강하게 성장시킬 수 있는 조직이다.
언젠가 새로운 버전이 필요할 수도 있다. 하지만 그 이유는 "더 이상 이 시스템을 건드릴 수 없어서"가 아니라, 비즈니스가 새로운 방향으로 진화했기 때문이어야 한다.
그 차이가 건강한 코드베이스를 가진 조직과 그렇지 않은 조직을 가르는 가장 큰 기준이라고 믿는다.