Tools/git

커밋 주기는 어느정도가 적당할까?

비비빅B 2023. 5. 8. 21:29

브랜치는 자주 분기하고 커밋 단위는 깔끔하게!

 

업무 컨텍스트가 바뀌면 브랜치를 분기하고, 작업 후 여러 커밋들을 `squash`해서 유의미한 커밋 메시지 단위를 유지하는 것이 좋다고 생각했다. 실제로 그렇게 했을 때 `revert`하기도 편하고 커밋히스토리도 비교적 깔끔하게 관리되기 때문이다.

 

하지만 최근에 브랜치 전략을 설명할 일이 생기면서, 다른 회사의 브랜치 전략들을 찾아봤는데 잘못 알고 있던 정보들이 많아 글로 정리한다.

 

커밋은 적어도 하루에 한 번

 

유의미한 커밋을 만들어 내는 것은 좋지만, 그것보다 내가 작업한 결과물을 동료들에게 빠르게 공유하는 것이 훨씬 중요하다. 왜냐하면 소스 통합 시 발생하는 충돌(conflict)때문이다.

 

개인적으로 충돌을 많이 경험하진 못했지만, 발생할 때마다 스트레스는 상당했다. 충돌된 소스와 내 소스 중 뭐가 더 맞는 소스인지 확인하려면 컨텍스트(무엇때문에 변경했는지, 뭐가 올바른 로직인 건지)를 알고 있어야 했기 때문이다. 실제로 변경 규모가 크고, 오랫동안 통합하지 않았다면 충돌 해결에만 반나절 정도 소요되는 경우도 있다고 한다.

충돌이 자주 발생해서 부정적인 경험이 쌓이게 되면, 개발자들은 소스 통합을 미루게 되고 결국 악순환에 굴레에 들어서게 된다.

추가적으로 다른 사람의 소스에서 변경할 부분이 눈에 보여도 충돌의 공포 때문에 변경하지 않게 된다. 당장의 리팩토링 기회도 놓칠뿐더러 적극적으로 문제를 해결하는 개발 문화에도 악영향을 미친다.

 

통합을 잦게 하면 동료 개발자들이 내 변경사항을 알게 돼 충돌을 피할 수 있고, 만약 충돌 나더라도 매우 작은 부분이기 때문에 시간이 별로 소요되지 않을 것이다.

 

소스 통합 전략

 

여기서 내가 알고 있던 지식이랑 충돌이 발생한다. 개발자들은 어떤 추가적인 기능을 개발할 때 feature 브랜치를 따서 하는 게 좋은 브랜치 전략 아니었나? 브랜치를 따서 작업하되 중간에 지속적으로 메인 소스에 병합하라는 말인가?

mainline은 항상 healthy 해야 한다.
  • mainline
    • 개발자들에게 공유되는 단 하나의 브랜치로 개발소스의 최신버전을 가짐
    • 흔히 git에서 master or main 브랜치라고 말하지만 엄밀히 구분하면 조금 다름
    • 개인 repository로 fork 하는 경우 자신의 repo master 브랜치는 mainline이 아님
  • healthy
    • 해당 소스로 당장 배포되더라도 문제없이 정상 서비스되는 상태

 

소스 통합 할 때 가장 중요한 원칙이다. 이 원칙이 지켜졌을 경우에만 Continuous Delivery 된다고 볼 수 있다.

 

Feature Branch Integration

기능 개발 시작할 때 개인 브랜치를 분기해서 진행하고 완료 후 병합하는 전략

 

가장 흔히 사용하는 통합 패턴이다. 예를 들어 oauth2 로그인 기능이 신규로 된다면 mainline에서 `feat/oauth2`를 분기해 작업을 시작한다. 작업이 완료되면 병합하기 전 테스트를 거치고 mainline에 반영해 healthy 한 상태를 유지한다.

기능 개발이 완료되는 시점에 mainline에 반영해 동료들에게 공유하기 때문에 소스가 명확하다는 장점이 있지만, 위에서 언급한 커밋 주기가 길다는 단점이 있다. 짧게는 하루에서 길게는 한 달 넘게 걸리는 기능이 있기 때문에, 병합 시 충돌의 위험성이 크다.

 

Continuous Integration

별도의 브랜치에서 작업하지 않고 mainline에 수정사항을 바로 통합하는 전략

 

최소 하루에 한 번은 mainline에 통합하는 것을 목표로 짧은 커밋 주기를 가지는 전략이다. 커밋 단위가 작은 만큼 충돌의 위험성이 작다는 장점이 있다. 하지만 healthy 한 mainline을 유지하기 위해 매 커밋마다 테스트가 필수적이며, 이를 위해 꼼꼼한 단위테스트 작성이 필요하다는 단점이 있다. 또한 새로운 기능의 개발 중인 소스가 mainline에 반영되기 때문에 Feature Toggle이라는 추가적인 전략이 필요하다.

 

Feature Toggle 이란 개발 완료되지 않은 기능이 클라이언트에 노출되는 것을 막기 위해, 코드 수정 없이 시스템의 동작을 바꾸는 기술이다.
 

매일 배포하는 팀이 되는 여정(2) — Feature Toggle 활용하기

효율적이고 안정적인 배포를 위해 고민했던 것 중 하나인 Feature Toggle(Feature Flag)에 대한 이야기

medium.com

 

Code Review

추가적으로 코드리뷰 시점이 애매해진다는 단점이 있다. 브랜치 통합 전략의 경우 github의 pull-request 기능과 결합하여, feature 브랜치가 mainline에 병합되기 전에 코드리뷰를 할 수 있었다. 하지만 Continuous Integration은 미완성된 소스가 계속 mainline에 반영되는데 코드리뷰를 어느 시점에 할 수 있을까?

 

코드리뷰에 대해서도 개발자들이 처리해야 할 큰 업무로 다가오면서 일종의 부채로 느껴지기 시작한 지 오래됐다고 한다. 그러면서 코드리뷰의 단점에 대해서도 많이 논의된 상황인데 정리하면 아래와 같다.

 

  • 많은 코드리뷰 처리량
  • 코드리뷰 과정에서 발생하는 불화
  • 지연되는 코드리뷰
    • 코드리뷰가 승인될 동안 개발자의 업무가 불명확해짐
    • 시간이 지날수록 Context가 희미해져 효율이 낮아짐
    • 병합 시 충돌 가능성이 커짐
  • 리뷰어에게 코드 품질을 의존하는 구조
    • 팀원을 신뢰하지 않는 분위기를 조장할 수 있음

 

위의 문제점 때문에 점차 코드리뷰를 줄이는 추세라고 한다. 나는 코드리뷰 문화를 경험해보지도 못했는데 뭔가 억울하다.

대신 짝 프로그래밍(pair programming) 혹은 `Ship/Show/Ask`를 통해 코드리뷰의 빈자리를 보완한다고 한다.

 

 

무조건 Continuous Integration?

 

'featrue 브랜치는 레거시 하고 나쁜 걸까?'라고 생각이 들 수도 있지만 그렇지 않다.

전략의 핵심은 통합 주기를 짧게 해서 충돌을 최소화해 개발자들의 스트레스를 줄이면서, 서비스를 성공적으로 배포하는 것이다.

만약 단위 테스트 코드가 부족하거나, 주니어 개발자들이 많아 강제적인 코드리뷰가 꼭 필요하는 등 여러 이유로 인해 mainline의 healthy를 유지하기가 힘든 상황이 있을 수도 있다. 그렇다면 Continuous Integration을 과감히 포기하고 `release` 브랜치를 따로 구성해, 배포 가능한 소스를 확보해 놓는 것이 좋다.

 

 

은탄환은 없다지만 현재 여건(신뢰할 수 있는 동료)이 된다면 브랜치를 최소화하는 것이 제일 좋은 방향이라고 한다.

흔히 알려진 git-flow는 여러 배포 버전을 관리해야 하는 서비스를 대상으로 만든 전략이다. 현재 그 의도와 맞지 않게 서비스에 비해 브랜치만 과도하게 않은 케이스가 많다고 한다.

배포 버전을 관리할 필요 없는 웹 서비스라면 github-flowTrunk-Based Development 전략 중에 하나를 선택하는 것이 현재로선 최선으로 보인다.

 


 

Patterns for Managing Source Code Branches

Mainline, Feature Branching, Continuous Integration, Release Branch and a clutch of other handy patterns.

martinfowler.com

 

 

'Tools > git' 카테고리의 다른 글

Git 명령어 정리  (0) 2021.12.28
Github-flow, Git-flow (1)  (0) 2020.11.06