피처 플래그란: 코드베이스 관리 완벽 가이드

요약

피처 플래그는 새 배포 없이 런타임에 기능을 제어하는 if 문입니다. 타입별 수명, 안전한 롤아웃 절차, 기술 부채 방지, 기존 코드베이스에서 플래그 찾기 및 정리하는 법을 배우세요.

엔지니어 책상과 노트북 옆의 토글 스위치

피처 플래그란 새로운 배포 없이 런타임에 코드의 특정 동작을 켜거나 끌 수 있는 조건문입니다. 이게 전부입니다. 실제로는 설정 파일, 데이터베이스 행, 또는 플래그 서비스에서 답을 받아오는 if 문이죠.

개념은 간단합니다. 하지만 저장소에 200개의 플래그가 있으면서 그것들을 관리하는 건 그렇지 않습니다. 이 가이드의 핵심은 바로 두 번째 부분입니다.

코드에서 피처 플래그는 어떻게 보이나요?

가장 최소한의 실용적인 버전입니다:

if (flags.isEnabled("new-checkout", { userId })) {
  return renderNewCheckout();
}
return renderOldCheckout();

두 코드 경로 모두 같은 빌드에 포함됩니다. 플래그 값은 재배포 없이 변경할 수 있는 곳에 있습니다: 환경 변수, JSON 파일, 테이블, 또는 호스팅된 서비스. 값을 바꾸면 다음 평가 때 동작이 바뀝니다.

이 분리가 핵심입니다. 배포는 코드를 서버에 올리는 것입니다. 릴리스는 사용자가 그것을 보게 하는 것입니다. 플래그는 이 두 이벤트를 분리하므로, main에 머지한다는 것이 더 이상 "모두가 지금 바로 이것을 얻는다"를 의미하지 않습니다.

hand flipping a single toggle switch with a green indicator light

팀이 피처 플래그를 왜 사용하나요?

5명에서 50명 규모의 실제 팀에서는 세 가지 이유가 계속 나옵니다.

이 중 어느 것도 벤더가 필요하지 않습니다. 플래그는 설정 테이블의 불린값일 수 있습니다. 백분율 롤아웃, 감시 추적, 엔지니어가 아닌 사람이 토글을 조작하는 기능이 필요할 때까지 플랫폼은 건너뛰세요.

피처 플래그의 네 가지 종류는 무엇인가요?

Pete Hodgson의 광범위하게 인용된 Martin Fowler 사이트의 feature toggles 기사는 플래그를 얼마나 오래 살아있는지, 얼마나 자주 결정이 바뀌는지에 따라 분류합니다. 이 분류들은 여전히 가장 명확한 정신 모델입니다.

수명 열이 가장 중요합니다. 릴리스를 넘어서는 릴리스 플래그는 아직 찾지 못한 버그입니다. 정리 스프린트에서 삭제되는 권한 플래그는 아직 겪지 못한 장애입니다.

플래그를 만들 때 이름과 종류를 지정하세요. 6개월 후에는 아무도 "new-nav-v2"가 어떤 종류인지 기억하지 못할 것입니다.

team planning grid of sticky notes grouped by category

사용자에게 피해 없이 플래그를 어떻게 롤아웃하나요?

단순한 순서가 가장 잘 작동합니다.

  1. 플래그를 끈 상태로 코드를 배포합니다. 아무것도 바뀌지 않았는지 확인합니다.

  2. 여러분의 팀에만 프로덕션에서 활성화합니다. 하루 동안 사용해봅니다.

  3. 사용자의 1%에서 5%에게 활성화합니다. 사용자별로 고정하여 아무도 세션 중에 변형 사이를 오가지 않습니다.

  4. 에러율, 레이턴시, 그리고 하나의 비즈니스 지표를 관찰합니다. 대시보드를 바라보면서가 아니라 시작하기 전에 임계값을 정하세요.

  5. 100%로 확대하고, 정의된 기간 동안 기다린 후, 플래그를 제거합니다.

5단계가 팀들이 건너뛰는 부분입니다. 이것이 여러분이 생각하는 것보다 훨씬 더 비용이 듭니다.

평가에 대한 실용적인 조언: 플래그 읽기를 저렴하고 장애 안전하게 만드세요. 플래그 서비스가 다운되면, 코드에는 기본값이 필요합니다. 플래그별로 목적에 맞게 기본값을 선택하세요. 킬 스위치는 "안전하게" 실패해야 하고, 새 기능은 "꺼진" 상태로 실패해야 합니다.

피처 플래그는 왜 기술 부채가 되나요?

모든 플래그는 코드의 분기입니다. 두 개의 플래그는 4개의 가능한 경로를 만들고, 10개는 1,024개를 만들며, 여러분은 그 중 소수만 테스트했을 가능성이 높습니다. GrowthBook의 플래그 부채 엔지니어링 가이드는 약 75%의 토글 컴포넌트가 도입 후 49주까지 코드베이스에 남아있었다는 연구를 인용하며, 대부분의 개발자는 제거할 계획이었다고 말했습니다.

Hodgson은 같은 Fowler 기사에서 이를 잘 표현합니다: 현명한 팀은 토글을 수용비를 갖는 인벤토리로 취급하고, 그 인벤토리를 낮게 유지하기 위해 작업합니다.

고전적인 공포 이야기는 2012년 Knight Capital입니다. 은퇴한 기능의 플래그가 한 서버의 기존 코드가 여전히 살아있는 동안 새로운 동작에 재사용되었습니다. 그 불일치는 1시간 미만에 대략 4억 6천만 달러의 손실에 기여했습니다. 여러분의 낡은 플래그는 아마도 그렇게 하지 않을 것입니다. 더 조용한 일을 할 것입니다: 아무도 존재하지 않는다고 알지 못했던 분기를 깨뜨리는 리팩터링, 또는 새 직원이 두 체크아웃 경로 중 어느 것이 실제인지 파악하는 데 오후를 보내는 것.

dusty shelf of forgotten boxes and old switches

기존 코드베이스에서 모든 플래그를 어떻게 찾나요?

이것은 벤더 문서가 건너뛰는 질문이며, 대부분의 팀이 막히는 부분입니다. 플래그 대시보드는 무엇이 설정되어 있는지 알려줍니다. 각 플래그가 코드의 어디에서 읽히는지, 또는 "끄기" 플래그 뒤의 코드 경로가 여전히 도달 가능한지는 알려주지 않습니다.

저렴한 방법으로 시작하세요:

# wrapper를 통해 읽혀지는 모든 리터럴 플래그 키
rg -n 'isEnabled\("' src/ | sort

# 정의되었지만 참조되지 않는 플래그
comm -23 <(jq -r 'keys[]' flags.json | sort)          <(rg -o 'isEnabled\("([^"]+)"' -r '$1' src/ | sort -u)

이것은 빨리 부러집니다. 문자열 연결로 만들어진 플래그 키는 grep에서 표시되지 않습니다. 헬퍼 함수를 통해 전달된 플래그는 호출 지점을 숨깁니다. 모노레포와 다중 저장소 설정은 같은 키를 세 개의 서비스에서 읽을 수 있기 때문에 문제를 곱합니다.

도구로 코드를 읽는 것이 도움이 되는 곳입니다. 저장소를 이해하는 코드 검색 도구는 "new-checkout이 어디에서 평가되고 결과에 무엇이 의존하는가?"를 오후의 grep 세션 대신 한 번의 쿼리로 답할 수 있습니다. Cursor와 GitHub Copilot은 한 저장소 내에서 이를 합리적으로 처리합니다. 여러 저장소에 걸쳐서는 모든 저장소를 아우르는 인덱스가 필요하며, 이것이 우리가 codebasechat을 만든 사례입니다.

이성적인 플래그 정리 프로세스는 어떻게 보이나요?

제거를 나중의 잡일이 아니라 일의 일부로 취급하세요.

정적 분석이 여기서도 도움이 됩니다. CodeScene 같은 도구는 가장 복잡한 조건부 논리를 담은 파일을 보여주며, 이것은 보통 오래된 플래그가 모여있는 곳입니다. SonarQube는 체크를 제거한 후 도달할 수 없고 죽은 코드를 표시합니다.

플래그 뒤의 코드를 어떻게 테스트하나요?

테스트는 아무도 예산을 잡지 않는 부분입니다. 플래그당 두 개의 경로로, 테스트 제품군은 둘 다 커버해야 하며, 최소한 위험한 동작을 보호하는 플래그는 그렇습니다.

실용적으로 유지하세요. 라이브 서비스를 읽는 대신 플래그 값을 주입하여 단위 테스트에서 모든 릴리스 플래그의 켜짐과 꺼짐 상태를 테스트합니다. 기본 프로덕션 구성에 대한 하나의 엔드-투-엔드 제품군을 실행하세요. 그러면 사용자가 오늘 얻는 것입니다. 그 다음 릴리스할 기능에 대해 플래그를 켠 상태로 두 번째 통과를 실행합니다.

모든 조합을 테스트하지 마세요. 10개의 플래그로는 할 수 없습니다. 대신 플래그를 독립적으로 유지하세요: 다른 플래그도 켜져 있을 때만 동작을 변경하는 플래그는 설계 냄새이며, 정리할 첫 번째 것입니다.

신입 엔지니어들이 플래그에 대해 뭘 잘못 이해하나요?

주니어들은 같은 세 가지 실수를 하는 경향이 있으며, 각각을 리뷰에서 저렴하게 예방할 수 있습니다.

새 직원의 첫 두 주는 정확히 그들이 소유자가 없는 오래된 플래그를 마주치는 때입니다. 각 항목에 대한 종류, 소유자, 제거 날짜가 있는 짧은 플래그 레지스트리는 몇 시간의 질문을 절약합니다.

피처 플래그를 언제 건너뛰어야 하나요?

플래그는 무료가 아니므로 다음의 경우 건너뛰세요:

변경이 위험하고, 사용자 관련이며, 재배포로 되돌리기 어려울 때 망설임 없이 사용하세요. 결제 흐름, 인증 변경, 그리고 뒤에 데이터 마이그레이션이 있는 모든 것이 해당합니다.

10명 팀에서는 실제로 뭘 하나요?

부울값과 하나의 래퍼 함수를 설정에서 시작하여, 모든 플래그 읽기가 한 곳을 통해 가도록 합니다. 그 단일 병목은 플래그 목록을 grepable하고, 감사할 수 있으며, 나중에 호스팅된 서비스로 쉽게 마이그레이션할 수 있게 만듭니다.

각 플래그를 종류별로 지정하고, 소유자를 지정하고, 첫 날에 제거 티켓을 제출하세요. 월간으로 10분 동안 목록을 검토합니다. 2주 동안 100%에 있었던 플래그들을 삭제합니다.

피처 플래그는 대출입니다. 위험한 릴리스를 구할 때 가져가고, 이자가 다음 리팩터에 나타나기 전에 갚으세요.

자주 묻는 질문

피처 플래그와 토글의 차이는 무엇인가요?
플래그와 토글은 같은 것입니다. Pete Hodgson의 Martin Fowler 기사에서 광범위하게 사용되는 용어는 'feature toggle'이며, 업계는 두 용어를 상호 교환적으로 사용합니다.
플래그가 없으면 테스트하기 어렵나요?
두 경로가 모두 코드에 있을 때, 테스트는 둘 다 커버해야 합니다. 단위 테스트에서 플래그 값을 주입하여 각 상태를 테스트하세요. 프로덕션 기본값으로 하나의 엔드-투-엔드 테스트를 실행하고, 활성화된 기능으로 두 번째를 실행하세요.
플래그가 얼마나 오래 살아있어야 하나요?
유형에 따라 다릅니다. 릴리스 플래그는 며칠에서 몇 주 정도, 실험은 몇 주, 권한은 몇 년이 될 수 있습니다. 생성할 때 타입과 소유자를 지정하고 만료일을 설정하세요.
Knight Capital은 정말로 플래그로 인해 4억 6천만 달러를 잃었나요?
2012년에는 그들이 재사용한 낡은 플래그가 한 서버에서 여전히 기존 코드에 의해 읽혀지고 있었습니다. 불일치가 기여했지만, 이것은 여러 요인 중 하나였습니다. 요점: 낡은 플래그는 진짜 위험입니다.
플래그 검색 도구를 사용하지 않고 플래그를 추적할 수 있나요?
작은 저장소에서는 grep이나 정규 표현식 검색으로 충분합니다. 모노레포나 마이크로서비스 설정에서는 코드 검색 도구(Cursor, GitHub Copilot, 또는 전사 인덱스)가 필요합니다.