혼자하는 개발자는 없다
개발자에게 있어 협업은 필수적인 요소라고 볼 수 있다. (1인 게임개발 같은 특수한 경우는 예외😅)
여기서의 협업은 개발자끼리의 협업 뿐 아니라 도메인 현직자, 설계자, 마케팅 등 모든 분야와의 교류를 포함하는 의미이다.
이번 글에서는 그 중에서도 개발자 사이의 협업에 대해서 알아보자
혼자서 하는 개발에는 공유 체계가 필요없다. 다 기억해내고 히스토리를 기록하면 될 일이다.
그런데 사람이 모든 것을 기억 할 수는 없는 노릇이지 않은가
그래서 고안해낸 것이 로컬 형상 관리 시스템이다. (Local Version Controll System : Local VCS)
이 로컬 형상 관리 시스템으로 버젼을 관리하여 수정 내역을 간편하게 관리 할 수 있다.
그런데 문제가 있다. 여러명이서 하나의 프로그램을 만드는데 모두 각자의 로컬 형상을 관리하면 어떻게 하나로 합쳐서 프로그램을 완성시킬 것인가? 벌써 머리가 아프다
개발한 코드가 뒤죽박죽 되어 프로그램이 난장판이 될것이다.
그래서 나온 것이 중앙 집중식 형상 관리 시스템 (Centralized VCS) 이다.
하나의 무결한 형상 관리 서버를 두고 그 서버에 여러 개발자가 코드를 체크아웃 받고 수정하여 커밋 하는 방식을 사용한다.
- 체크아웃 : 소스 코드를 가져와서 수정할 수 있는 상태
- 커밋 : 변경된 코드를 저장
대표적인 툴로 Subversion(SVN) 이 있다. 본인도 실무에서 이 SVN을 사용하기도 했다.
그런데 하나의 서버를 사용한다는 것에서 드는 우려가 있을 것이다.
그렇다 이 하나의 중앙 서버에 지나치게 의존적이라는 점이다. 중앙 서버에 문제가 생기거나 네트워크 연결이 끊기면 협업 자체가 힘들어지게 될 것이다.
그 점을 해결하고자 나온 것이 분산 형상 관리 시스템(Distributed VCS) 이다.
이 DVCS는 각 개발자들이 로컬 환경에 전체 코드 레파지토리의 복사본을 가져와 작업을 진행하는데
각 개발자의 로컬 레파지토리는 고유하게 각각의 완전한 히스토리와 버젼을 가지고 있다.
필요에 따라 원격 레파지토리에 변경 사항을 푸시하는 방식으로 사용된다.
- 푸시 : 변경된 코드 원격 레파지토리에 병합하는 것
이러한 특성 덕분에 네트워크 연결이 끊기더라도 크게 문제 없이 작업을 진행 할 수 있고
각자가 맡은 분야를 더 확실하게 구분지어 협업 할 수 있다.
대표적인 DVCS로는 Git이 있으며 이 Git을 기반으로 한 GitHub, GitLab, Bitbucket 등의 웹 호스팅 서비스가 존재한다.
🤔Git은 뭐가 다를까 ?
CVCS(중앙집중형)가 가지는 큰 한계점 중 하나는 커밋의 단위가 모호하다는 것이다.
하나의 큰 기능을 개발하는 것을 커밋 단위로 정하고 중앙서버에 Merge 하자니 Merge 까지의 시간이 오래걸리고 그 사이 다른 개발자들이 개발해서 Merge한 소스와 충돌이 날 수 있는 상황이 많고
그렇다고 내가 개발중인 기능을 부분적으로 커밋하여 Merge 하자니 커밋 자체가 의미를 가지기 힘들고 해당 기능에서 문제가 생겼을 경우 원인을 찾는 과정에서 중간중간 섞인 커밋들 때문에 어떤 부분을 봐야하는지 찾기가 힘들다.
Git은 이러한 문제를 해결하기 위해 브랜치 라는 기능을 사용한다.
브랜치?
그렇다. 나뭇가지란 뜻이다(?) 뻗어나가는 모양을 하고 있어 이러한 이름이 붙었는데
이런식으로 중심 줄기를 기준으로 여러 브랜치들이 생성되는 구조인데
그래서 브랜치가 하는 것이 무엇이냐 하면
- Git의 핵심 기능 중 하나로 독립적인 작업 영역을 생성하여 코드의 변경을 관리하는 기능이다.
거창하게 말했지만 결론적으로는 개발자가 코드를 작업할 수 있는 개별적인 작업 공간을 의미한다.
위의 그림에서 각 가지가 독립적인 작업 영역이 되는 것이다.
개발자들은 본인이 맡은 기능 단위로 브랜치를 생성하여 작업을 진행하고
작업이 끝나면 메인 브랜치(master)에 Merge 한다.
이렇게 브랜치로 관리가 되면 특정 기능에 문제가 생겼을 경우
해당 기능을 개발한 브랜치를 추적하면 되기 때문에 원인 파악이 쉽고 그로 인해 빠르게 문제를 해결 할 수 있다.
그런데 이런 브랜치를 정해진 규칙 없이 마음대로 생성하게 된다면 무분별하게 생성된 브랜치로
오히려 복잡해 알아보기 힘든 구조가 될 것이다.
그래서 브랜치들을 어떻게 구성하고 관리할지 약속을 정해야 하는데
이러한 약속을 정하는 행위를 두고 "브랜치 전략을 정한다" 라고 한다.
협업 단계에서 브랜치 방법론에 대한 커뮤니케이션을 최소화 하고
브랜치의 안정성 보장과 배포 관리의 기반을 제공하기 위해
상황에 맞는 브랜치 전략을 선택하는 것이 매우 중요하다.
Git 브랜치 전략에는 중앙집중식 워크플로우, 기능 브랜치 전략, Git-Flow, GitHub-Flow, Gitlab-Flow 등
여러가지가 있는데
우리는 그 중에서도 가장 많이 다뤄지고 사용되는 Git Flow 와 GitHub Flow에 대해서 알아보고 우리가 진행하는 프로젝트에서는 어떤 방식을 채택 할 지 고민해보자
Git-Flow
Vincent Driesson이 2010년에 제시한 Git 브랜치 전략으로
- master : 제품으로 출시될 수 있는 브랜치
- develop : 다음 출시 버전을 개발하는 브랜치
- feature : 기능을 개발하는 브랜치
- release : 이번 출시 버전을 준비하는 브랜치
- hotfix : 출시 버전에서 발생한 버그를 수정 하는 브랜치
이렇게 총 5개의 브랜치를 사용하는 전략이다.
Vincent Driesson이 제시한 Git Flow 브랜치 전략의 그성도는 다음과 같다.
시작은 기본적으로 master 브랜치로부터 시작된다.
master 브랜치가 현재 운영되고 있는 코드가 관리되는 브랜치이고
master 브랜치에서 뻗어나온 develop 브랜치에서 개발 작업들이 이루어진다.
가장 핵심이 되는 브랜치가 이 두가지 브랜치라고 볼 수 있다.
develop 브랜치에서는 버그를 고치는(시스템에 치명적이지 않은) 커밋이 상시로 일어난다.
그러다 새로운 기능 개발을 해야하는 경우 develop 브랜치로부터 feature 브랜치를 만들게된다.
이 feature 브랜치에서 기능을 개발하고 기능 구현이 완료된 feature 브랜치는 develop 브랜치로 merge(병합)된다.
merge 된 devleop 브랜치에서는 테스트를 거쳐 하나의 릴리즈를 준비하고 이 준비가 완료되면 develop 브랜치를 release 브랜치에 merge 한다.
merge 된 release 브랜치에서는 자잘한 버그 수정을 거쳐 실제 배포 가능 한 코드가 되면 릴리즈 프로그램을 배포하고 master 브랜치에 최종 merge된다.
이런 기본적인 프로세스 중 즉시 수정해야하는 치명적인 버그들은 hotfix 브랜치를 통해 수정 후 develop 브랜치를 거치지 않고 master 브랜치로 바로 merge 된다.
이렇게 총 5가지의 브랜치를 사용하는데 딱 봐도 알겠지만 상당히 복잡하다..
그리고 몇가지 의문이 들 것이다.
- release 브랜치는 hotfix 브랜치와 merge 하지 않는 것인가 ❓
- 웹 프로그램은 release 프로그램 시스템을 잘 활용 할까 ❓
Git-Flow 전략이 2010년에 화두가 된 후로 수 많은 프로젝트에서 이 Git Flow 전략을 바탕으로 Git을 관리해왔다.
그러다보니 어쩌면 개발중인 환경과 잘 맞지 않음에도 이 전략을 채택하는 경우도 더러 있었을 것이다.
이를 의식이라도 한 듯
2010년에 작성된 Vincent Driesson 블로그의 Git-Flow 전략 글에는
2020년에 다음과 같은 글이 추가되었다.
https://nvie.com/posts/a-successful-git-branching-model/
A successful Git branching model
In this post I present a Git branching strategy for developing and releasing software as I’ve used it in many of my projects, and which has turned out to be very successful.
nvie.com
요약하자면
Git-Flow 전략 모델은 Git 자체가 등장한지 얼마 되지 않았을 때 고안 한 것이며
웹 처럼 지속적으로 수정되고 다양한 버젼이 필요 하지 않은 소프트웨어에서는 적합 하지 않을 수 있다는 내용이다.
🧐 왜 적합하지 않다는 것일까? 🧐
5개의 브랜치 전략을 사용함으로써 반영되는 과정에서 많은 절차를 거쳐야하고
지속적인 배포와 작은 단위의 변경이 자주 일어나는
웹 어플리케이션 특성 상 이런 많은 절차들은 발목을 잡기 쉬운 구조인 것이다.
물론 Git-Flow 를 사용해도 문제 없지만 여기서 적합하지 않다는 것은 더 나은 전략이 있다는 것을 의미한다.(본문에서도 나와있듯)
🤨 : 그럼 더 나은 전략이 뭔데 ??
바로 GitHub-Flow다.
GitHub-Flow : 간단하게 합시다.
GitHub-Flow에는 Git-Flow와 다르게 master 브랜치 하나에서만 정식 버젼이 관리된다.
그리고 기능 추가가 필요한 경우 feature branch를 사용하여 기능을 개발하고 즉각적으로 master 브랜치에 merge 처리한다.
GitHub-Flow는 단일 브랜치 위에서 협력하고, 브랜치가 오래 유지되지 않도록 하는 전략 트렁크 기반 개발( TBD : Trunk-based development )의 사상을 기본적으로 따르는데 여기서의 Trunk가 master 브랜치를 의미한다.
GitHub-Flow는 다음과 같은 특징을 갖는데
- 지속적인 배포와 간단한 협력 규칙 👉🏼 직관적인 워크플로우를 제공
- 빠른 피드백과 지속적인 통합 👉🏼 변화에 유연하게 대응
이러한 특징 덕분에 지속적인 배포와 작은 단위의 변경이 자주 일어나는 웹 어플리케이션 환경에서 사용하기 적절하다.
물론 모든 전략이 그렇듯 장점만 있는 것은 아니다.
- 체계적이지 않고 자유분방한 코드 관리 👉🏼 오히려 직관적이지 않은 워크플로우가 될 수 있음
- master 브랜치의 불안정성 👉🏼 릴리즈 준비와 버그 수정을 모두 master 브랜치에서 direct로 처리
이러한 단점들에도 불구하고 이 GitHub-Flow를 채택하는 이유는
웹 어플리케이션이 추구하는 방향인 CI/CD 통합과도 잘 어울리는 전략이기 때문이다.
여기서 CI/CD는 앞서 계속해서 말하던
지속적인 통합(Continuous Integration)과
지속적인 배포(Continuous Delivery)를 의미하는데
소프트웨어 개발 생명주기에서 자동화된 빌드, 테스트, 배포 등의 활동으로 개발자들이 더욱 빠르고 안정적인 방식으로 소프트웨어를 개발하고 제공할 수 있도록 돕는다 정도로만 알고 넘어가자.
🧐 그럼 뭘 쓰란거지?
모든 상황에서 정답인 전략은 없다.
- 대규모의 시스템이나 체계적인 관리가 필요한 시스템에서는 Git-Flow 전략을
- 상시로 배포하고 지속적으로 통합을 하는 시스템에서는 GitHub-Flow 전략을
- 이도 저도 아니라면 두가지 전략을 섞어서 속한 개발 팀 만의 전략을
채택하면 될 것이다.
실제로 본인의 경우에도 곧 진행하게 될 사이드 프로젝트에서 팀원과의 상의를 통해
Git-Flow 전략은 너무 무겁고 GitHub-Flow 전략은 너무 간단하니
GitHub-Flow 전략에 Develop 브랜치만 추가로 하여
Master, Develop, Feature 3가지 브랜치로 관리하는 전략을 선택하기로 했다.
이 외에도 다양한 전략들이 있으니
현재 브랜치 전략 수립에 대해서 고민중이거나 팀에서 브랜치 전략을 변경해야 하는 상황이라면
상황에 맞는 전략을 찾아보는 것을 권장한다.