Maintenance & Tech Debt
1. **Stage 1: Fundamentals (Weight: 1)** * Maintenance Types and Software Evolution Laws. 2. **Stage 2: Quantification (Weight: 2)** * Tech Debt Me...
Article
M
Me
hyunyoun's Blog
software-engineering-devopssoftware-engineeringdev-opsmaintenancetech-debtreliabilityobservabilitytechnical-debt10 min read
1. Overview
유지보수 및 기술 부채(Maintenance & Tech Debt, MTD)는 세상에 배포되어 작동하기 시작한 소프트웨어가 세월과 비즈니스 변화에 부딪혀 어떻게 서서히 늙어가고, 부패하며, 다시 현대화(Modernization)되는지를 다루는 공학적 생명 연장의 학문입니다.
출시된 소프트웨어는 버려진 자동차처럼 썩어가는 것이 아니라(Software Aging), 매일매일 들어오는 요구사항 수정 때문에 스파게티처럼 엉키며 망가집니다. 학습자는 이 지연 비용을 워드 커닝햄의 **기술 부채(Technical Debt)**라는 위대한 메타포로 이해합니다. "일단 굴러가게" 짠 코드가 어떻게 이자를 불려 결국 개발 속도를 0으로 수렴하게 만드는지 그 파산 과정을 정량적으로 분석하고, 코드 스멜(Code Smell)을 제거하는 리팩토링과 교살자 무화과(Strangler Fig) 패턴을 통해 거대한 레거시 시스템의 심장을 멈추지 않고 수술하는 아키텍트의 수리 역학을 갖춥니다.
2. Scope & Boundaries
In-Scope
- 소프트웨어 진화의 법칙 (Software Evolution): 리먼의 법칙(Lehman's Laws), 유지보수의 4대 유형(교정적, 적응적, 완전화, 예방적).
- 기술 부채의 정량화 (Technical Debt): 무지한 부채 vs 신중한 부채, 기술 부채 비율(Technical Debt Ratio, TDR) 및 이자(Cost of Delay) 측정 물리.
- 리팩토링 메커니즘 (Refactoring Mechanics): 코드 스멜(Code Smell) 감지, 구조는 개선하되 외부 동작은 유지하는 릴레이 테스트 기법.
- 레거시 현대화 (Legacy Modernization): 리플랫포밍(Replatforming), API 래핑(Wrapping), Strangler Fig Pattern을 이용한 점진적 마이그레이션.
Out-of-Scope
- 새로운 언어의 문법 최적화 공부: Python 2를 Python 3로 올리는 단순 문법 변환 05-02. FPL 영역으로 위임.
- 기존 인프라를 클라우드로 통째로 옮기기 (Lift and Shift): 애플리케이션 코드는 건드리지 않고 AWS VM으로만 옮기는 작업 09-05. DevOps 영역으로 위임.
Boundaries
- MTD vs. QA (09-04): QA(09-04)가 '코드가 버그 없이 명세대로 동작하는가'를 확인하는 것이라면, MTD는 동작은 멀쩡히 잘 되더라도 '코드가 너무 지저분해서 다음 주에 새 기능을 넣을 때 회사가 망할 확률이 얼마인가'를 측정하는 내부 구조의 경제학입니다.
3. Counterexample
- "버그 수정이 곧 유지보수"라는 오해 (Maintenance Fallacy): 유지보수 기간을 단순히 고객이 찾아낸 에러를 고치는(Corrective) 기간으로만 생각하는 주니어의 시각. 실제 소프트웨어 유지보수 예산의 70% 이상은 에러 수정이 아니라, 운영체제나 브라우저가 업그레이드되어서 코드를 맞추거나(적응적), 속도를 개선하고 코드를 예쁘게 가다듬는 작업(완전화, 예방적)에 쓰입니다. 유지보수는 '에러 처리'가 아니라 '환경에 대한 진화'입니다.
- 기능 개발 멈추고 한 달간 리팩토링만 하기 (Big Bang Refactoring Fallacy): 기술 부채가 쌓였다고 기획팀에게 "이번 달은 새 기능 출시 못 합니다. 코드 좀 뜯어고칠게요"라고 선언하는 행위. 이는 비즈니스와 엔지니어링의 타협점을 무시한 폭력입니다. 진정한 리팩토링 역학은 보이스카우트 규칙(Boy Scout Rule: 떠날 때는 머물 때보다 더 깨끗하게)을 적용하여, 새 기능을 짤 때 그 기능과 맞닿은 10%의 코드만 매일매일 조금씩 개선하는 점진적 상환(Repayment)의 원리를 따릅니다.
4. Prerequisites
- 아키텍처 및 설계 기초 (Basic): 코드가 어떻게 꼬여 있는지(강결합) 알려면 SOLID 원칙과 아키텍처 패턴의 기초를 알아야 합니다. (09-03. SAD)
- 테스트 자동화 (Recommended): 리팩토링 중 기존 기능이 깨지지 않았는지 1초 만에 확인해 줄 단위 테스트 파이프라인이 없으면 수술(리팩토링) 자체가 불가능합니다. (09-04. TQA)
5. Learning Map
6. Learning Topics
Basic
Core Topic 01: 소프트웨어 진화와 유지보수 유형 (Software Evolution)
- Why to Learn: 프로그램은 완성되는 순간 죽어가는 역설을 인지하고, 배포 이후에 더 많은 공학적 노력(비용의 60% 이상)이 들어감을 계획하기 위함입니다.
- What to Learn:
- Concepts: 리먼(Lehman)의 소프트웨어 진화 법칙 (계속적 변경, 복잡도 증가 등).
- Skills: 4대 유지보수 유형 분별 (Corrective-수정형, Adaptive-적응형, Perfective-완전형, Preventive-예방형).
- Tools: 이슈 트래커 (이슈 레이블링).
- Trade-offs: 요구사항 변경을 적극 수용하는 유연한 태도 vs 잦은 변경으로 인해 시스템 전체의 구조적 무결성(Structural Integrity)이 서서히 붕괴하는 엔트로피 증가 현상.
- How to Learn:
- 1단계: Jira 등에 쌓여있는 지난 1년간의 과거 티켓들을 분석하여, "DB 버전 업그레이드 지원", "속도 20% 개선", "눌리지 않는 버튼 수정" 등의 작업이 4가지 유지보수 중 각각 어디에 해당하는지 파이(Pie) 차트로 분류합니다.
- 2단계: 리먼의 '복잡도 증가의 법칙'을 실증하기 위해, 처음 설계 문서의 클래스 다이어그램과 2년 뒤 땜질이 반복된 현재 코드의 구조를 비교하여 얼마나 결합도(Coupling)가 거미줄처럼 엉켰는지 도식화합니다.
- Implement: 특정 레거시 프로젝트의 최근 6개월간 커밋 로그를 분석하여, 유지보수 활동 비율(수정, 적응, 완전, 예방)을 정량화하고 향후 방어적 예산 편성을 제안하는 분석 리포트.
Recommended
Core Topic 02: 기술 부채의 메타포와 정량화 (Tech Debt Quantification)
- Why to Learn: 경영진에게 "코드를 고쳐야 하니 시간을 달라"고 설득하기 위해, 보이지 않는 코드 품질을 보이는 '돈(부채와 이자)'으로 치환하기 위해서입니다.
- What to Learn:
- Concepts: 워드 커닝햄의 기술 부채(Technical Debt) 사분면 (무지한/신중한, 고의적/비고의적 부채), 복리의 이자(Cost of Delay).
- Skills: SQALE(Software Quality Assessment based on Lifecycle Expectations) 방법론, 기술 부채 비율(TDR) 측정.
- Tools: SonarQube 정적 코드 분석기.
- Trade-offs: 당장 이번 달에 제품을 내놓기 위해 복사 붙여넣기로 하드코딩을 하는 것(원금 대출) vs 1년 뒤 새로운 기능을 붙일 때 1주일이면 할 일을 3달 동안 뜯어고치게 되는 비용(이자 폭탄).
- How to Learn:
- 1단계: 프로젝트에 SonarQube를 연동하고, "중복 코드 100줄, 복잡도 초과 함수 5개" 등으로 뜬 알림을 보고, 도구가 제시하는 "이 부채를 갚기 위해 필요한 예상 리팩토링 시간(예: 3 Days)"의 의미를 해석합니다.
- 2단계: '무지해서 발생한 부채(디자인 패턴을 몰라서 엉망으로 짬)'와 '전략적인 부채(투자를 받기 위해 1주일 만에 날림으로 MVP를 만듦)'의 비즈니스적 차이를 토론하며 부채가 항상 나쁜 것만은 아님을 이해합니다.
- Implement: 팀 내 소스 코드 저장소에 정적 분석 도구를 붙이고, 전체 프로젝트의 TDR(기술 부채 비율)을 측정한 뒤 우선적으로 청산해야 할 악성 부채 Top 3 목록을 뽑아낸 청산 계획서.
Practical
Core Topic 03: 리팩토링 역학과 릴레이 테스트 (Refactoring Mechanics)
- Why to Learn: 썩어가는 코드를 발견했을 때 겉으로 드러나는 동작(API 스펙)은 1바이트도 건드리지 않고, 내부의 더러운 내장(구조)만 아름답게 들어내는 수술 기법을 익히기 위함입니다.
- What to Learn:
- Concepts: 코드 스멜(Code Smell: 긴 함수, 거대한 클래스, 데이터 클럼프 등), 보이스카우트 규칙.
- Skills: 마틴 파울러의 리팩토링 기법 (메서드 추출, 다형성으로 조건문 대체, 변수 캡슐화), 불변성(Invariant) 테스트 보존.
- Tools: IDE 자동 리팩토링 도구, 단위 테스트 프레임워크.
- Trade-offs: 더 깨끗한 구조를 위해 매번 메서드를 분리하고 클래스를 쪼개는 미학 vs 오버엔지니어링으로 인해 코드가 수십 개의 파일로 파편화되어 읽기 더 힘들어지는 추상화의 함정.
- How to Learn:
- 1단계: 1,000줄짜리
GodClass.java에서 '스위치(switch)문'이 덕지덕지 붙은 냄새(Smell)를 찾고, 이를 인터페이스와 다형성(Polymorphism)을 활용한 전략(Strategy) 패턴으로 쪼개어 리팩토링하는 실습을 진행합니다. - 2단계: 리팩토링 전과 후의 코드가 정확히 동일하게 작동함을 증명하기 위해, 기존에 작성된 100개의 단위 테스트(Unit Test)를 돌려 모두 초록불(Green)이 들어오는지 확인하는 릴레이 검증 물리를 체험합니다. (테스트가 없으면 리팩토링은 절대 할 수 없습니다.)
- 1단계: 1,000줄짜리
- Implement: 오픈 소스나 과거 프로젝트에서 '가장 코드 스멜이 심각한' 로직 하나를 선정하여, 마틴 파울러의 명명법에 맞게 단계별(Commit 단위)로 리팩토링해 나가는 전 과정 증명 보고서.
Advanced
Core Topic 04: 레거시 현대화와 교살자 무화과 패턴 (Legacy Modernization)
- Why to Learn: 도무지 코드를 까볼 엄두가 안 나는 10년 된 낡은 모놀리식 시스템(Legacy)을, 서비스 중단 없이 최신의 클라우드 네이티브(MSA) 환경으로 안전하게 이주시키기 위해서입니다.
- What to Learn:
- Concepts: 빅뱅(Big-bang) 마이그레이션의 위험성, 리플랫포밍(Replatforming), 안티 코럽션 레이어(Anti-corruption Layer).
- Skills: 교살자 무화과 패턴(Strangler Fig Pattern), API 게이트웨이를 이용한 점진적 트래픽 스위칭, 병렬 실행(Dark Launching).
- Tools: Nginx / API Gateway (라우팅 제어), Feature Toggle(기능 스위치).
- Trade-offs: 기존 시스템을 버리고 옆에 새 시스템을 100% 만들어 한 번에 오픈하는 방식(속도는 빠르나 실패 시 회사 파산) vs 새 시스템을 모듈별로 하나씩 갈아 끼우는 교살자 패턴(안전하나 1~2년간 두 시스템을 동시에 운영해야 하는 비용 고통).
- How to Learn:
- 1단계: 프록시(API Gateway)를 세워 모든 트래픽을 구형(Legacy) 서버로 보내다가, '결제' 모듈만 최신(Modern) 서버로 개발한 뒤 트래픽 라우팅을
/pay경로만 새 서버로 살짝 꺾어주는(Strangling) 물리적 라우팅 역학을 스케치합니다. - 2단계: 새 결제 모듈이 기존 구형 데이터베이스의 스키마와 충돌하지 않도록, 중간에 번역기 역할을 하는 '부패 방지 계층(Anti-corruption Layer)'을 두어 레거시의 더러운 데이터 구조가 새 시스템으로 오염되는 것을 막는 방어벽을 설계합니다.
- 1단계: 프록시(API Gateway)를 세워 모든 트래픽을 구형(Legacy) 서버로 보내다가, '결제' 모듈만 최신(Modern) 서버로 개발한 뒤 트래픽 라우팅을
- Implement: 거대한 모놀리식 이커머스 시스템을 마이크로서비스로 분리한다고 가정할 때, 트래픽 유도, 데이터베이스 마이그레이션, 롤백 시나리오를 포함한 4단계 Strangler Fig 마이그레이션 아키텍처 다이어그램.
7. Terminology
8. References
Primary
- [P2] SWEBOK v3 - Software Maintenance (Evolution, Tech Debt)
- [P5] SFIA - Systems development management (DLMG)
Secondary
- [Refactoring] Martin Fowler - Code smells and refactoring mechanics
- [Working Effectively with Legacy Code] Michael Feathers - Testing legacy code
Industry
- [Strangler Fig Pattern] Martin Fowler - Legacy modernization
- Repo-Local ZK:
20_ZK/22_Permanent/10-learning/00-tech-cs/tech/ZK-maintenance-tech-debt.md
9. Final Checklist
Primary
- 소프트웨어 유지보수가 단순히 버그를 잡는 것(Corrective)을 넘어, OS나 브라우저의 변화에 적응(Adaptive)하고 구조를 개선(Perfective)하는 '진화(Evolution)'의 과정임을 리먼의 법칙을 들어 설명할 수 있는가?
- 당장의 출시 속도를 높이기 위해 무지 혹은 의도적으로 엉망으로 짠 코드가 훗날 어떤 복리의 이자(수정 시간 폭증)를 발생시키는지 워드 커닝햄의 '기술 부채(Technical Debt)' 사분면으로 논증할 수 있는가?
Secondary
- 수천 줄짜리
GodClass나 5번 이상 복붙된 중복 로직 등 코드 스멜(Code Smell)을 감지하고, 기존 API의 외부 동작을 1%도 훼손하지 않으면서 내부 구조만 갈아엎는 리팩토링(Refactoring)의 역학을 렌더링할 수 있는가? - 단위 테스트(Unit Test)의 든든한 방어막 없이 무작정 리팩토링을 감행하는 것이 왜 "안대를 쓴 채 진행하는 심장 수술"과 같은 자살 행위인지, 릴레이 검증 물리의 관점에서 설명할 수 있는가?
Industry
- SonarQube 등 정적 분석 도구를 이용해 레거시 코드의 냄새를 맡고, 이를 기술 부채 비율(TDR)이라는 '숫자'로 정량화하여 비즈니스 부서에 리팩토링 예산(일정)을 타당하게 요구할 수 있는가?
- 10년 된 거대한 모놀리식 레거시 시스템을 빅뱅(Big-bang) 방식으로 한 번에 교체하려다 파산하는 대신, API 게이트웨이와 교살자 무화과 패턴(Strangler Fig)을 이용해 2년에 걸쳐 서서히 질식시키는 현대화 파이프라인을 설계할 수 있는가?