대부분의 Git 워크플로우가 솔로 개발자에게 실패하는 이유
대부분의 Git 튜토리얼과 워크플로우의 문제는 다수의 팀, 코드 리뷰 프로세스, 그리고 최소 세 개의 서로 다른 환경을 포함하는 배포 파이프라인을 가진 회사에서 일하는 사람들이 작성했다는 점입니다. 솔로 개발자일 때는 이러한 제약이 없지만, 동시에 이러한 안전망도 없습니다. 2010년대를 지배했던 GitFlow는 완벽한 예입니다. 이는 Vinenc Driessen이 여러 버전을 동시에 지원해야 하는 소프트웨어의 릴리스 관리를 위해 특정 문제를 해결하기 위해 설계했습니다. 고객이 로컬에 설치하는 데스크탑 애플리케이션을 구축하고 있다면 GitFlow는 이해가 됩니다. SaaS 제품이나 클라이언트 웹사이트를 배포하고 있는 솔로 개발자라면 완전히 과한 것입니다. 일반적인 솔로 개발자의 Git 여정은 이렇습니다: 단지 `main`(또는 Git을 배운 시기에 따라 `master`)에 커밋하는 것으로 시작합니다. 그런 다음 "전문적인 Git 워크플로우"에 대한 기사를 읽고 죄책감을 느낍니다. 기능 브랜치를 구현합니다. 그리고 다이어그램이 보여준 대로 `develop` 브랜치를 추가합니다. 얼마 지나지 않아 하루에 20분을 브랜치를 관리하는 데 써서, 그 중 절반이 왜 존재하는지도 확신할 수 없게 됩니다. 저도 그랬습니다. `feature/new-feature`, `feature/new-feature-2`, `feature/new-feature-actually-final`, `feature/new-feature-for-real-this-time`라는 이름의 브랜치를 가진 리포지토리를 가진 적이 있습니다. 브랜치 이름 지정 위기가 없었다면, 당신은 거짓말을 하고 있거나 솔로 개발을 한 지 오래되지 않았습니다. 근본적인 문제는 팀의 워크플로우가 팀의 문제를 해결하기 위해 설계되었다는 것입니다: 여러 사람 간의 작업 조정, 충돌 방지, 코드 리뷰 프로세스 관리, 그리고 공유 환경에서의 안정성 유지. 솔로로 작업할 때 이러한 문제는 대부분 단순히 존재하지 않습니다. 다른 사람이 없다면 누군가와 병합 충돌이 발생할 수 없습니다.모든 것을 바꾼 세 커밋 규칙
오전 2시의 재앙 이후, 저는 제 실제 작업 패턴을 분석하기 시작했습니다. 지난 6개월 동안의 Git 기록을 살펴보며 제가 만든 모든 브랜치, 진행한 모든 병합, 해결한 모든 충돌을 살펴보았습니다. 제가 발견한 것은 계몽적이었습니다. 제 기능 브랜치 중 90%는 병합하기 전에 3개 이하의 커밋을 포함하고 있었습니다. 이것들은 복잡하고 여러 주가 걸리는 기능이 아니라, 제가 "진짜 개발자"가 해야 하는 것이라고 생각해 인위적으로 분리한 작은 개선, 버그 수정 및 점진적인 변경이었습니다. 남은 10%—실제 복잡한 기능이—브랜치가 의미가 있는 경우였습니다. 하지만 그때도 저는 무언가를 알아차렸습니다: 문제가 발생한 브랜치는 일주일 이상 열려 있었던 것입니다. 브랜치의 생존 기간이 길어질수록 병합 시 문제가 발생할 가능성이 높아졌습니다. 이것은 제가 "세 커밋 규칙"이라고 부르는 것으로 이어졌습니다: 변경이 3개 이상의 커밋이 필요하다면, 아마도 너무 크고 쪼개어져야 합니다. 쪼개질 수 없다면, 브랜치가 실제로 도움이 되는 드문 경우입니다. 이 규칙은 제가 어떻게 작업하는지에 대해 다르게 생각하게 만들었습니다. "UI 전체를 재디자인"하기 위해 브랜치를 만드는 대신, "버튼 스타일 업데이트" 또는 "새 탐색 컴포넌트 구현"을 위한 브랜치를 만들었습니다. 각 브랜치는 최대 하루 또는 이틀 동안 존재하였고, 집중된 변경을 포함하며, 깔끔하게 병합되었습니다. 심리적 변화는 상당했습니다. 저는 "기능"이라는 용어로 생각하는 것을 멈추고 "배포 가능한 인크리먼트"라는 용어로 생각하기 시작했습니다. 각 브랜치는 기존 기능을 중단하지 않고 배포할 수 있는 것을 대표해야 했습니다. 이는 자연스럽게 브랜치를 작고 짧게 유지하게 했습니다.버그를 프로덕션에 배포했던 날 (그리고 이로 인해 제 워크플로가 어떻게 더 나아졌는지)
저의 경력에서 최악의 배포에 대해 말씀드리겠습니다. 저는 클라이언트 프로젝트인 소규모 호텔 체인을 위한 예약 시스템에서 일하고 있었습니다. 제가 새로운 결제 통합을 추가하는 기능 브랜치에서 2주 동안 작업하고 있었습니다(네, 알겠습니다, 제 규칙을 깨뜨렸습니다). 브랜치가 `main`에서 현저히 벗어나 있었고, 결제 기능에 너무 집중한 나머지 긴급 클라이언트 요청으로 인해 `main`에서 직접 진행한 작은 수정 및 개선 작업을 따라잡지 못했습니다. 병합할 때가 되었을 때, 14개의 파일에서 충돌이 발생했습니다. 저는 충돌을 해결하고, 테스트를 실행했으며(테스트가 통과했습니다), 프로덕션에 배포했습니다. 한 시간도 채 지나지 않아, 고객으로부터 급한 전화가 왔습니다. 예약 양식이 망가졌습니다. 새로운 결제 통합이 아니라, 몇 달 동안 잘 작동하고 있던 기본 예약 양식이었습니다. 무슨 일이 있었을까요? 병합 충돌 중 하나를 해결하면서 저는 우연히 잘못된 버전의 기능을 유지하게 되었습니다. 테스트는 그 특정 엣지 케이스에 대한 테스트를 작성하지 않았기 때문에 그것을 잡지 못했습니다(교훈을 얻었습니다). 버그는 전적으로 제 잘못이었지만, 워크플로가 그 실수를 저지르기 쉽게 만들었습니다. 그 사건은 제가 중요한 것을 배울 수 있게 했습니다: 솔로 개발자로서 저의 최대 위험은 다른 사람의 코드가 아니라, 2주 전 제 자신의 코드입니다. 프로젝트의 다양한 부분을 계속 전환할 때, 저는 본질적으로 과거의 저와 협업하고 있습니다. 그리고 과거의 저가 종종 신뢰할 수 없는 동료입니다. 이러한 인식은 제 워크플로의 두 번째 기둥인 "1주 규칙"으로 이어졌습니다. 어떤 브랜치도 1주 이상 존재하지 않습니다. 기능이 그보다 더 오래 걸릴 것이라면, 저는 그것을 각각 일주일 내에 완성해 병합할 수 있는 더 작은 조각으로 쪼갭니다. 만약 불가능하다면, 기능 플래그를 사용하여 사용자에게 숨긴 채로 불완전한 코드를 `main`에 병합합니다. 1주 규칙 덕분에 무수히 많은 시간을 절약할 수 있었습니다. 이는 제가 항상 `main`에 가까이 있도록 강요하며, 따라서 저는 항상 코드베이스의 최신 버전으로 작업하고 있습니다. 이는 복잡한 병합 충돌로 이어지는 분기를 방지합니다. 그리고 범위에 대해 정직하게 유지하게 하며—무언가를 일주일 안에 끝내지 못할 경우, 아마도 저는 한 번에 너무 많은 것을 시도하려고 하고 있습니다.브랜치 복잡성의 실제 비용
숫자로 이야기해 보겠습니다. 저는 제 Git 관련 활동을 워크플로를 단순화하기 전과 후의 3개월 동안 추적했습니다. 결과는 극명했습니다:| 활동 | 이전 (시간/주) | 후 (시간/주) | 절약된 시간 |
|---|---|---|---|
| 브랜치 생성 및 관리 | 2.5 | 0.5 | 2시간 |
| 병합 충돌 해결 | 3.0 | 0.3 | 2.7시간 |
| 어떤 브랜치에서 작업할지 결정하기 | 1.5 | 0.1 | 1.4시간 |
| 오래된 브랜치 정리하기 | 1.0 | 0.1 | 0.9시간 |
| 브랜치 리베이스 및 동기화 | 2.0 | 0.2 | 1.8시간 |
| 총 Git 오버헤드 | 10.0 | 1.2 | 8.8시간 |
왜 "조기 커밋, 자주 커밋"이 솔로 개발자에게 잘못된 것인지
다소 논란의 여지가 있는 의견을 말씀드리겠습니다: "조기 커밋, 자주 커밋하라"는 조언은 솔로 개발자에게 실제로 해롭습니다. 이것은 일반적인 지혜에 반하는 말이지만, 잘 들어보세요.커밋의 목적은 모든 키 입력에 대한 세부 로그를 만드는 것이 아닙니다. 그것은 코드의 진화에 대한 이야기를 들려주는 의미 있는 체크포인트를 만드는 것입니다. 솔로로 작업할 때, 당신은 그 이야기를 이해해야 할 유일한 사람입니다.