AtomicCommit
주니어 개발자들을 위한 패턴 언어 - 변경의 역사를 의미 있고 안전한 단위로 기록하는 법
Contents
The Story 1: The Giant Bundle vs. The Clean History (Programming)
두 명의 개발자, 민수와 하나가 '장바구니 기능'을 완성하고 코드를 제출(Commit)하려 한다.
민수의 커밋 (The Big Bang): 민수는 하루 종일 코드를 작성했다. 변수 이름을 고치고, 버그를 잡고, 새로운 기능을 추가하고, 필요 없는 주석을 지웠다. 퇴근 직전, 그는 40개의 파일을 한꺼번에 커밋했다.
커밋 메시지: 장바구니 기능 완성 및 버그 수정
나중에 동료가 물었다. "민수님, 아까 고친 버그가 다른 데 문제를 일으키는 것 같은데, 그 부분만 되돌릴 수 있을까요?" 민수는 당황했다. "음... 그게 다른 코드랑 다 섞여 있어서, 그것만 따로 빼기는 힘들 것 같은데요..."
하나의 커밋 (Atomic Steps): 하나는 작업을 쪼개서 진행했다.
cart 변수명을 shoppingCart로 변경 (커밋: refactor: 장바구니 변수명 명확화)
장바구니 합계 계산 로직 추가 (커밋: feat: 장바구니 합계 계산 기능 구현)
잘못된 할인율 적용 버그 수정 (커밋: fix: VIP 할인율 5% -> 10% 수정)
하나는 각 단계가 끝날 때마다 테스트를 확인하고 커밋했다. 나중에 버그 수정에 문제가 발견되었을 때, 그녀는 단 1초 만에 해당 커밋만 취소(Revert)할 수 있었다.
The Story 2: The Laundry Day (Ordinary Life)
민수와 하나는 각자 집에서 밀린 빨래를 하고 있다.
민수의 빨래 (The Mixed Load): 민수는 빨래 바구니에 담긴 모든 옷을 세탁기에 한꺼번에 넣었다. 흰 수건, 검은색 청바지, 섬세한 실크 셔츠가 한데 뒤섞여 돌아갔다. 세탁이 끝난 후, 민수는 경악했다. 청바지에서 빠진 물이 흰 수건을 푸르게 물들였고, 실크 셔츠는 엉망으로 망가졌다. 무엇이 잘못되었는지 알았을 때는 이미 늦은 뒤였다.
하나의 빨래 (The Sorted Cycle): 하나는 빨래를 종류별로 나누어 세 번에 걸쳐 세탁기를 돌렸다.
- 흰 수건들만 모아서 고온 세탁.
- 색깔 있는 겉옷들만 모아서 표준 세탁.
- 섬세한 의류들만 모아서 울 코스 세탁.
하나는 각 세탁 주기가 끝날 때마다 상태를 확인하고 정리했다. 덕분에 옷감은 상하지 않았고, 나중에 옷을 찾아 입기도 훨씬 편했다. 작업을 의미 있는 단위로 나누어 처리하는 것이 결국 전체의 품질을 지키는 길임을 하나는 알고 있었다.
Context
당신은 BabySteps를 밟으며 기능을 구현하고 있다. 이제 작성한 코드를 저장소에 기록할 차례다.
일상적인 상황:
- 퇴근할 때 한꺼번에 "오늘 작업분"이라고 커밋한다.
커밋 메시지에 and, also, fixed many things 같은 단어가 자주 등장한다.
- 리팩토링과 기능 추가가 하나의 커밋에 뒤섞여 있다.
- 나중에 특정 변경 사항만 찾거나 되돌리려고 하면 막막하다.
당신은 지금 코드를 거대한 뭉텅이로 다루고 있어, 과거의 기록이 미래의 짐이 되고 있다.
Problem
여러 목적의 변경이 섞인 거대한 커밋은 협업과 유지보수를 불가능하게 만든다.
커밋이 "원자적(Atomic)"이지 않으면 다음과 같은 문제가 생긴다:
리뷰의 고통: 동료가 코드를 리뷰할 때, 무엇이 핵심 기능이고 무엇이 단순한 오타 수정인지 구분하기 어렵다.
선택적 취소 불가: 기능 구현은 유지하고 버그 수정만 되돌리고 싶어도, 코드가 섞여 있어 불가능하다.
충돌(Conflict) 해결의 지옥: 커밋이 클수록 다른 사람의 코드와 충돌할 확률이 높아지고, 해결하기도 복잡해진다.
신뢰도 하락: 커밋 하나가 컴파일되지 않거나 테스트가 실패하는 상태라면, 그 기록은 아무런 가치가 없다.
Solution
하나의 커밋이 "하나의 완전하고 일관된 변경"만을 담게 하라.
원자적 커밋(Atomic Commit)은 시스템을 한 상태에서 다른 안정적인 상태로 전이시키는 최소 단위다.
Principle 1: One Commit, One Purpose (한 커밋에 한 목적)
커밋 하나는 하나의 이야기만 해야 한다.
- 리팩토링과 기능 추가를 섞지 마라. 리팩토링을 먼저 하고 커밋한 뒤, 기능을 추가하라.
- 오타 수정이나 포맷팅 변경은 별도의 커밋으로 분리하라.
커밋 메시지에 and가 필요하다면, 그것은 커밋을 쪼개야 한다는 신호다.
Principle 2: Always Stable (항상 안정적인 상태)
커밋된 시점의 코드는 언제나 빌드가 되고 테스트를 통과하는 상태여야 한다.
- "작업 중(WIP)"인 코드를 메인 브랜치에 커밋하지 마라.
BabySteps의 한 단계가 완료되었을 때가 가장 좋은 커밋 시점이다.
Principle 3: Minimum Viable Change (최소 기능 단위)
변경 사항은 가능한 한 작아야 한다. 하지만 동시에 그 자체로 의미가 있어야 한다.
- 너무 작아서 시스템에 아무런 영향을 주지 않는 조각은 합쳐도 좋다.
- 하지만 5개 이상의 파일을 건드렸다면, 더 쪼갤 수 없는지 검토하라.
Principle 4: Descriptive Messages (의미 있는 메시지)
메시지는 "무엇을(What)" 했는지보다 "왜(Why)" 했는지를 설명해야 한다.
fix: ... 보다는 fix: VIP 할인 로직이 결제 단계에서 누락되는 문제 해결이 낫다.
Real Examples
Example 1: Refactoring before Feature
새로운 검색 필터를 추가해야 한다. 그런데 기존 코드가 너무 지저분해서 고치기 힘들다.
(Step 1) 코드를 깨끗하게 정리한다. (커밋: refactor: 검색 필터 확장성을 위한 인터페이스 추출)
(Step 2) 새로운 필터를 추가한다. (커밋: feat: 날짜 범위 검색 필터 추가)
이렇게 분리하면, 나중에 검색 필터 기능에 버그가 생겨도 리팩토링한 부분은 안전하게 유지할 수 있습니다.
Example 2: Small Fixes
기능 개발 중에 오타를 발견했다.
현재 하던 작업을 잠시 멈춘다(또는 git stash).
오타만 고치고 커밋한다. (커밋: docs: README 오타 수정)
- 다시 하던 작업으로 돌아간다.
작은 것들을 즉시 치워버리면 주 작업의 커밋이 깨끗해집니다.
Common Pitfalls
"I forgot to commit!" (커밋하는 걸 깜빡했어요)
정신없이 코딩하다 보니 어느새 2시간이 지났고 10개의 파일을 고쳤다.
이럴 때는 git add -p (patch mode)를 사용하여 파일을 부분적으로 나누어 커밋하라.
- 코드를 조각조각 나누어 논리적인 흐름으로 재구성할 수 있다.
"Small commits are noisy" (커밋이 너무 많으면 시끄러워요)
커밋 로그가 길어지는 것을 두려워하지 마라.
- 지저분하고 큰 커밋 1개보다, 깨끗하고 작은 커밋 10개가 훨씬 읽기 쉽다.
필요하다면 나중에 squash를 통해 합칠 수 있지만, 처음부터 섞여 있는 것을 나누기는 매우 힘들다.
Connection to Other Patterns
GreenRefuge - 커밋이 원자적이면, 문제가 생겼을 때 바로 전 커밋으로 되돌아가는 것이 매우 안전하고 쉽습니다. 안전망
TightLoop - 피드백 루프가 빠를수록 작은 단위의 확신을 얻기 쉽고, 더 자주 커밋할 수 있습니다. 동력
OrganicGrowth - 시스템은 작은 원자적 변경들이 쌓여서 유기적으로 성장합니다. 철학
Signs of Success
- 커밋 로그만 읽어도 이 기능이 어떻게 만들어졌는지 이야기가 들린다.
- 코드 리뷰를 할 때 커밋 단위로 하나씩 넘겨보며 이해할 수 있다.
버그가 발생했을 때 git bisect를 사용하여 원인이 된 커밋을 정확히 찾아낼 수 있다.
- "이 부분만 잠깐 되돌려볼까요?"라는 제안에 즉시 실행할 수 있다.
The Ultimate Insight
커밋은 당신의 코드를 저장하는 도구일 뿐만 아니라, 동료(그리고 미래의 당신)와 대화하는 수단이다.
원자적 커밋을 하는 습관은 당신의 사고를 더 정교하게 만들고, 팀 전체의 개발 속도를 높여줍니다. 기록을 깨끗하게 유지하십시오. 그것이 프로의 책임감입니다.
CategoryPatternLanguage CategoryProgramming CategoryGit CategoryAgile
