레거시 코드 리팩토링 실전 회고
개발자라면 한 번쯤 들어봤을, 혹은 직접 내뱉었을 말이 있습니다.
"이거 건들면 어디서 터질지 몰라요."
저는 이 말을 프로젝트 인수인계 첫날에 들었습니다.
대규모 이커머스 플랫폼의 기획전 시스템. 운영 기간만 10년이 넘은 코드였습니다.
기획전이라는 도메인 특성상 이벤트 시간에 트래픽이 폭발적으로 몰리는 구조인데, 정작 그 트래픽을 받아내는 코드는 누구도 자신 있게 설명할 수 없는 상태였습니다.
새로운 사업 기획이 나오면? 기존 담당자들은 회피하거나, 용기 있게 로직을 추가하더라도 어딘가에서 사이드 이펙트가 터졌습니다.
전형적인 "살아있지만 아무도 제대로 이해하지 못하는 시스템"이었습니다.
이 글은 그 시스템을 AI를 활용해 분석하고, 클린 아키텍처 기반의 MSA로 재설계한 경험을 공유하는 글입니다.
다만 미리 말씀드리면, 이 글은 특정 AI 도구를 추천하는 글이 아닙니다.
어떤 AI를 쓰느냐보다, 개발자가 AI를 어떤 전략으로 활용하느냐가 핵심이라는 이야기를 하려고 합니다.
코드를 열어본 첫인상은 솔직히 막막함이었습니다.
하나의 서비스 로직을 타고 들어가면 내부에 또 하나의 서비스급 로직이 있고, 그 안을 다시 타고 들어가면 또다시 거대한 로직 덩어리가 나오는 깊은 계층 구조가 곳곳에 존재했습니다. 분석한다고 파고 들어갔더니 끝이 아니라 또 하나의 세계가 펼쳐지는 느낌. 클래스 하나가 수백 줄이 아니라 수천 줄. 메서드 하나가 하나의 마이크로서비스 규모의 책임을 지고 있는 형태. 경험 있는 개발자분들이라면 고개를 끄덕이실 겁니다.
10년이라는 시간 동안 여러 사람의 손을 거치면서, 조건문 안에 임시방편으로 로직을 끼워 넣은 흔적들이 지층처럼 쌓여 있었습니다.
특히 외부 API 연동 부분은 상황이 더 심각했습니다. 연동 문서가 존재하지 않거나, 있더라도 어디에 있는지 아무도 모르는 상태. API를 호출하는 코드 자체가 유일한 명세서 역할을 하고 있었습니다.
분석 결과, 기존 시스템 위에서 점진적 개선을 하는 것은 리스크가 너무 컸습니다. 새로운 MSA 프로젝트로 재구성하기로 결정했고, 아키텍처 원칙으로 클린 아키텍처를 채택했습니다.
프레임워크 구조를 먼저 잡고 개발에 착수했지만, 진짜 문제는 그다음이었습니다. 새 아키텍처 위에 무엇을 옮겨야 하는지, 즉 기존 로직의 정확한 이해가 선행되어야 했습니다.
처음에는 AI 없이 순수하게 코드를 읽으며 분석을 시도했습니다. 하지만 계층의 깊이와 복잡도가 상당했고, 일정 안에 사람의 힘만으로 전체를 파악하는 것은 현실적으로 어렵다는 결론에 도달했습니다.
여기서부터 AI를 본격적으로 투입했습니다.
AI를 투입하면서 가장 먼저 세운 원칙이 있습니다.
전체 로직을 한 번에 AI에게 던지지 않는다.
이건 실제로 해보면 바로 체감하는 부분인데, 수천 줄의 코드를 한꺼번에 넣으면 AI도 핵심을 놓치거나 엉뚱한 방향으로 분석을 이어가는 경우가 빈번합니다. 할루시네이션 리스크도 급격히 올라갑니다.
대신 다음과 같은 단계적 접근을 취했습니다.
먼저 AI에게 상세 로직이 아닌 전체 호출 흐름만 파악하도록 요청했습니다. "이 클래스가 어떤 클래스를 호출하고, 그 클래스는 또 어디를 호출하는가"라는 의존 관계의 지도를 그리는 작업입니다. 계층이 몇 단계까지 내려가는지, 전체 윤곽을 먼저 잡는 것이 목적입니다.
전체 지도가 나오면, 계층 구조의 가장 깊은 곳(leaf)부터 역순으로 AI에게 상세 분석을 요청했습니다. 가장 안쪽의 로직은 상대적으로 의존성이 적기 때문에 AI의 분석 정확도가 높고, 이 분석 결과를 기반으로 한 단계씩 상위로 올라오면 AI도, 개발자도 맥락을 유지하기가 수월해집니다.
외부 API 호출 부분은 AI의 패턴 인식 능력이 빛을 발한 영역입니다. AI는 규격화된 구조(요청 파라미터, 응답 포맷, 헤더 등)를 파악하는 데 상당히 강합니다. 코드에서 API 호출 패턴을 추출하고, 이를 마크다운 형태의 API 명세서로 문서화하도록 요청했습니다.
이렇게 만들어진 문서는 단순히 분석용이 아니라, 이후 새로운 세션에서 AI와 대화를 이어갈 때 컨텍스트로 활용할 수 있는 자산이 됩니다.
전체 구조와 상세 구조를 파악한 후, 제가 한 일은 이 모든 것을 다이어그램으로 시각화하는 작업이었습니다. 텍스트로 정리된 분석 결과만으로는 머릿속에서 전체 그림이 선명하게 그려지지 않았기 때문입니다.
이 작업 역시 AI에게 요청했습니다. 앞서 문서화한 결과물을 입력으로 제공하고, 시스템의 호출 관계와 데이터 흐름을 다이어그램으로 정리하도록 한 것입니다. 사람이 직접 처음부터 다이어그램을 그리는 것과 비교하면 초안 작성 속도가 압도적으로 빨랐고, 이 초안을 기반으로 제가 이해한 내용과 맞는지 검증하며 수정해 나가는 방식이 훨씬 효율적이었습니다.
다이어그램으로 전체 그림이 잡히고 나면, 그다음은 현재 비즈니스 로직에 적합한 디자인 패턴을 선정하는 작업이었습니다.
기존 코드가 아무리 복잡해도, 다이어그램 위에서 보면 각 영역의 책임과 역할이 보이기 시작합니다. 이 구조에 어떤 패턴을 입히면 깔끔하게 정리되는지 — 이 판단은 개발자의 설계 역량이 필요한 영역이지만, 패턴을 적용해서 기존 로직을 정리하는 실무 작업에는 다시 AI를 적극적으로 활용했습니다.
핵심은 단계적으로 진행하는 것이었습니다. 한꺼번에 전체를 재작성하는 것이 아니라, 단위별로 기존 로직을 분석하고, 새로운 패턴으로 정리하고, 검증하는 사이클을 반복하는 방식입니다.
기존 비즈니스 로직을 단위별로 쪼개면서 병행한 것이 있습니다. TDD(Test-Driven Development)를 통한 테스트입니다.
솔직히 말하면, 이 부분이 전체 프로젝트에서 가장 중요한 과정이었다고 생각합니다.
이유는 단순합니다. 운영 중인 시스템이었기 때문입니다. 아무리 코드를 깔끔하게 재작성해도, 기존 로직과 동일한 결과를 보장하지 못하면 의미가 없습니다. "리팩토링했더니 기획전 당일에 장애가 났다"는 상황은 절대 발생해서는 안 됐습니다. 기존 로직과 완전히 동일한 결과를 얻을 것이라는 확신, 이것이 코드를 한 줄이라도 바꾸기 위한 전제 조건이었습니다.
단위별로 로직을 정리할 때마다 테스트를 먼저 작성하고, 기존 로직의 입출력과 새 로직의 입출력이 정확히 일치하는지 검증하는 사이클을 반복했습니다.
정리하고 나니 실감한 것이 두 가지 있습니다.
첫째, 상당한 성능 개선이 가능했습니다. 계층 구조 깊숙이 묻혀있던 비효율적인 호출 패턴, 불필요한 반복 로직들이 정리되면서 자연스럽게 성능이 올라갔습니다.
둘째, 기존 코드에서 불필요하거나 중복된 로직이 절반 이상이었습니다. 10년 동안 여러 사람이 "혹시 몰라서" 남겨둔 코드, 이미 쓰이지 않는 조건 분기, 같은 역할을 하는데 각자 따로 구현된 로직들. 이것들을 걷어내고 나니 유지보수성이 대폭 향상된 것은 말할 것도 없습니다.
모든 로직 정리가 완료된 후, 마지막으로 한 작업이 있습니다. 다음 개발자를 위한 문서화입니다.
적용한 디자인 패턴의 의도와 구조를 다이어그램으로 정리하고, 새롭게 작성된 로직의 흐름을 시각화했습니다. 그리고 소스 코드 중간중간에 해당 로직의 맥락과 판단 근거를 주석과 문서로 남겼습니다. 이 단계에서도 AI에게 많은 도움을 받았습니다. 코드를 읽고 문서 초안을 뽑아내는 작업은 AI가 빠르게 처리하고, 저는 그 내용이 정확한지 검증하고 보완하는 데 집중할 수 있었습니다.
왜 이 작업에 공을 들였느냐 하면, 돌이켜보면 지금 제가 마주한 10년 레거시의 근본적인 문제가 "아무도 설명할 수 없는 코드"였기 때문입니다. 코드는 깔끔하게 정리했는데 문서가 없으면, 5년 후에 다른 누군가가 같은 고통을 겪게 됩니다. 그 악순환을 끊고 싶었습니다.
AI 활용에서 의외로 많은 분들이 간과하는 부분이 있습니다. 세션(대화 컨텍스트) 관리입니다.
하나의 세션에서 분석, 문서화, 리팩토링 방향 수립까지 전부 하려고 하면 대화가 길어질수록 AI의 응답 품질이 떨어집니다. 컨텍스트 윈도우의 물리적 한계도 있지만, 대화가 길어지면 초반의 맥락을 점점 잃어버리는 현상이 발생하기 때문입니다.
저는 다음과 같은 방식으로 세션을 나눴습니다.
세션 A: 전체 흐름 구조 파악 → 결과를 마크다운으로 문서화
세션 B: 문서화된 결과를 입력으로 제공 → 특정 모듈의 상세 로직 분석 → 다시 문서화
세션 C: 축적된 문서를 기반으로 API 규격 정리 → 문서화
세션 D: 정리된 문서들을 기반으로 새로운 아키텍처에 맞는 코드 설계 논의
각 세션의 산출물이 다음 세션의 입력이 되는 파이프라인 구조입니다. 이렇게 하면 AI가 항상 깨끗한 컨텍스트에서 출발하면서도, 이전 분석의 맥락은 문서를 통해 유지됩니다.
여기서 한 가지 분명히 해둘 부분이 있습니다. AI가 분석을 도와준다고 해서 개발자가 수동적으로 결과만 받아보면 되는 것은 아닙니다.
AI가 생성한 분석 결과를 검증하고, 맥락을 보정하고, 아키텍처적 판단을 내리는 것은 전적으로 개발자의 몫입니다.
예를 들어, 레거시 코드에서 API를 호출하는 방식 하나를 보더라도 — 경험 많은 개발자라면 공감하시겠지만 — 깔끔하게 추상화된 코드가 있는가 하면, 조건문 20개 안에 하드코딩된 URL이 박혀있는 코드도 있습니다. AI는 둘 다 "이것은 API 호출입니다"라고 분석하지만, 이 호출이 정상적인 패턴인지, 임시방편인지, 제거해도 되는 데드코드인지를 판단하는 것은 도메인과 히스토리를 이해하고 있는 개발자만이 할 수 있습니다.
결국 AI가 가져다주는 가치는 분석 속도의 가속이지, 판단의 대체가 아닙니다.
작은 단위로 쪼개기
전체 코드를 한 번에 던지면 AI도 길을 잃는다
Top-Down → Bottom-Up
전체 흐름을 먼저 잡고, 최하위 계층부터 역순으로 상세 분석
다이어그램으로 시각화
텍스트 분석만으로는 한계가 있다. AI로 초안을 빠르게 뽑고 검증
디자인 패턴 + 단계적 정리
전체 그림 위에서 패턴을 선정하고, 단위별로 정리와 검증을 반복
TDD는 선택이 아닌 필수
운영 중인 시스템의 리팩토링은 동일한 결과 보장이 전제 조건
다음 개발자를 위한 문서화
코드만 정리하고 문서가 없으면, 5년 후 같은 문제가 반복된다
세션 분리 + 문서화
하나의 세션에서 모든 것을 해결하려 하지 않는다
AI 산출물은 검증 대상
AI의 분석 결과를 맹신하지 않고 개발자가 반드시 검증
문서가 컨텍스트를 잇는다
마크다운 문서화가 세션 간 맥락 유지의 핵심
저는 그렇게 생각하지 않습니다.
이번 프로젝트를 돌이켜보면, AI가 해준 것은 분석, 문서화, 다이어그램 초안, 패턴 적용 보조 같은 작업들이었습니다. 하나하나가 분명히 가치 있는 도움이었지만, 아키텍처를 결정하고, 어떤 패턴이 이 비즈니스에 적합한지 판단하고, 테스트 전략을 세우고, 레거시 코드의 임시방편과 핵심 로직을 구별하는 것은 결국 개발자의 몫이었습니다.
오히려 AI의 진짜 가치는 다른 곳에 있다고 느꼈습니다.
많은 개발자들이 TDD와 문서화의 중요성을 알고 있습니다.
당연히 해야 한다는 것도 압니다.
하지만 현실은 어떻습니까. 일정의 압박 앞에서 테스트 코드 작성은 "나중에"로 밀리고, 문서화는 "시간 나면"으로 미뤄지다가 결국 생략됩니다. 그게 나쁜 개발자여서가 아닙니다. 현실적으로 시간이 부족했기 때문입니다.
AI는 바로 이 지점을 메워주고 있습니다.
테스트 코드 초안을 빠르게 생성하고,
코드를 읽어 문서 초안을 뽑아내고,
다이어그램을 그려주는 것.
개발자들이 "해야 하는 줄 알지만 현실적인 어려움 앞에서 타협할 수밖에 없었던 부분들"을 보완해 주는 역할입니다.
그래서 AI의 등장으로 공부할 필요가 사라졌느냐 하면, 저는 오히려 반대라고 생각합니다.
디자인 패턴을 모르면 AI에게 "이 로직에 적합한 패턴을 적용해 줘"라는 요청 자체를 할 수 없습니다.
클린 아키텍처를 이해하지 못하면 AI가 만들어준 코드가 원칙에 맞는지 검증할 수 없습니다.
더 많이 공부하고, 그 지식을 AI를 통해 더 빠르게 적용하는 것. 이것이 AI 시대에 개발자가 가져야 할 자세가 아닐까 생각해 봅니다.
긴 글 읽어주셔서 감사합니다.
앞으로도 현장에서 겪은 경험들을 계속 공유하겠습니다.