Rain Lag

아날로그 기술 부채 테라리움: 책상 위 작은 서식지로 최악의 레거시 시스템을 천천히 치유하기

기술 부채를 관리하는 실용적이면서도 유쾌한 비유를 탐구합니다. 레거시 시스템을 책상 위 작은 테라리움처럼 바라보며 관찰하고, 다듬고, 점진적 리팩터링·재사용 가능한 요구사항·모던 툴링으로 서서히 치유하는 방법을 다룹니다.

아날로그 기술 부채 테라리움: 책상 위 작은 서식지로 최악의 레거시 시스템을 천천히 치유하기

당신이 떠올리기만 해도 머리가 아픈 그 최악의 레거시 시스템을, 저주받은 코드 더미가 아니라 책상 위에 올려둔 작은 유리 테라리움이라고 상상해 보자.

그 안에는 뒤엉킨 덩굴(의존성), 흐릿하고 탁한 물(설정/환경 구성), 그리고 이제는 아무도 정확히 이해하지 못하는 몇몇 귀하고 연약한 식물들(비즈니스 규칙)이 들어 있다. 이 생태계를 밀어버리듯 갈아엎으면 뭔가 중요한 것도 함께 죽게 되고, 그렇다고 곰팡이가 벽을 타고 올라오는데도 괜찮은 척하며 방치할 수도 없다.

이게 바로 아날로그 기술 부채 테라리움이다. 제품 로드맵을 멈추지 않으면서도 기술 부채를 돌보고 관찰하고 서서히 치유하는 방법을 돕는 사고 모델이다. 공상적인 이야기가 아니라, 장수하는 시스템을 바라보고 기술 부채를 1급 시민으로 대하는 실질적인 관점이다.

이 글에서는 이 비유를 다음과 같은 구체적인 전략으로 풀어본다.

  • 기술 부채를 장기적인 유지보수 비용으로 이해하기
  • 부채를 눈에 보이고 추적 가능하게 만들기
  • 한 번에 갈아엎는 위험한 빅뱅 리라이트 대신 점진적 리팩터링 적용하기
  • 재사용 가능한 요구사항과 베스트 프랙티스로 새로운 부채를 예방하기
  • 모던 툴링과 클라우드 워크플로우를 활용해 대규모 리팩터링을 안전하게 수행하기

기술 부채, 정확히 뭐지? (피할 수 없는 토양)

기술 부채(Technical Debt)는 튼튼하고 잘 설계된 해법 대신, 빠르고 편한 해법을 택할 때 생기는 장기 유지보수 비용이다.

그 자체가 악은 아니다. 테라리움에서 일단 생태계가 버틸지 보려고 빨리 자라는 지피 식물을 먼저 심어 보는 것처럼, 제품 아이디어를 검증하기 위해서는 어쩔 수 없이 빨리 배포해야 할 때도 있다. 다만 이런 모든 지름길은 언젠가 잘라내거나 옮기거나 교체해야 할 새로운 종을 서식지에 추가하는 행위와 같다.

“나중에 고치자”는 결정이 시간이 지나면 결국 다음과 같은 형태로 돌아온다.

  • 건드리면 바로 깨지는 취약한 모듈
  • 세 개의 다른 서비스에 흩어져 중복된 로직
  • 이름부터 수상한 원오프(one-off) 설정 플래그들
  • 아무도 마이그레이션하고 싶어 하지 않는 DB 스키마

이 모든 것이 처음 빌린 "코드 대출"에 붙는 이자다. 방치할수록 이해·유지·변경 비용이 눈덩이처럼 불어난다.

핵심 개념: 기술 부채는 단순한 나쁜 코드가 아니라, 변경 비용을 높이는 모든 구조적 타협이다.


부채를 1급 시민으로 다루기 (테라리움의 병들에 라벨 붙이기)

방치된 테라리움이 망가지는 순간은 관찰을 멈췄을 때다. 기술 부채도 보이지 않을 때 같은 방식으로 당신을 배신한다.

기술 부채를 1급 시민으로 다룬다는 건 다음을 의미한다.

  1. 명시적으로 인정하기

    • 기능 개발과 분리된 전용 기술 부채 백로그를 만들고, 항목마다 구체적인 설명과 영향도를 적는다.
    • 문제에 이름을 붙인다. “레거시 문제들”보다는 “X와 Y 모듈 간 강한 결합”이 훨씬 낫다.
  2. 시간에 따라 추적하기

    • 티켓에 성능, 아키텍처, 테스트 커버리지, 관측 가능성(Observability) 등 부채 카테고리 태그를 붙인다.
    • 가능하다면 영향도를 수치로 측정한다: 인시던트 발생 빈도, 온보딩에 걸리는 시간, 변경 구현 리드타임 등.
  3. 의도적인 상환 계획 세우기

    • 각 스프린트의 10–20%처럼 정기적인 용량을 부채 상환에 할당한다.
    • 상환을 비즈니스 결과에 연결한다. “정리하기”가 아니라 “인시던트 발생량 30% 감소”처럼 목표를 잡는다.

이것은 테라리움 속에 작은 깃발과 라벨을 꽂는 것과 같다. 어떤 식물이 침습성인지, 어떤 식물이 더 많은 빛이 필요한지, 어떤 뿌리 시스템이 다른 걸 조이고 있는지를 표시하는 것이다. 문제가 보이고 이름이 붙으면 관리할 수 있다.


점진적 리팩터링: 밀어버리기 말고 가지치기

테라리움이 너무 우거졌다고 해서 유리를 깨고 전부 갈아엎지는 않는다. 가지를 하나씩 치고, 화분을 옮기고, 균형을 다시 맞춘다.

**점진적 리팩터링(Incremental Refactoring)**도 같은 사고방식이다.

기존 코드를 행동은 그대로 유지한 채, 설계와 구조를 개선하도록 재구성하는 것.

모든 기능 개발을 멈추고 영웅적인 리라이트에 올인했다가 실패하는 대신 다음과 같이 접근한다.

  • 결합도가 높은 모듈 하나를 뽑아서 더 명확한 인터페이스로 분리한다.
  • 1,000줄짜리 클래스를 여러 개의 작고 집중된 컴포넌트로 나눈다.
  • 직접 만든 유틸리티를 표준 라이브러리나 검증된 오픈소스로 교체한다.
  • 코드를 건드리기 전에 가장 위험한 플로우부터 테스트를 추가한다.

실무에서 자주 쓰이는 패턴은 다음과 같다.

  • 스트랭글러 피그(Strangler Fig) 패턴: 레거시 컴포넌트를 새 인터페이스로 감싸고, 트래픽을 구버전에서 신버전으로 점진적으로 우회시킨다.
  • 보이스카웃 룰(Boy Scout Rule): 파일을 수정할 때마다, 처음보다 조금이라도 더 나은 상태로 돌려놓는다(이름 정리, 중복 제거, 작은 추상화 등).
  • 리팩터링 예산(Refactor Budget): 대규모 "정리만 하는" 스프린트를 잡는 대신, 이미 진행 중인 기능 작업에 작은 리팩터링을 끼워 넣는다.

이런 작은 안전한 변화들이 쌓이면, 제품 개발을 멈추지 않고도 부서지기 쉬운 레거시 시스템을 이해 가능하고 유지보수 가능한 시스템으로 바꿔갈 수 있다.


재사용 가능한 요구사항: 개별 식물이 아니라 서식지 설계하기

많은 레거시 악몽은 나쁜 코드에서가 아니라, 즉흥적이고 일회성인 요구사항에서 시작한다.

“X 고객만 예외 처리 하나 더 넣어주세요.”
“일단 플래그는 하드코딩해 두고, 나중에 정리하죠.”
“서비스 A 동작을 복사하되, B는 좀 다르게 해주세요.”

**재사용 가능한 요구사항 저장소(Requirements Repository)**를 만들면 개별 식물이 아니라 전체 생태계를 설계하는 시야를 갖게 된다.

  • 요구사항 템플릿 중앙화
    인증, 로깅, 감사(Audit) 추적, 에러 처리, SLA, 피처 플래그, 데이터 보존 정책처럼 반복되는 패턴을 모아둔다.

  • 표준화와 검증
    매번 새로 쓰지 말고, 팀이 재사용·확장할 수 있는 체크리스트와 라이브 문서(living document)를 운영한다.

  • 요구사항과 구현 연결
    비즈니스 규칙과 이를 구현한 코드·테스트 사이의 추적 가능성(Traceability)을 유지해서, 나중에 변경할 때도 추측이 아니라 이해에서 출발하도록 한다.

결과적으로 유지할 수 없는 특수 케이스가 줄어들고, 시스템 전반에 더 일관되고 예측 가능한 동작이 늘어난다.


베스트 프랙티스: 테라리움의 일상 관리

기술 부채는 한 번 "싹 정리"한다고 끝나지 않는다. 테라리움처럼 주기적인 관리가 필요하다.

시스템이 다시 정글로 변하지 않게 막아주는 실천 방법은 다음과 같다.

  1. 정기적인 코드 리뷰(Code Review)

    • 가독성, 테스트 커버리지, 아키텍처에 대한 기준을 리뷰를 통해 지킨다.
    • 새로 생기는 부채를 리뷰에서 잡아낸다: 새는 추상화, 복붙 로직, God Object 같은 것들.
  2. 작고 지속적인 리팩터링

    • 리팩터링을 특별 프로젝트가 아니라, 기능 개발의 당연한 일부로 취급한다.
    • 고객이 바로 보지 못하더라도, 미래 유지보수 비용을 줄이는 개선에 대해 엔지니어를 인정하고 보상한다.
  3. 아키텍처 가이드라인

    • 간단하지만 중요한 규칙을 문서화하고 전파한다. 예: “UI 레이어는 DB를 직접 호출하지 않는다”, “이벤트는 반드시 버전 관리한다”, “새로운 포인트 투 포인트(Point‑to‑Point) 통합은 이벤트 버스 없이는 금지” 등.
    • 가이드는 살아 있는 문서이자 최소한으로 유지해야 한다. 규정이 너무 많으면 사람들은 우회로를 찾기 시작한다.

이런 습관들이, 잠깐 눈 돌린 사이에 테라리움이 다시 혼돈으로 회귀하는 일을 막아준다.


클라우드 기반 도구: 필요할 때만 빌려 쓰는 햇빛과 물

대규모 리팩터링이 두려운 이유는, 비싸고 위험해 보이기 때문이다. 클라우드 기반 도구는 이런 작업을 더 저렴하고 예측 가능하게 만들어 준다.

항상 켜져 있는 대형 서버를 따로 마련해두고 마이그레이션이나 분석을 돌릴 필요 없이, 다음과 같이 할 수 있다.

  • 대규모 테스트와 리팩터링을 수행하기 위해 에페메럴(Ephemeral) 환경을 일시적으로 띄운다.
  • **온디맨드 컴퓨트(On‑Demand Compute)**를 사용해 정적 분석, 의존성 맵핑, 코드 변환을 수행한다.
  • 리팩터링 작업 중 실제로 사용한 컴퓨팅 리소스에 대해서만 비용을 지불하고, 놀고 있는 용량에는 돈을 쓰지 않는다.

이를 통해 가능한 예시는 다음과 같다.

  • 실제 사용자에게 영향을 주지 않고, 프로덕션과 유사한 데이터셋에 자동 마이그레이션 스크립트를 실행한다.
  • 리팩터링 전후로 대규모 성능 벤치마크와 회귀 테스트를 수행해 기준선을 확보한다.
  • 카나리 릴리스, 블루–그린 배포(Blue‑Green Deployment) 등으로 구버전과 신버전 컴포넌트 사이를 안전하게 전환한다.

이것은 마치 테라리움에 잠깐 다른 기후를 시뮬레이션해 보는 것과 같다. 필요할 때만 빛을 더 주고, 물을 더 주고, 공기를 더 순환시킨다.


모던 툴링: 손으로 잡초 뽑기에서 자동 정원 관리로

과거의 레거시 리팩터링은 파일을 하나씩 열어 문자열을 검색하고, 참조를 손으로 따라다니며, 혹시 뭔가 놓치지 않았기를 기도하는 작업에 가까웠다. 그러다 보면 어느 영역은 건드리기 무서운 구역이 되어버린다.

모던 개발자 툴링은 이 과정을 더 안전하고 반복 가능한 프로세스로 바꿔 준다.

  • 의존성 시각화(Dependency Visualization)
    서비스·모듈·패키지 간 실제 의존성 그래프를 그려보고, 코어 컴포넌트를 바꿀 때 어디가 깨질지 이해한다.

  • 자동 import 및 설정 업데이트 도구
    클래스를 옮기거나 API를 변경했을 때, import나 wiring, 설정 참조를 자동으로 업데이트해 주는 도구는 리스크를 크게 줄여준다.

  • 리팩터링 어시스턴트와 린터(Linter)
    IDE와 정적 분석 도구는 추출(Extract), 죽은 코드 제거, 안전한 리네임 같은 리팩터링을 제안하고 도와준다.

  • 대규모 검색·치환(Search + Replace at Scale)
    AST 기반 코드모드(Codemod) 같은 도구로 리포지토리 전체에 일관된 변경을 적용할 수 있어, 사람 손으로 하나씩 수정하는 위험을 줄인다.

이 도구들을 활용하면 테라리움 관리가 체계적인 작업이 된다. 수천 개 파일에서 공통 패턴을 한 번에 정리할 수 있고, 더 이상 잡초를 한 포기씩 뽑는 기분으로 일하지 않아도 된다.


모두 엮어보기: 서식지 치유, 어디서부터 시작할까?

이미 레거시 시스템이 늪지처럼 느껴진다면, 다음과 같은 현실적인 출발점을 제안한다.

  1. 서식지 지도 그리기

    • 가장 아픈 레거시 시스템 3–5개를 리스트업하고, 각자의 고통 포인트(인시던트, 변경 리드타임, 온보딩 난이도 등)를 정리한다.
  2. 부채를 보이게 만들기

    • 기술 부채 백로그를 만든다. 가장 심각한 구조적 문제에 이름을 붙이고, 설명을 남긴다.
  3. 리팩터링 용량 보호하기

    • 팀 용량의 일정 비율을 작고 지속적인 리팩터링에 고정적으로 배정한다.
  4. 요구사항 저장소 세우기

    • 상대적으로 건강한 시스템에서 공통 패턴을 뽑아내어, 재사용 가능한 요구사항으로 표준화하기 시작한다.
  5. 툴링 도입·업그레이드

    • 의존성 시각화, 자동 리팩터링 도구, 클라우드 기반 테스트 환경 등에 투자한다.
  6. 진척을 측정하고, 눈에 띄게 축하하기

    • 인시던트 감소, 변경 리드타임 단축, 온보딩 스토리 단순화 등을 지표로 추적하고, 팀이 체감할 수 있게 공유한다.

결론: 손 대기 무서운 시스템이 아닌, 만져볼 수 있는 테라리움

레거시 시스템이 완벽한 정원처럼 변신할 일은 아마 없을 것이다. 그게 목표일 필요도 없다.

목표는, 두려움 없이 바꿀 수 있을 만큼 잘 이해된 살아 있는 서식지를 만드는 것이다. 그 안에서는

  • 기술 부채가 눈에 보이고, 이름이 붙어 있고, 관리되고 있으며,
  • 리팩터링이 10년에 한 번 벌어지는 위기가 아니라 매일의 일과이고,
  • 요구사항이 매번 즉흥적으로 나오지 않고 재사용 가능하고 일관되며,
  • 클라우드 리소스와 모던 툴링이 변화를 비용 효율적이고 반복 가능하게 만들어 준다.

당신의 코드베이스를 책상 위 아날로그 기술 부채 테라리움이라고 생각해 보자. 관찰하고, 돌보고, 작은 단위로 의도적으로 가지치기하라. 몇 달, 몇 년이 지나면 목을 조르던 덩굴은 느슨해지고, 공기는 맑아지며, 한때는 손도 못 대겠던 영역이 건강하게 진화하는 생태계의 일부로 편입될 것이다.

레거시 시스템에서 도망칠 필요는 없다. 치유하면 된다. 가지 하나하나를, 조심스럽게 잘라내고 다듬어 가면서.

아날로그 기술 부채 테라리움: 책상 위 작은 서식지로 최악의 레거시 시스템을 천천히 치유하기 | Rain Lag