SafetyNet
주니어 개발자들을 위한 패턴 언어 - 두려움 없이 코드를 수정할 수 있는 용기를 주는 안전망
Contents
The Story 1: The House of Cards vs. The net (Programming)
두 명의 개발자, 민수와 하나가 3년 된 레거시 시스템의 핵심 결제 로직을 수정해야 한다.
민수의 상황 (The Fear): 민수는 코드를 고치는 것이 무섭다. "이거 고쳤다가 잘 돌아가는 다른 기능이 깨지면 어떡하지?" 그는 변경을 최소화하기 위해 if (new_condition) 문을 덕지덕지 붙였다. 코드는 더 지저분해졌지만, 기존 로직을 건드리는 것보다는 안전해 보였다. 하지만 배포 후, 전혀 상관없어 보이는 '포인트 적립' 기능이 멈췄다. 민수는 밤새 식은땀을 흘리며 롤백했다. 이제 그는 코드를 건드리는 것 자체를 공포로 느낀다.
하나의 상황 (The Confidence): 하나는 수정하기 전에 먼저 안전망을 설치했다. "기존 기능들이 어떻게 동작해야 하는지 테스트로 기록해두자." 그녀는 현재 동작을 그대로 검증하는 테스트(Characterization Test)를 작성했다. 그리고 나서 과감하게 구조를 뜯어고쳤다(Refactoring). 중간에 실수로 포인트 적립 로직을 지워버렸지만, 1초 만에 테스트가 빨간불을 켰다. "아차, 이걸 빠뜨렸네." 하나는 웃으며 다시 코드를 수정했다. 그녀에게 수정 작업은 줄타기가 아니라, 그물망 위에서의 점프였다. 떨어져도 안전했기 때문이다.
The Story 2: The Acrobat's Net (Ordinary Life)
민수와 하나는 서커스 공연을 관람하고 있다. 오늘은 세계적인 공중곡예사의 공연 날이다.
민수의 관찰 (The Risk): 민수는 곡예사가 공중에서 회전할 때마다 가슴을 졸인다. "저렇게 높은 곳에서 실수라도 하면 끝장이잖아." 민수의 눈에는 곡예의 화려함보다 떨어졌을 때의 위험이 더 크게 보였다. 만약 민수가 저 위에 있다면, 무서워서 아주 간단한 동작조차 시도하지 못했을 것이다.
하나의 발견 (The Safety Net): 하나는 곡예사의 발아래에 설치된 크고 튼튼한 그물망(Net)을 보았다. "저 그물이 있기 때문에 곡예사가 저토록 대담하고 아름다운 기술을 선보일 수 있는 거야." 곡예사는 떨어지는 법을 먼저 배웠고, 그물이 자신을 받아줄 것임을 100% 신뢰했다. 그 신뢰가 곡예사에게 한계를 뛰어넘는 용기를 주었고, 결국 관객들에게 최고의 감동을 선사했다. 안전망은 구속이 아니라, 자유를 위한 전제 조건임을 하나는 깨달았다.
Context
시스템은 이미 OrganicGrowth를 통해 어느 정도 성장했고 복잡해졌다. 이제 기능을 추가하거나 구조를 개선(Refactoring)해야 한다.
일상적인 상황:
- "잘 돌아가는 건 건드리지 마"라는 불문율이 있다.
- 코드를 수정할 때마다 기도하는 마음이 된다.
- QA팀이 전체 기능을 손으로 테스트하는 데 3일이 걸린다.
- 리팩토링을 하고 싶지만, 사이드 이펙트가 두려워 포기한다.
당신은 지금 안전 장비 없이 고층 빌딩에서 작업하고 있다. 한 번의 실수가 추락으로 이어진다.
Problem
기존 기능이 깨질 수 있다는 두려움은 코드의 개선을 막고, 결국 시스템을 썩게 만든다.
개선의 정체: 두려움 때문에 리팩토링을 미루면, 기술 부채(Technical Debt)가 쌓여 개발 속도가 급격히 느려진다.
버그의 두더지 잡기: 이곳을 고치면 저곳이 터지는 현상이 반복된다.
심리적 위축: 개발자가 코드의 주인이 아니라 노예가 된다.
Solution
코드를 수정하기 전에, 기존 기능의 동작을 보장하는 자동화된 회귀 테스트(Regression Test)를 구축하라.
이 테스트들의 목적은 "새로운 기능을 검증하는 것"이 아니라, "기존 기능이 여전히 잘 작동함을 보장하는 것"이다. 이것이 당신의 안전망(Safety Net)이다.
Principle 1: Cover Before Change (변경 전 커버리지 확보)
수정하려는 코드가 테스트로 커버되지 않았다면, 절대로 코드를 먼저 고치지 마라.
- 테스트가 없다면? 먼저 현재 동작을 그대로 통과시키는 테스트를 작성하라.
이것을 Characterization Test(특성 테스트)라고 한다. 버그가 있더라도 일단 현재 동작 그대로를 테스트로 옮겨라. 그래야 내가 무엇을 바꿨는지 알 수 있다.
Principle 2: Fast Feedback Loop (빠른 피드백)
안전망은 즉시 작동해야 한다.
- 코드를 고치고 나서 QA팀의 결과를 기다리는 건 안전망이 아니다. 그것은 부검(Post-mortem)이다.
TightLoop를 통해 1분 안에, 늦어도 5분 안에 "모든 기능 정상"이라는 신호를 받아야 한다.
Principle 3: Confidence over Coverage (커버리지보다 확신)
테스트 커버리지 100%가 목표가 아니다.
- "이 테스트들이 통과하면, 나는 안심하고 배포할 수 있는가?"가 기준이다.
- 깨지기 쉬운 세부 구현보다는, 중요한 비즈니스 규칙(Invariants)을 검증하라.
Principle 4: The Scout Rule (보이스카우트 규칙)
모든 곳에 안전망을 칠 수는 없다.
- 내가 지금 작업하는 영역, 내가 지나가는 길에만이라도 안전망을 설치하라.
- 시간이 지나면 시스템의 중요한 부분들은 모두 안전망으로 덮이게 된다.
Real Examples
Example 1: Legacy Code Refactoring
1000줄짜리 PaymentService를 리팩토링해야 한다.
먼저 PaymentService의 주요 시나리오(성공, 잔액 부족, 타임아웃)에 대한 테스트를 작성한다. (아직 코드는 안 건드림)
- 테스트가 모두 통과하는지 확인한다. (Green)
- 이제 내부 구조를 쪼개고 변수명을 바꾼다.
- 테스트를 돌린다. 여전히 Green인가? 그렇다면 안전하다.
Example 2: Bug Fix with Safety Net
"특정 날짜에 할인이 안 적용돼요"라는 버그 리포트.
- 버그를 재현하는 테스트 케이스를 먼저 만든다. (Red)
- 이 테스트가 나의 안전망이자 나침반이 된다.
- 버그를 고친다. (Green)
- 이 테스트는 영원히 테스트 스위트에 남아, 1년 뒤에 누군가 똑같은 실수를 하는 것을 막아준다(Regression Prevention).
Common Pitfalls
"I don't have time to write tests" (테스트 짤 시간이 없어요)
수동으로 테스트하고, 버그가 생겨서 디버깅하고, 다시 고치는 시간을 합치면 테스트 작성 시간보다 훨씬 길다. 안전망 설치는 시간이 걸리지만, 추락해서 병원에 가는 시간보다는 짧다.
Fragile Tests (깨지기 쉬운 테스트)
내부 구현(Private 변수, 메서드 순서 등)을 너무 자세히 테스트하면, 리팩토링할 때마다 테스트가 깨진다.
안전망은 "기능(Behavior)"을 지켜야지 "구현(Implementation)"을 지키면 안 된다. CleanIsolation을 활용해 인터페이스 위주로 테스트하라.
False Sense of Security (잘못된 안도감)
테스트는 다 통과하는데 실제로는 작동 안 하는 경우(Mock 남용 등).
가끔은 OrganicGrowth된 전체 시스템을 관통하는 End-to-End 테스트도 필요하다.
Connection to Other Patterns
GreenRefuge - 안전망이 있어야 실패했을 때 즉시 GreenRefuge로 돌아갈 수 있습니다. 필수 조건
Refactoring - 리팩토링은 안전망 없이는 불가능합니다. 안전망 없는 리팩토링은 그냥 "코드 망가뜨리기"입니다. 전제
DesignThroughTest - 새로운 기능은 DesignThroughTest로 만들고, 만들어진 기능은 SafetyNet이 되어 남습니다. 순환
Signs of Success
- 배포 전날 밤에 잠을 잘 잔다.
- 코드를 대대적으로 수정하는 것이 두렵지 않고 오히려 즐겁다.
- "지난번에 고친 것 때문에 이게 안 되잖아요"라는 항의가 사라진다.
- 신입 개발자가 와서 코드를 고쳐도 시스템이 안전하게 유지된다.
The Ultimate Insight
테스트는 코드를 위한 것이 아니라, 개발자의 심장을 위한 것이다.
두려움은 창의성의 적입니다. 안전망은 두려움을 제거함으로써, 당신이 더 과감하고 더 나은 설계를 시도할 수 있는 자유를 줍니다. 안전망을 짜십시오. 그리고 자유롭게 날아오르십시오.
CategoryPatternLanguage CategoryProgramming CategoryTesting CategoryTDD CategoryRefactoring
