안녕하세요, 맘편한세상의 백엔드 엔지니어 이재찬입니다.
맘편한세상의 백엔드 팀은 최근 1년 동안 Git Flow의 대안으로서 트렁크 기반 개발을 활용해 왔습니다. 이 글에서는 두 브랜치 전략의 이론적 사용법에 대해서, 그리고 실제로 사용해오면서 느낀 점들을 공유해보고자 합니다.
Git Flow는 Vincent Driessen이 2010년에 제시한 Git 브랜치 전략으로 널리 알려져 있습니다.
A successful Git branching model - Vincent Driessen
Git Flow를 설명하는 그래프
Git Flow 전략의 개요를 간단히 한번 짚고 넘어가 보겠습니다. Git Flow의 핵심은 master
와 develop
두 개의 주 브랜치입니다. master
브랜치에 있는 작업은 운영환경에 배포될 수 있는 것, develop
브랜치에 있는 작업은 다음 릴리즈를 위해 준비된 것입니다. 이 외에도 feature
, release
, hotfix
이 세 가지 보조 브랜치가 존재합니다.
feature
: 새로운 기능을 develop
브랜치 위에서 개발하기 위해 사용release
: develop
의 변경사항을 운영환경에 배포하기 위해 사용hotfix
: 운영환경에 시급하게 수정되어야 할 이슈가 있을 때, master
를 빠르게 변경하기 위해 사용Vincent Driessen이 2010년에 Git Flow를 처음 제시했던 블로그 글을 보면, 그가 글을 작성한 지 10년 뒤인 2020년에 추가한 Note Of Reflection 을 확인할 수 있습니다.
이 부분에서는 Git Flow가 웹 앱(web apps) 개발을 염두에 두지 않고 만들어졌고, 적합하지 않다고 회고합니다. 즉 그의 말에 따르면 우리가 일반적으로 작성하는 백엔드, 프론트 애플리케이션은 Git Flow를 사용하기 적합하지 않다는 것이죠.
Git Flow의 어려움
그렇다면 어떤 이유에서 Git Flow가 웹 앱 개발에 적합하지 않다는 것일까요? 제가 생각하는 Git Flow의 어려움은 아래와 같습니다.
A successful Git branching model 에서는 feature
, release
, hotfix
세 가지의 보조 브랜치가 어디서 생성될 수 있으며, 어디로 머지(Merge)되어야 하는지, 그리고 어떤 이름을 가질 수 있는지 상세하게 설명합니다. 이러한 규약을 익히는 것도 어려운 점 중 하나이지만, 규약으로 인해 브랜치 관리의 본질적인 복잡성이 증가하는 것 또한 문제가 됩니다. 이러한 복잡성을 보여주는 예시를 간단히 짚어보자면 아래와 같습니다.
release
와 hotfix
브랜치를 머지하기 복잡합니다. 기본적으로 두 종류의 브랜치는 변경 사항이 덮어씌워지는 것을 방지하기 위해 master
와 develop
에 동시에 머지되어야 하며, 활성화된 release
브랜치가 있다면 이것도 신경써야 합니다.feature
브랜치와 hotfix
브랜치 중 어떤 것으로 해야 할지 판단하기 어렵습니다. 일반적으로는 계획된 기능을 feature
, 계획되지 않은 픽스를 hotfix
로 하지만 이런 분류가 애매해지는 순간이 분명 존재합니다.hotfix
에서 새로 발생한 변경 사항을 feature
브랜치에 적용하고 싶다면, 최소 3번의 머지가 필요합니다. (hotfix
-> master
, hotfix
-> develop
, develop
-> feature
)Git Flow에서는 브랜치가 보통 오래 유지되고, 상대적으로 많은 변경사항을 한 번에 머지하는 것을 선호합니다. 이러한 선호는 여러가지 부작용을 같이 야기합니다.
먼저, 서로 다른 두 브랜치에서 독립적으로 작업을 하게 되면 동시에 수정한 부분이 생길 수 있는데, 이 때 두 브랜치를 머지하기 위해서는 Git 상에서 컨플릭트를 해결해야 합니다. 두 브랜치가 각각 독립적으로 오래 작업되었을수록, 컨플릭트는 보통 더 크고 해결하기 어려워집니다. 컨플릭트 해결 중 발생하는 휴먼 에러로 버그를 만들 확률 또한, 컨플릭트의 규모가 커질수록 같이 증가합니다.
오랫동안 작업한 두 브랜치를 머지하면… 💥
그 뿐만이 아니라, 브랜치가 오래 유지되어서 변경사항이 많을수록, 동료 개발자가 변경사항에 대해 코드리뷰를 진행하기가 더욱 어려워집니다. 동료 개발자가 코드 퀄리티나 버그에 대한 피드백을 주기 어려워지면, 전체적인 개발 문화에도 영향을 주게 됩니다.
코드 리뷰의 아이러니
마지막으로, 브랜치가 오래 유지된다는 것은 자연스레 배포의 주기가 길어진다는 것을 의미합니다. 이는 운영 배포를 통해 실제 환경에서 새롭게 만든 코드와 기능에 대한 피드백을 받는 것을 어렵게 합니다.
트렁크 기반 개발은 Git Flow의 대안으로서 주로 사용되는 브랜치 전략입니다. 트렁크 기반 개발을 소개하는 trunkbaseddevelopment.com에서는 트렁크 기반 개발을 아래와 같이 한 문단으로 설명합니다.
A source-control branching model, where developers collaborate on code in a single branch called ‘trunk’, resist any pressure to create other long-lived development branches by employing documented techniques. They therefore avoid merge hell, do not break the build, and live happily ever after.
일종의 코드 관리 브랜칭 모델이며, 여기서는 개발자들이 ‘트렁크’라고 불리는 단일 브랜치 위에서 협력하고, 오래 유지되는 개발 브랜치를 만들게 하는 압력에 저항하기 위해 위해 설명된 테크닉을 사용합니다. 그러므로 그들은 머지 헬을 피하고, 빌드를 깨트리지 않고, 영원히 행복하게 살아갑니다.
트렁크 기반 개발
한 문단만으로는 설명이 쉽지 않네요. 조금 더 알아볼까요?
트렁크 기반 개발에서는 main
(또는 trunk
)이라는 주 브랜치 하나만 운영합니다. 신규 피쳐는 main
에 바로 커밋하거나, 며칠 내로 main
에 머지할 피쳐 브랜치에서 작업합니다.
main
브랜치에 코드가 머지되었다면, 먼저 자동화된 CI 시스템이 main
브랜치에 대해 테스트 / 통합 과정을 통과하는지 확인합니다. 문제가 없다면, main
브랜치의 코드가 그 즉시 운영 환경에 배포됩니다.
(이는 큰 틀에서 Github Flow와의 실천법과도 일치하기 때문에, Github Flow 또한 트렁크 기반 개발의 일종이라고 할 수 있겠습니다.)
이러한 간단한 방식은 Git Flow의 많은 문제들을 해결합니다.
main
브랜치와 싱크를 맞추는 것만으로도 충분합니다.main
에 머지하는 것만으로 충분합니다. 배포 프로세스가 간단해져서, 더욱 자주 배포할 수 있게 됩니다.이런 간단한 방식으로, 우리는 Git Flow의 어려움을 모두 해결하고 영원히 행복하게 살았답니다. 끝!
…처럼 전래동화 스타일로 끝낼 수 있으면 참 좋았겠지만, 아쉽게도 제 경험상 트렁크 기반 개발 또한 모든 것을 마법처럼 해결하지는 못합니다. 일반적으로 트렁크 기반 개발의 실천법을 실행하다 보면, 아래와 같이 크게 세 가지 상황에서 어려움을 맞닥트립니다.
만들고자 하는 기능이 몇 주 내지는 몇 달의 개발 기간이 필요한 큰 기능일 수 있습니다. 이런 상황에서는 트렁크 기반 개발의 실천법대로 며칠마다 메인 브랜치에 머지하기 어려워집니다.
만들고자 하는 기능 A가 다른 기능 B의 릴리즈에 의존적이라면, B 기능이 완료되기 전까지 A 기능도 배포하기 어렵습니다.
기능을 별도의 스테이지 서버에서 검증하고 배포하는 것이 아니라 바로 실서버로 배포하기 때문에, 잘못된 기능이 메인 브랜치로 머지될 위험이 증가합니다.
트렁크 기반 개발에도 분명히 어려움이 존재하지만, 위의 어려움을 해결하는 나름의 방법 또한 존재합니다. 아래에서 트렁크 기반 개발을 용이하게 하는 세 가지 방법을 설명드리겠습니다. 이 방법들은 서로 상호 보완적이며, 더 많이, 더 잘 도입할수록 트렁크 기반 개발의 어려움을 더 잘 해소할 수 있습니다.
예를 들어서, 한 달이 걸릴 작업 하나를 일주일에 한번 배포하는 방식으로 쪼개서 배포할 수 있습니다. 물론 작업의 유형에 따라 그렇게 하기 상대적으로 더 어려운 경우도 존재하지만, 그렇게 했을 때 얻을 수 있는 이득 또한 분명합니다.
피쳐 토글(Feature Toggle)을 사용한다면, 작성한 코드를 운영 서버에 미리 배포해두고, 이 코드를 실제로 운영 환경에서 실행할지를 원격으로, 별도의 배포 없이 결정할 수 있습니다. 이는 코드의 배치 (deploy)와 기능의 릴리즈 (release)를 분리해서 다룰 수 있게 합니다.
피쳐 토글에 대해 더 자세히 알고 싶으시다면, 제가 작성한 다른 글인 피쳐 토글 - 빠르고 안정적인 릴리즈를 향한 도약도 확인해 보세요!
테스트 코드의 중요성은 트렁크 기반 개발에서도 그 빛을 발합니다.
여기까지가 트렁크 기반 개발에 대한 기본적인 설명이었습니다. 여기까지 읽었을 때 어떤 생각이 드셨나요? 트렁크 기반 개발이 좋아 보여서 적용해보고 싶을 수도 있고, 그래도 설득되지 않아서 Git Flow를 그대로 사용하고 싶을 수도 있습니다.
Git Flow와 트렁크 기반 개발 두 방식 중 어느 하나가 항상 더 좋다고 생각하기 쉽지만, 저는 두 방식 모두 각자의 장점을 취하기 위해 감수하는 단점이 있다고 생각합니다. 아래와 같이 Git Flow와 트렁크 기반 개발이 내포하는 근본적인 가치를 각각 한 문장으로 요약할 수 있습니다.
즉, 트렁크 기반 개발은 간단하고 빠른 배포를 추구하기 위해 정교하고 안정적인 배포를 포기한 것이죠. 따라서 트렁크 기반 개발이 추구하는 간단하고 빠른 배포가 잘 들어맞는 환경을 가지고 있을 때, 트렁크 기반 개발을 도입하는 것을 적극적으로 고려해보면 좋을 것이라고 생각합니다. 예를 들어서..
Git Flow에 한계를 느끼고 있고, 트렁크 기반 개발의 가치에 공감할지라도, 아마 트렁크 기반 개발 도입을 주저하게 되는 가장 큰 이유 중에 하나는 “운영배포하는 것이 두려워서” 일 것이라고 생각합니다. 검증도 안 한 기능을 바로 운영에 올리는 것은 당연히 그 위험성이 존재하고, 그게 두려운 건 어떻게 보면 당연한 반응이라고 생각합니다.
운영 배포가 두렵게 느껴질 때는, 마틴 파울러의 FrequencyReducesDifficulty 글을 읽어보는 것이 도움이 되었습니다. 이 글의 첫 문장에서는 아래와 같이 이야기합니다.
if it hurts, do it more often.
어떤 일이 고통스럽다면, 더 자주 해라.
이 글에서는, 통합은 고통스러운 작업이기 때문에 이를 미룰려고 시도하는 것은 사람이라면 당연한 반응이라고 얘기합니다. 하지만 통합은 미루면 미룰수록 그 난이도가 증가하기 때문에, 오히려 자주 통합해서 자주 고통을 맞이한다면 고통의 총합은 자연스레 줄어들 것이라고 이야기합니다.
통합이 늦어지면 늦어질수록, 통합의 난이도도 같이 빠르게 증가합니다.
만약 배포하는 것이 너무나 무섭고 고통스러운 일이라서 트렁크 기반 개발을 도입하기에 어려움을 느낀다면, 트렁크 기반 개발을 통해 더 자주, 더 작게 배포해서 배포의 고통을 줄여보는 것은 어떨까요?
여기서부터는 맘시터 백엔드팀에서 트렁크 기반 개발을 적용해보면서 얻은 성과를 자랑해보고자 합니다.
맘시터 백엔드팀은 트렁크 기반 개발의 실천법을 따라 main
이라는 주 브랜치 하나를 운용하고 있습니다. 새로운 기능을 만들기 위해서는 main
에서 피쳐 브랜치를 만들어서 작업을 하고, 며칠 내로 PR(Pull Request)을 올려 코드리뷰를 받습니다.
PR이 올라감과 동시에, Github Action을 통해 PR에 대한 테스트와 코드 품질 분석을 자동으로 실행합니다.
테스트와 코드 품질 분석(SonarCloud)가 모두 성공한 모습
테스트가 성공하는 것을 확인 후, PR 작성자는 원하는 시점에 Merge버튼을 눌려 PR을 운영과 스테이지 환경에 동시에 배포할 수 있습니다. 날마다 다르지만, 일반적으로는 하루 평균 5건 내외의 배포가 발생합니다. (백엔드 개발자는 현재 11명입니다.)
Github Action을 통해 최근 배포된 커밋들의 목록
트렁크 기반 개발을 적용하며, 백엔드팀에서 몸소 느낄 수 있었던 장점은 아래과 같습니다.
main
에서만 디버깅하면 충분합니다.이것으로 제 글을 마치겠습니다. 첨언하자면 Git Flow와 트렁크 기반 개발 두 방법 모두 오랜 기간동안 많은 변형이 있었던 전략이고, 위에서 설명한 내용이 모두 항상 들어맞는 것은 아닙니다.
이 글의 내용은 대략적인 소개로 바라봐주시고, 관심이 있으시다면 다른 글들을 더 읽어보시면서 더 알아보시는 것을 추천드립니다!
레퍼런스: