아날로그 디버깅 지도 키트: 길 잃지 않고 레거시 코드를 탐험하는 손그림 지도
손으로 그린 지도, 심층 아키텍처 다이어그램, 가벼운 문서를 활용해 혼란스러운 레거시 시스템을 개발자가 탐색 가능한 영역으로 바꾸는 방법을 다룹니다.
아날로그 디버깅 지도 키트: 길 잃지 않고 레거시 코드를 탐험하는 손그림 지도
레거시 코드베이스를 열어 보는 순간, 영혼이 빠져나가는 기분을 느껴본 적이 있다면 혼자가 아닙니다.
수많은 패치 레이어, 반쯤만 마이그레이션된 프레임워크, 실종된 문서, 그리고 이제는 성인이 된 “임시” 핵(hack)까지—이 모든 것이 디버깅을 공학이라기보다 폐도시 탐험에 가깝게 만듭니다.
그런데 대부분의 팀은 이런 난장판을, 깔끔하고 잘 정리된 시스템을 전제로 만든 도구로 탐색하려 합니다. 예를 들면:
- 형식적인 UML 다이어그램
- 완벽하게 층이 나뉜 아키텍처
- 실제 사용 현실은 반영하지 못한 자동 생성 문서
더 나은 접근법이 있습니다. 디버깅을 지도 제작(cartography) 으로 보는 겁니다.
이 글에서는 아날로그 디버깅 지도 키트(Analog Debugging Cartography Kit) 라는 아이디어를 소개합니다. 레거시 코드베이스에서 길을 잃지 않고—그리고 아무도 이해하지 못하지만 모두가 의존하는 그 한 군데를 실수로 부수지 않도록—탐색을 도와주는 가볍고 유연한 지도, 메모, 도구의 모음입니다.
왜 레거시 세계에서는 완벽한 UML보다 손그림 지도가 더 강력한가
고전적인 UML이나 엄격한 형식의 다이어그램은, 대부분의 레거시 시스템에는 거의 존재하지 않는 수준의 아키텍처 위생(architectural hygiene)을 전제로 합니다. 예를 들어 15년 된 모놀리식(monolith) 시스템에서는:
- 논리 계층이 서로 뒤섞여 있고,
- 모듈들이 설계 의도와 상관없이 직접 서로 호출하며,
- 2013년에 만든 “아키텍처” 슬라이드는 거의 소설에 가깝습니다.
이런 현실에서는 손그림이나 비공식 다이어그램이 빛을 발합니다. 이들은 다음을 최적화하기 때문입니다.
- 속도 – 모델링 도구보다 펜이나 펜슬이 훨씬 빠릅니다.
- 정직함 – “이상한 것들”을 그대로 적을 수 있습니다. (예: “hot path”, “mystery queue”, “이 잡(jobs)은 건들지 말 것”)
- 집중 – 지금 조사에 필요한 것만 그리면 됩니다.
정답 같은 “정식 아키텍처 다이어그램”을 목표로 하기보다, 스케치를 현장에서의 관찰 기록(field notes) 이라고 생각해 보세요.
- 화살표: 데이터 흐름
- 박스: 주요 모듈이나 서비스
- 구불구불한 선과 메모: “여긴 위험 지대(here be dragons)”
이 지도는 예쁠 필요 없습니다. 대신 쓸모가 있어야 합니다.
시각적 지도: 코드베이스를 ‘보이는’ 지형으로 바꾸기
큰 레거시 시스템이 압도적으로 느껴지는 이유는, 파일·폴더·함수 호출을 머릿속에서 조합하기 전까지는 시스템이 눈에 보이지 않기 때문입니다. 시각적 지도는 이 보이지 않는 지형을 손에 잡히는 형태로 바꿔 줍니다.
당신의 지도 키트에 포함할 수 있는 실용적인 지도 유형은 다음과 같습니다.
1. 고도 지도(Topographic Map) 수준의 상위 개요
목표: 시스템의 주요 “지역”이 어떻게 나뉘는지 파악하기.
포함할 것:
- 주요 서비스 / 바운디드 컨텍스트(bounded context) / 큰 모듈들
- 핵심 데이터베이스, 캐시, 외부 의존성
- 주요 통신 채널 (HTTP, RPC, 메시지 큐 등)
이걸 시스템의 “지하철 노선도(metro map)” 라고 생각해도 좋습니다. 모든 골목길을 보여주지는 않지만, 전체를 이해하고 방향을 잡는 데 필요한 노선과 역은 모두 들어 있습니다.
2. 핵심 플로우를 위한 여정 지도(Journey Map)
로그인, 결제, 리포트 생성, 데이터 가져오기(import), 빌링 같은 진짜 중요한 플로우를 고르세요.
그리고 한 단계씩 그려 봅니다.
- 요청이 어디서 들어오는지 (UI / API / 게이트웨이)
- 어떤 모듈이 어떤 비즈니스 로직을 처리하는지
- 인증, 로깅, 피처 플래그 같은 횡단 관심사(cross-cutting concern)가 어디서 개입하는지
- 데이터가 어디서 읽히고, 어디에 쓰이는지
이런 지도는 새로 합류한 개발자가 “대체 어디서부터 봐야 하지?” 하는 마비 상태에 빠지지 않게 도와줍니다.
3. 로컬 동네 지도(Local Neighborhood Map)
특정 버그를 디버깅할 때는, 더 작고 집중된 지도를 만듭니다.
- 지금 보고 있는 핵심 클래스나 함수
- 그와 직접적으로 상호작용하는 중요한 협력자들 (의존성, DI로 주입된 서비스 등)
- 주요 설정값이나 환경 변수 등, 동작에 영향을 주는 것들
이 지도들은 일시적이고 전술적인 도구에 가깝지만, 시간이 지나면 쌓여서 시스템 전체를 더 잘 보여주는 풍부한 그림을 구성하게 됩니다.
심층 아키텍처 다이어그램: 진짜 의존성을 들춰내기
빠른 스케치 외에도, 핵심 영역에 대해서는 심층 아키텍처 다이어그램(deep architecture diagram) 을 만들어 둘 가치가 있습니다. 이 다이어그램은 상위 지도보다 한 단계 깊게 들어가서 다음을 밝히는 데 초점을 둡니다.
- 어떤 모듈이 어떤 모듈에 의존하는지
- 어디에 강한 결합과 숨은 부작용이 있는지
- “하중을 버티는 벽(load‑bearing wall)”이라서 함부로 건드리면 안 되는 부분이 어디인지
심층 아키텍처 다이어그램에 담아야 할 것
집중해야 할 대상:
- 모듈과 계층 – UI, 서비스, 도메인, 인프라스트럭처, 통합(Integration) 등
- 방향성 있는 의존성 – 누가 누구를 호출하는지, 데이터는 어느 방향으로 흐르는지
- 크리티컬 패스 – 성능상 또는 비즈니스상 핵심 로직이 어디에 있는지
- 공용 유틸리티 – 로깅, 설정, 검증 등의 공통 모듈이 어떻게 연결돼 있는지
모든 클래스를 넣을 필요는 없습니다. 핵심 질문 하나만 답할 수 있으면 됩니다.
“X를 바꾸면, 또 어디가 같이 망가질 가능성이 높은가?”
리팩터링을 할 때 이런 다이어그램은 특히 유용합니다. 겉보기엔 간단해 보이는 변경이 실제로는 시스템 절반을 가로지르고 있다는 사실을 드러내 주기 때문입니다.
‘접착제 코드’ 문서화: 보이지 않는 아키텍처
대부분의 레거시 시스템에서 진짜 아키텍처는 “접착제 코드(glue code)” 에 숨어 있습니다.
예를 들면:
- 의존성 주입과 객체 연결부
- 프레임워크 설정과 부트스트랩 코드
- 이벤트 등록, 파이프라인 구성, 미들웨어 체인
- 피처 플래그 로직과 분기 경로
이 접착제 코드는 잘 문서화되어 있지 않은 경우가 많지만, 시스템에는 치명적으로 중요합니다.
그래서 지도 키트에는 다이어그램 옆에 붙일 짧고 날카로운 텍스트 메모 도 포함되어야 합니다.
- "Service A가 Service B에 의존하는 건 순수하게 레거시 사유 X 때문이다. 새로운 코드는 여기에 호출을 추가하지 말 것."
- "이 잡(job)은 매일 밤 돌아가며 누락된 데이터를 보정한다. 삭제하면 리포팅 데이터가 조용히 망가진다."
- "인증 경로가 두 개 있다: 쿠키 기반(구 방식)과 토큰 기반(신 방식). 둘 다 아직 사용 중."
이 메모는 다음처럼 관리하는 것이 좋습니다.
- 코드 가까이에 두기 (모듈 폴더의 README, 짧은 Markdown, ADR 등)
- 다이어그램에서 링크 걸기 (URL, 파일명, Confluence 페이지 등)
그림과 함께 놓인 이런 짧은 내러티브가 시스템의 의도와, 우연히 생긴 복잡성을 새로 온 사람에게 훨씬 더 명확하게 보여 줍니다.
시스템을 몸에 익히기: 더 빠른 디버깅을 위한 멘탈 모델
목표는 지도를 그리는 것에 그치지 않고, 그 지형을 내면화 해서 디버깅을 더 빠르고 덜 위험하게 만드는 것입니다.
모든 것을 외울 필요는 없습니다. 대신 다음에 집중하세요.
- 핵심 플로우 – 로그인, 결제, 데이터 인입(ingestion), 빌링, 리포팅 등
- 전형적인 코딩 패턴 – 에러 처리 방식, 서비스 주입 방식, 설정 접근 방식
- 프로젝트의 관용구와 규칙 – 네이밍 컨벤션, 폴더 구조, 공통 베이스 클래스, 테스트 전략
실천 방법 예시:
- 버그를 고친 뒤에는 다이어그램을 업데이트하거나, 모듈 README에 작은 지도를 하나 추가합니다.
- 개인용 “현장 노트(field notebook)”를 만듭니다. (디지털이든 종이든 상관없음)
- 겪었던 함정들
- 예상 밖의 코드 경로
- 이상한 레거시 결정과 그 이유
- 주기적으로 노트를 정리하고 줄입니다. 작고 관련성 높은 것만 남기세요.
시간이 지나면 머릿속에 일종의 오버레이 지도가 생깁니다. 무언가 깨졌을 때, 어디를 먼저 봐야 할지, 무엇을 조심해야 할지에 대한 직관이 훨씬 예리해집니다.
내비게이션 키트 조립하기: 도구 + 문서 + 다이어그램의 결합
디버깅 환경 전체를 내비게이션 키트라고 생각해 보세요. 서로 상관없는 도구 더미가 아니라요.
하나의 탄탄한 키트는 다음을 포함할 수 있습니다.
- 아날로그 도구
- 스케치를 위한 노트북이나 태블릿
- 위험 구역이나 열린 질문을 표시하는 포스트잇
- 다이어그램 도구
- 빠른 아키텍처 맵을 위한 가벼운 툴 (Excalidraw, Miro, draw.io, tldraw 등)
- 화이트보드 세션을 찍어 레포나 위키에 저장한 스크린샷
- 문서 앵커(Doc Anchors)
- 핵심 다이어그램과 노트를 모아두고 링크하는 최상위
SYSTEM_MAP.md - 모듈 수준의 짧은 README (역할과 진입 지점 설명)
- 주요 설계 결정을 기록하는 ADR(Architecture Decision Record)
- 핵심 다이어그램과 노트를 모아두고 링크하는 최상위
- 코드 내비게이션 지원
- 언어 인식 IDE 검색, 호출 계층(call hierarchy) 뷰, goto‑definition
- 멘탈 맵을 검증하는 정적 분석 도구나 의존성 그래프 도구
중요한 것은 통합성입니다.
- 다이어그램은 코드로 이어져야 하고,
- 문서는 다이어그램을 참조해야 하며,
- 도구는 당신이 그린 지도를 검증하거나 업데이트하는 데 도움을 줘야 합니다.
이것들이 함께 돌아가기 시작하면, 시스템은 더 이상 정글이 아니라, 시간이 지날수록 하나씩 배워 가는 도시처럼 느껴집니다.
즉흥 디버깅에서 지도 기반 탐험으로
많은 팀이 레거시 시스템 디버깅을 일종의 예술처럼 다룹니다. 경험 많은 엔지니어를 버그에 투입하고, 언젠가 해결해 주길 기대하는 식입니다.
여기에 체계적인 지도 기반(map‑driven) 실천을 도입하면, 이 과정을 보다 훈련된 탐험(disciplined exploration) 으로 바꿀 수 있습니다.
- 먼저 상위 지도로 시작합니다. 이 버그는 시스템의 어느 지역에 있을 가능성이 높은가?
- 이어서 여정 지도를 추가합니다. 실패한 요청이나 플로우를 진입부터 종료까지 따라가 봅니다.
- 로컬 동네 지도를 만들면서, 인스트루멘테이션을 추가하고 코드를 따라가며 배운 것들을 그립니다.
- 마지막으로, 발견한 사실과 결정 사항을 짧은 텍스트로 남깁니다.
무엇을 발견했고, 무엇을 바꿨으며, 어디가 여전히 불안해 보이는지.
시간이 지나면 조직 차원에서 다음을 얻게 됩니다.
- 시스템에 대한 공유된 시각 언어
- 신규 개발자의 온보딩 속도 향상
- “무서운” 코드 영역을 건드릴 때의 리스크 감소
이제 더 이상 “그냥 버그를 고치는” 수준이 아닙니다. 당신은 지도를 그리고, 미지의 영역을 개척하고 있습니다.
결론: 먼저 그려라, 리팩터링은 그다음
레거시 시스템이 어려운 이유는 단지 오래되었기 때문이 아니라, 제대로 된 지도가 없기 때문입니다.
보이지 않는 것을 이해할 수 없고, 이해하지 못하는 것은 리팩터링할 수 없습니다.
아날로그 디버깅 지도 키트—손그림 지도, 심층 아키텍처 다이어그램, 접착제 코드 메모, 그리고 잘 엮인 도구 모음—는 다음을 가능하게 해 줍니다.
- 혼란스러운 아키텍처를 탐색 가능한 지형으로 바꾸고,
- 새로운 개발자를 과부하 없이 온보딩하며,
- 디버깅을 신비한 예술이 아니라, 반복 가능하고 가르칠 수 있는 기술로 만드는 것.
다음에 무시무시한 레거시 레포지토리를 열게 되면, 바로 코드부터 파고들고 싶은 충동을 잠시 참아 보세요.
펜을 드세요.
먼저 지도를 그리세요.