TL;DR
- 커밋 메시지를 코딩 전에 작성하면 작업자의 활동이 아니라 소프트웨어의 목표 행동을 약속하게 되며, 이를 통해 작업의 초점과 설계 합의, 커밋 단위의 명확성이 높아짐.
- 테스트 주도 개발(TDD)의 테스트는 검증이 아니라 시스템의 행동을 설명하는 요구사항이며, 구현 전에 작성하는 것이 자연스러운 접근임.
Use Set instead of List같은 메시지는 작업 기록인 반면, “장바구니에 항목이 1만 개를 넘어도 충돌하지 않음”은 소프트웨어의 행동을 설명함.- Jujutsu의 스쿼시 워크플로는 파일을 수정하기 전에 설명이 담긴 빈 리비전을 만들며, Git에서는
git commit --allow-empty와git commit --amend로 같은 방식을 적용할 수 있음. - 2012년 시작된 이 방식은 페어 간 합의, 집중력, 작은 목표, 리뷰, 설계 대화, 시간 제한, 브랜치 흐름, 커밋 이력의 자연스러운 세분화를 이끌어냄.
행동, 테스트가 아닌
- Daniel Terhorst-North의 저서 *Introducing BDD*는 행동 주도 개발(BDD)이 TDD를 단순한 테스트로 보지 않는 직관에서 시작됐다고 설명함.
- “테스트”라는 말은 개발자를 검증과 과거로 향하게 하므로, Daniel은 “행동”이라는 표현을 선호함.
- 이 관점에서 테스트는 클라이언트나 사용자의 시점에서 시스템의 행동을 외부에 드러내며, 시스템이 해야 할 일을 서술형 문장으로 설명함.
- 따라서 테스트는 구현이 존재하기도 전에 비즈니스 언어로 작성하는 비즈니스 요구사항임.
왜 먼저 테스트하는가
- 테스트 대상 시스템이 존재하기도 전에 테스트를 작성하는 일을 직관에 반하거나 터무니없다고 여기는 사람도 있음.
- 하지만 “테스트”를 “요구사항”으로 바꾸면, 목적지를 모른 채 코드를 작성한 뒤 완료 시점에 요구사항을 알아내는 방식이 오히려 이상해짐.
- TDD를 요구사항 주도 개발(Requirement-Driven Development)이라고 불렀다면 직관에 반한다고 여기는 사람은 없었을 것임. “테스트”라는 말이 이미 완성된 것을 검증한다는 인상을 주는 것이 문제임.
집중을 유지하는 데 정말 유용한 방법은 “시스템이 아직 하지 못하는 일 중 다음으로 중요한 것은 무엇인가?”라고 묻는 것임.
- 이 질문은 다음 테스트를 정하고, 테스트는 의도와 약속을 표현함. 테스트를 작성하면 제품의 미래 행동에 구체적으로 전념하게 됨.
커밋은 약속임
- 커밋 메시지도 같은 관점으로 바라보면 Git 용어의 “커밋”이 우연한 표현이 아닐 수 있음. 커밋을 만든다는 것은 약속을 하는 일이기도 함.
- Git에서는 코드가 이미 완성된 뒤 커밋하므로 약속이 다소 늦게 이뤄짐.
- 반면 Jujutsu에서는 관용적인 순서가 정반대임. 먼저
jj commit을 실행한 다음 코드를 작성함.
약속을 어떻게 설명할 것인가
Use Set instead of List는 약속도 행동 설명도 아니며, 수행한 작업을 보고하는 문장임.- BDD 방식으로는 “장바구니에 항목이 1만 개를 넘어도 충돌하지 않음”처럼 쓸 수 있음.
- 두 표현의 차이는 꾸밈의 차이가 아님. 첫 문장은 프로그래머가 수행한 과거의 작업과 방법을 다루고, 두 번째 문장은 기능이 현재 보이는 행동과 결과를 다룸.
내가 한 일이 아니라 소프트웨어가 하는 일을 설명하기
- 두 번째 형식은 Git 이력에서 읽고 싶은 내용이며, 변경 로그 자동 생성을 약속하는 Conventional Commits의 취지와도 맞닿아 있음.
- 커밋을 체크아웃하면 누군가 소프트웨어가 올바르게 행동하도록 작업했다는 점은 알 수 있음. 하지만 그 커밋 위에서 작업할 때 중요한 질문은 “프로그래머가 작업 시간에 무엇을 했는가?”가 아니라 “지금 프로젝트는 어떻게 행동하는가?”임.
- Ferdinando Santacroce가 자주 말하듯, 커밋 메시지는 코드만으로 추론할 수 없는 맥락과 동기, 해결책에 이른 사고 과정을 담아야 함.
- 이 점만으로도 커밋 메시지 작성을 대형 언어 모델(LLM)에 맡기지 않을 이유가 충분함.
먼저 작성하기
- Eric Willeke의 게시물은 버전 관리에 테스트 우선 접근을 적용하는 간결한 관점이며, 즉시 공감대를 형성함.
- 구현 전에 테스트를 작성하는 데 익숙하다면 코딩 전에 커밋 메시지를 쓰는 일도 자연스러움. 메시지는 의도를 표현하고 커밋은 약속이 됨.
- Jujutsu의 스쿼시 워크플로는 파일을 하나도 건드리기 전에 설명이 담긴 새 빈 리비전을 만드는 방식임. 이를 수행하는 명령이
jj commit인 것도 우연이 아님. - 커밋 메시지는 의도이자 작업 단위임. 먼저 작성한 뒤, 그것을 사실로 만듦.
이 방식을 적용하면 생기는 일
- 2012년 팀과 함께 Git에서 이 기법을 시작함. 빈 커밋을
git commit --allow-empty -m <message>로 만든 뒤 작업을 마치면git commit --amend를 실행하는 방식임. 일부 Git 그래픽 사용자 인터페이스(GUI)는 이를 쉽게 처리함. - 페어 작업자의 방향을 맞춤. 드라이버든 내비게이터든 상대와 메시지 및 목표에 합의해야 하므로 대화가 촉진됨. 프로그래밍을 시작할 때는 달성할 목표에 실제로 합의한 상태가 됨. 혼자 코딩할 때도 자신의 이해와 합의를 이뤄야 하며, 그 과정은 마찬가지로 어렵고 보람이 있음.
- 집중하기 쉬워짐. 테스트와 커밋 메시지가 코딩 세션의 중심이 되며, 다른 데로 빠져도 메시지에 적힌 약속이 다시 방향을 잡아줌.
- 작업 범위가 작고 명확해짐. 언제 코딩을 멈춰야 하는지, 어느 정도면 충분한지, 완료했는지를 판단하기 쉬워짐.
- 커밋 리뷰가 단순해짐. 변경사항을 확정하기 전에 검토할 때 “무엇을 했더라?” 대신 “약속한 것을 모두, 그리고 그것만 했는가?”라고 물을 수 있음.
- 메시지의 정확성과 충실도가 높아짐. 코딩 전에 메시지를 쓰면 구체적으로 표현하기 쉬우며,
Fix나Update Repository.cs같은 모호한 문장을 피하게 됨. 처음부터 메시지가 목표이므로 메시지와 결과물도 자연스럽게 일치함. - 메시지를 정하는 과정마다 작은 설계 세션이 열림. 페어 상대와 원하는 행동을 설명할 단어, 도메인 개념의 이름, 행동을 소유할 컴포넌트에 합의해야 함. 이러한 설계 질문을 해결해야 메시지를 작성할 수 있음.
- 자연스러운 시간 제한이 생김. 안정된 상태에서 다음 작은 목표로 나아가는 작은 단계를 약속하면, 변경사항이 목표에 속하는지 판단하기 쉬움.
- 수명이 짧은 기능 브랜치와 잘 맞음. 메시지가 작은 목표를 정의하고, 브랜치 이름이 더 큰 목표의 맥락을 제공함. 브랜치 이름 역시 설계상 사전에 정해짐. 두 수준의 목표가 방향을 잡아줌.
- 커밋 이력의 세분성이 자연스럽게 높아짐. 각 커밋은 하나의 목표를 가지며 단일 책임 원칙(SRP)을 따른다고 볼 수 있음. 기능 브랜치는 행동을 읽기 쉬운 순서로 보여주고, 각 커밋은 더 큰 이야기의 작은 단계가 됨. 자연스러운 변경 로그도 만들어짐.
- 이 실험은 2012년 Arialdo Martini, Mattia Piccinetti, Gian Marco Gherardi, Guglielmo Brasile, Francesco Pichierri, Giuseppe Mariano가 시작했으며, 처음에는 *Pre-emptive Commit Comments*에서 설명됨.
- 이 방식은 Ferdinando Santacroce의 책 *Git Essentials*에서 자세히 설명됨.
참고 자료
- Jujustu
- Conventional Commits
- Pre-Emptive Commit Comments
- Ferdinando Santacroce Git Essentials - Ferdinando Santacroce
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요