feature flag는 무엇을 해결하는가 — 단일 브랜치 협업과 구글식 트렁크 개발의 오해#

2026-06-28

단일 브랜치 협업과 feature flag

회사의 웹 서비스 저장소에서 한 가지 실험을 해본 적이 있습니다. 협업자들이 각자 작업 브랜치를 만들고 PR(Pull Request, 변경을 본 브랜치에 합치기 전 검토를 거치는 단위)을 올리는 전통적인 과정 없이, 모두가 기본 브랜치(develop)에 직접 push하는 방식이었습니다.

전통적인 개발에서는 지양하는 방식이지만, AI 에이전트가 개발의 상당 부분을 담당하는 환경에서는 브랜치와 PR을 만드는 절차 자체가 불필요한 병목일 수 있다는 가설이었습니다. 사람이 일일이 리뷰하지 않아도 CI(Continuous Integration, 코드가 합쳐질 때 자동으로 빌드·테스트를 돌리는 시스템)가 품질을 보장해 줄 것이라는 기대였습니다.

그런데 막상 적용해 보니 문제가 드러났습니다. 그래서 “직접 push를 제한하고 PR 기반으로 돌아가자"는 프로세스 개선을 건의했는데, 단일 브랜치 방식을 지지하던 동료가 feature flag라는 개념을 언급했습니다. 구글 같은 회사도 하나의 브랜치를 함께 쓰는데, 그 비결이 feature flag라는 취지였습니다.

이 글은 그 대화에서 출발합니다. feature flag란 무엇인지 쉽게 설명하고, 그것이 단일 브랜치 직접 push에서 생긴 문제들을 실제로 해결해 주는지 따져봅니다.

먼저, 무엇이 문제였는가#

단일 브랜치 직접 push에서 겪은 문제는 크게 다섯 가지였습니다.

  • 동시 쓰기 충돌: 여러 사람이 거의 동시에 develop에 push하면, 잠금장치 없이 공유 자원을 동시에 수정하는 것과 비슷한 상태가 됩니다. 병합 순서가 꼬입니다.
  • 사후 검증이 되는 CI: CI가 “합치기 전 검사"가 아니라 “이미 합쳐진 뒤의 검사"가 됩니다. 실패하면 이미 공유 브랜치가 망가진 상태에서 수습해야 하므로 비용이 큽니다.
  • 조합 실패: 변경 A와 B가 각각은 통과해도, develop + A + B 조합에서는 실패할 수 있습니다. 누가 책임지고 무엇을 검증해야 하는지 흐려집니다.
  • 프론트엔드/백엔드 배포 타이밍 불일치: 두 저장소가 같은 시점에 배포되어야 하는데, 한쪽이 지연되면 호환성이 깨질 위험이 있습니다.
  • 배포 중 기준 시점 흔들림: developmain으로 합쳐 배포하는 도중에도 develop이 계속 바뀌어, 배포 대상 코드의 기준 시점이 흔들립니다.

이 문제들을 머릿속에 두고 feature flag를 살펴보겠습니다.

feature flag란 무엇인가#

feature flag(기능 플래그, feature toggle이라고도 합니다)는 한마디로 코드 안에 박아둔 런타임 on/off 스위치입니다.

if (flags.isEnabled("new_checkout_ui")) {
  renderNewCheckout();   // 새 기능
} else {
  renderOldCheckout();   // 기존 동작
}

핵심은 이 flags.isEnabled(...) 값이 코드 배포와 무관하게 바뀐다는 점입니다. 설정 시스템이나 원격 config 서버에서 값을 바꾸면, 다시 배포하지 않고도 기능이 켜지고 꺼집니다.

비유하자면 집을 지을 때 방을 미리 다 만들어 두되, 아직 공개하지 않을 방은 문을 잠가 두는 것과 같습니다. 방(코드)은 이미 건물 안에 있지만, 열쇠(flag)를 돌리기 전까지는 아무도 들어가지 못합니다. 새 방을 쓰게 하고 싶으면 건물을 다시 짓는 게 아니라 열쇠만 돌리면 됩니다.

구글은 왜 feature flag를 쓰는가#

구글은 거대한 단일 저장소에 수많은 개발자가 하나의 브랜치(흔히 trunk 또는 head라고 부릅니다)에 계속 커밋하는 방식, 이른바 트렁크 기반 개발(trunk-based development)을 합니다.

이런 환경이 굴러가려면 아직 완성되지 않았거나 위험한 기능도 일단 그 하나의 브랜치에 넣을 수 있어야 합니다. 그래서:

  • 미완성 기능은 flag를 꺼둔 채로 병합합니다. 브랜치에는 들어가 있지만 사용자에게는 보이지 않습니다.
  • 기능이 준비되면 flag를 켭니다. 배포 없이 활성화됩니다.
  • 문제가 생기면 flag를 끕니다. 즉시 되돌릴 수 있습니다(kill switch).

여기서 가장 중요한 개념이 배포(deploy)와 출시(release)의 분리입니다.

구분의미
Deploy(배포)코드가 서버에 올라가는 것. 이때 flag는 꺼져 있어 사용자에게는 변화가 없음
Release(출시)flag를 켜서 사용자가 실제로 새 기능을 쓰게 되는 것

이 둘을 분리하면 코드는 미리 올려두고 출시 타이밍만 따로 조절할 수 있습니다. 점진적 롤아웃(1% → 10% → 100%), A/B 테스트, 카나리 배포, 즉시 롤백이 전부 여기서 나옵니다.

흔한 오해: 단일 브랜치 = 검증 없는 직접 push?#

동료가 “구글도 하나의 브랜치를 쓴다"고 말한 부분은 사실입니다. 그러나 여기에 중요한 오해가 숨어 있습니다. 구글의 트렁크 기반 개발은 결코 “검증 없이 직접 push"가 아닙니다.

구글은 하나의 브랜치에 코드를 커밋하기 전에 다음을 강제합니다.

  • 모든 변경에 코드 리뷰 필수 — 승인 없이는 반영 자체가 불가능합니다.
  • 사전 검증(pre-submit) 테스트 — 브랜치에 들어가기 전에 자동 검증을 통과해야 합니다.
  • 반영 큐(submit queue) — 실제로 합쳐질 조합을 검증하고 순서대로 반영합니다.

즉 구글의 “단일 브랜치"는 “합치기 전에 줄 세우고 검사하는 문지기"를 이미 다 깔아둔 위에서 돌아갑니다. 이것은 직접 push 방식을 개선하려고 제안한 “PR 사전 검증 + 반영 큐"와 사실상 같은 구조입니다. feature flag는 그 위에 얹는 별개의 도구일 뿐입니다.

다시 말해 구글 사례는 직접 push 방식을 옹호하는 근거가 아니라, 오히려 PR 기반 사전 검증을 도입하자는 제안을 뒷받침합니다. 구글조차 검증 없는 직접 push는 하지 않습니다.

작업 브랜치도 PR도 없이 어떻게 검증하는가#

여기서 자연스러운 의문이 생깁니다. 구글이 작업 브랜치를 만들고 PR을 올리는 방식이 아니라면, 대체 무엇을 보고 리뷰하고 무엇을 사전 검증한다는 걸까요?

먼저 논리적으로 분명히 해둘 것이 있습니다. “공유 브랜치에 직접 push"와 “합치기 전 검증"은 동시에 성립할 수 없습니다. 코드가 공유 브랜치에 올라간 순간, 검증은 정의상 사후 검증이 됩니다. 그러니 합치기 전에 리뷰와 검증을 하려면, 변경이 공유 브랜치에 닿기 전에 잠시 머무는 격리된 공간이 반드시 있어야 합니다. 이 격리 공간이 git 세계에서는 “작업 브랜치 + PR"이고, 구글에서는 이름만 다를 뿐 같은 역할을 하는 장치가 따로 있습니다.

구글은 git이 아니라 자체 버전 관리 시스템을 쓰는데, 변경의 흐름을 git/GitHub와 나란히 놓으면 거의 일대일로 겹칩니다.

구글의 단위역할git/GitHub 대응
Workspace(개인 작업 공간)변경이 머무는 곳. 아직 공유 브랜치(trunk)에 없음작업 브랜치
CL(Changelist, 변경 묶음)검토·제출의 단위PR
코드 리뷰 도구승인 없이는 제출 불가PR 리뷰
사전 검증(pre-submit) 테스트trunk에 들어가기 전에 돌리는 자동 검증required checks
Submit(제출)검증을 통과한 변경을 trunk에 반영merge

흐름으로 쓰면 양쪽이 사실상 같은 구조라는 것이 드러납니다.

[구글]   개인 작업 공간에서 변경(CL) → 리뷰 승인 → 사전 검증 통과 → trunk에 제출
[GitHub] 작업 브랜치에서 변경(PR) → 리뷰 승인 → required checks 통과 → 본 브랜치에 merge

CL이 곧 PR이고, 개인 작업 공간이 곧 작업 브랜치이며, 사전 검증이 곧 required checks입니다. 부르는 이름과 도구만 다를 뿐입니다.

그래서 “트렁크 기반 개발"이 뜻하는 것은 검증 단계를 없앤다가 아니라 갈라진 가지의 수명과 크기를 줄인다는 것입니다. 전통적 방식의 문제는 “브랜치와 PR이 있다"가 아니라 “브랜치가 몇 주씩 떨어져 살며 공유 브랜치와 멀어진다"였습니다. 트렁크 기반 개발은 변경을 작게 쪼개 하루 안에 자주 합쳐 그 거리를 좁히는 것이지, 리뷰와 사전 검증이라는 문지기를 치우는 것이 아닙니다.

결론적으로 “PR 없이 직접 push하면서 사전 검증도 한다"는 것은 존재할 수 없는 조합입니다. 사전 검증을 하려면 변경이 잠시 머무는 격리 단위가 필수이고, 그 단위가 곧 PR(또는 구글의 CL)이기 때문입니다.

feature flag가 푸는 문제와 풀지 못하는 문제#

그렇다면 feature flag는 앞서 정리한 다섯 가지 문제를 해결할까요? 핵심은 feature flag와 git 협업 문제가 서로 다른 층(layer)에서 작동한다는 점입니다. feature flag는 “이 코드 경로를 실행할지 말지"를 정하는 런타임 동작의 도구이고, 앞의 문제 대부분은 “코드가 공유 브랜치에 어떻게 들어오는가"라는 git의 동시성·검증 문제입니다.

문제feature flag로 해결되는가이유
동시 push 충돌❌ 거의 못 함flag는 코드 안의 조건문일 뿐, 두 사람이 동시에 push할 때의 충돌·순서 꼬임과 무관
CI가 사후 검증이 됨❌ 못 함깨진 코드가 들어가면 빌드·테스트는 그대로 깨짐. flag도 “공유 브랜치가 망가진 상태"는 못 막음
조합 실패🔸 부분적두 기능이 각각 flag 뒤에 격리되면 런타임 충돌은 줄지만, 빌드·타입·통합 실패는 그대로 발생
프론트/백 배포 타이밍✅ 핵심 해결flag의 본업. 백엔드를 먼저 배포(flag off)하고, 프론트를 배포한 뒤, flag를 켜는 순서로 안전하게 맞춤
배포 중 기준 시점 흔들림🔸 간접 완화배포와 출시가 분리되어 “배포 = 즉시 노출"의 긴장은 줄지만, 병합 순서 문제 자체는 남음

가장 아팠던 세 가지(동시 충돌, 사후 CI, 조합 실패)는 feature flag가 거의 손대지 못합니다. 이 문제들은 본질적으로 git의 병합 모델과 CI 실행 시점의 문제이기 때문입니다. flag는 출시한 기능을 사용자에게 보여줄지 정하는 스위치이고, 우리가 필요로 했던 것은 코드가 공유 브랜치에 들어오기 전에 줄 세우고 검사하는 문지기였습니다. 둘은 서로 다른 일을 합니다.

feature flag가 진짜 빛나는 곳#

반대로 프론트엔드와 백엔드의 배포 타이밍 문제에서는 feature flag가 정석 해법입니다. 두 저장소를 같은 순간에 배포해 타이밍을 맞추는 것은 까다로운 일인데, feature flag를 쓰면 동시 배포 자체가 필요 없어집니다.

  1. 백엔드에 새 API를 flag가 꺼진 상태로 먼저 배포합니다. 아직 아무도 호출하지 않습니다.
  2. 프론트엔드를 나중에 여유 있게 배포합니다.
  3. 양쪽이 다 준비되면 flag만 켭니다. 그 순간 새 기능이 동시에 활성화됩니다.

배포 순서와 타이밍을 코드 출시에서 떼어내기 때문에, “반드시 동시에 배포해야 한다"는 제약 자체가 사라집니다. 이 부분은 브랜치 전략 논쟁과 별개로 도입할 가치가 충분합니다.

결론: 양자택일이 아니다#

feature flag와 PR 기반 사전 검증은 둘 중 하나를 고르는 문제가 아닙니다. 서로 다른 축의 도구이며, 함께 쓰는 것이 맞습니다.

  • 단일 브랜치 직접 push에서 가장 아팠던 문제들(동시 충돌, 사후 CI, 조합 실패)은 PR 사전 검증과 반영 큐로만 풀립니다. 구글이 단일 브랜치로 굴러가는 진짜 이유도 feature flag가 아니라 바로 이 문지기 장치들입니다.
  • feature flag는 그 문제들을 풀어주지는 않지만, 프론트엔드/백엔드 배포 분리와 점진적 출시, 즉시 롤백이라는 다른 가치를 얹어줍니다. 이건 무조건 도입할 만합니다.

동료에게는 이렇게 정리해 전하면 좋겠습니다. feature flag는 좋은 도구이고 우리도 도입하자, 다만 그것은 검증 없는 직접 push를 정당화하는 근거가 아니라 배포 분리와 점진 출시를 위한 별도의 도구다. 정작 구글이 단일 브랜치로 굴러가는 비결은 flag가 아니라 합치기 전의 리뷰와 테스트와 큐인데, 그게 바로 우리가 PR로 도입하자고 제안한 것이다.

좋은 도구를 도입하는 것과, 그 도구가 실제로 어떤 문제를 푸는지 정확히 아는 것은 다른 일입니다. feature flag는 분명 강력하지만, 그것이 풀어주는 문제와 풀어주지 못하는 문제의 경계를 분명히 할 때 비로소 제값을 합니다.