GitLab 개발에서의 피처 플래그

caution
이 문서는 GitLab 제품의 개발과 운영에 기여하는 방법에 대해 설명합니다. 만약 여러분이 자신의 애플리케이션에서 기능을 표시하고 숨기기 위해 피처 플래그를 사용하려면, 대신 이 피처 플래그 정보를 참조하세요.
caution
새롭게 도입된 피처 플래그는 기본적으로 비활성화되어야 합니다.
caution
새롭게 도입된 피처 플래그는 액터를 사용하여 사용되어야 합니다.

블루프린트:

이 문서는 피처 플래그의 내부 사용을 개선하기 위한 에픽의 일환으로 계속 작업 중입니다. 어떤 제안이라도 새로운 문제로 제기하고 그것들을 에픽에 첨부하세요.

피처 플래그 라이프사이클 개요피처 플래그를 사용해야 하는지 여부를 결정하는 데 도움이 필요하다면 핸드북 페이지를 참조하세요.

피처 플래그를 사용해야 하는 경우

핸드북의 “피처 플래그를 사용해야 하는 경우” 섹션으로 이동했습니다.

GitLab 개발에서의 피처 플래그

다음 하이라이트는 피처 플래그를 사용해야 하는지 결정할 때 고려해야 합니다:

  • 피처 플래그는 기본적으로 비활성화되어야 합니다.
  • 피처 플래그는 가능한 한 짧은 기간 동안 코드베이스에 유지되어야 합니다. 피처 플래그 회계의 필요성을 줄이기 위해.
  • 피처 플래그를 운영하는 사람은 피처 플래그 뒤의 기능의 상태를 문서와 다른 이해 관계자들과 명확히 커뮤니케이션해야 합니다. 이슈 설명은 피처 플래그 이름과 해당 피처 플래그가 켜져 있는지 끌 때까지 반드시 업데이트되어야 합니다.
  • 피처 플래그를 도입하거나 상태를 업데이트하거나 기존 피처 플래그를 제거하는 Merge Request는 반드시 ~"feature flag" 라벨이 지정되어야 합니다.

기능 구현이 여러 개의 Merge Request를 통해 제공될 때:

  1. 첫 번째 피처 플래그가 사용된 첫 번째 Merge Request에서 기본적으로 비활성화된 채 새로운 피처 플래그를 만들어 주세요. 플래그는 별도로 추가되어서는 안 됩니다.
  2. 하나 이상의 Merge Request를 통해 점진적인 변경을 제출하면서 새로 추가된 코드가 피처 플래그가 활성화된 경우에만 도달할 수 있도록 보장하세요. 개발 중에 로컬 GDK에서 피처 플래그를 활성화한 상태를 유지할 수 있습니다.
  3. 해당 기능이 다른 팀원들에 의해 테스트될 준비가 되면, 초기 문서를 작성하세요. 피처 플래그에 대한 상태에 대한 세부 정보를 포함하세요.
  4. 특정 그룹/프로젝트/사용자를 위해 피처 플래그를 활성화하고 구현에 문제가 없는지 확인하세요. 문서가없는 경우 gitlab-org/gitlab와 같은 공개 프로젝트에 대해서 피처 플래그를 활성화하지 마세요. 팀원 및 기여자는 공개 프로젝트에서 활성화된 기능의 사용 방법에 대해 검색할 수 있습니다.
  5. 해당 기능이 운영에 적합해졌을 때, 다음을 수행하기 위해 Merge Request를 오픈하세요:
    • 최신 플래그 상태를 설명하는 문서를 업데이트하세요.
    • 변경 로그 항목을 추가하세요.
    • 새로운 동작을 활성화하려면 피처 플래그를 제거하거나 피처 플래그를 기본적으로 활성화하도록 전환하세요(ops 및 베타 피처 플래그의 경우에만).

피처 플래그 제거가 여러 개의 Merge Request를 통해 제공될 때:

  1. 피처 플래그의 값 변경은 Merge Request에서 유일한 변경이어야 합니다. 피처 플래그가 코드베이스에 존재하는 한 두 상태가 완전히 기능해야 합니다(기능이 켜고 꺼진 경우).
  2. 피처 플래그에 대한 모든 언급이 제거된 후에, 레거시 코드를 제거할 수 있습니다. 피처 플래그 롤아웃 문제의 단계는 따라야 하며, 단계를 건너 뛰어야 하는 경우, 왜 그렇게 해야 하는지에 대한 설명을 이슈에 추가해야 합니다.

피처 플래그는 적어도 한 달 (= 한 릴리스) 동안 특정 기능의 출시를 지연시킬 것으로 생각될지 모르겠지만, 실제로는 그렇지 않습니다. 피처 플래그는 특정 기간 동안(예: 최소한 하나의 릴리스) 기다릴 필요가 없으며, 대신에 해당 기능이 안정적이라고 판단될 때까지 유지되어야 합니다. 안정적이라 함은 이상 무엇을 일으키지 않고(GitLab.com에서의 장애와 같은 문제를 일으키지 않으면서) 문제없이 작동한다는 것입니다.

깨진 기본 브랜치의 위험

피처 플래그는 도입하는 MR에서 사용되어야 합니다. 그렇지 않으면 기본 브랜치가 깨질 수 있습니다(깨진 마스터 참조).

피처 플래그 유형

예상되는 사용에 맞는 피처 플래그 유형을 선택하세요.

gitlab_com_derisk 유형

gitlab_com_derisk 피처 플래그는 GitLab.com 배포를 위해 위험을 줄이는 데 사용되는 단기간 피처 플래그입니다. GitLab에서 사용되는 대부분의 피처 플래그는 gitlab_com_derisk 유형입니다.

제약 조건

  • default_enabled: 반드시 true로 설정하지 마세요. 이 유형의 피처 플래그는 GitLab.com의 위험을 감소시키는 것을 목적으로 하므로, GitLab.com에서 활성화된 후에는 더 이상 코드베이스에 피처 플래그를 유지할 필요가 없습니다. default_enabled: true는 이 유형의 피처 플래그에는 영향을 주지 않습니다.
  • 최대 수명: 기본 브랜치에 Merge된 후 2개월
  • 문서: 이 유형의 피처 플래그는 짧은 수명을 가지고 배포 관련이기 때문에 GitLab의 모든 피처 플래그 페이지에 문서화될 필요가 없습니다.
  • 롤아웃 이슈: 반드시 피처 플래그 롤아웃 템플릿에서 생성된 롤아웃 이슈가 있어야 합니다.

사용법

gitlab_com_derisk 피처 플래그의 형식은 Feature.<state>(:<dev_flag_name>)입니다.

이를 활성화하거나 비활성화하려면 GitLab Rails 콘솔에서 다음을 실행하십시오.

# 인스턴스에 대해 활성화하려면:
Feature.enable(:<dev_flag_name>)

# 인스턴스에서 비활성화하려면:
Feature.disable(:<dev_flag_name>)

# 특정 프로젝트에 대해 활성화하려면:
Feature.enable(:<dev_flag_name>, Project.find(<project id>))

# 특정 프로젝트에서 비활성화하려면:
Feature.disable(:<dev_flag_name>, Project.find(<project id>))

gitlab_com_derisk 피처 플래그의 상태를 확인하려면:

# 피처 플래그가 활성화되었는지 확인
Feature.enabled?(:dev_flag_name)

# 피처 플래그가 비활성화되었는지 확인
Feature.disabled?(:dev_flag_name)

wip 유형

일부 기능은 복잡하여 여러 MR(Merge Request)를 통해 구현해야 합니다. 완전히 구현될 때까지 누구에게도 표시되지 않아야 합니다. 이 경우 wip(“작업 진행 중”의 약자) 피처 플래그를 사용하여 아직 기능을 사용하지 않은 채로 모든 변경 사항을 기본 브랜치에 Merge할 수 있습니다.

기능이 완료되면, 피처 플래그 유형을 gitlab_com_derisk 또는 beta 유형으로 변경할 수 있습니다. 이는 기능이 고객에게 어떻게 제시/문서화될지에 따라 달라집니다.

제약 사항

  • default_enabled: true로 설정해서는 안 됩니다. 필요한 경우, 이 유형은 기능이 완료되면 beta 유형으로 변경할 수 있습니다.
  • 최대 유지 기간: 기본 브랜치에 Merge된 후 4개월
  • 문서: 이 유형의 피처 플래그는 대부분 완료되지 않은 코드를 숨기므로 GitLab의 모든 피처 플래그 페이지에 문서화할 필요가 없습니다.
  • 롤아웃 이슈: 아마도 사용 여부를 예측하기 어려워 wip 피처 플래그는 활성화되기 전에 다른 유형으로 전환되어야 합니다.

사용법

# 피처 플래그를 활성화했는지 확인
Feature.enabled?(:my_wip_flag, project)

# 피처 플래그가 비활성화되었는지 확인
Feature.disabled?(:my_wip_flag, project)

# 프론트엔드로 피처 플래그 푸시
push_frontend_feature_flag(:my_wip_flag, project)

beta 유형

현재 형태로는 모든 설계된 사용 사례에 대해 기능을 충분히 확장, 지원 및 유지 관리할 수 없다는 믿음이 있는 경우, [베타 상태에서 모든 사람에게 “릴리스”할 수 있도록 true로 설정될 수 있어야 한다. 확장 가능성 문제로 이를 비활성화할 가능성이 있는 특정온프레미스 설치의 경우에만 이 유형의 기능은 비활성화되어야 합니다. -  최대 수명: 기본 브랜치에 Merge된 후 6개월 -  문서: 이 유형의 피처 플래그는 GitLab의 모든 피처 플래그 페이지에 반드시 문서화되어야 합니다. - 롤아웃 이슈: 롤아웃 문제가 꼭 있어야 합니다. Feature Flag Roll Out template에서 만들어졌습니다.

사용법

# 피처 플래그가 활성화되었는지 확인
Feature.enabled?(:my_beta_flag, project)

# 피처 플래그가 비활성화되었는지 확인
Feature.disabled?(:my_beta_flag, project)

# 프론트엔드로 피처 플래그 푸시
push_frontend_feature_flag(:my_beta_flag, project)

ops 유형

ops 피처 플래그는 GitLab 제품 동작의 운영 측면을 제어하는 장기간 사용되는 피처 플래그입니다. 예를 들어, Sidekiq 워커 동작과 같이 성능에 영향을 미칠 수 있는 기능을 비활성화하는 피처 플래그 등이 있습니다.

이 유형을 사용하는 것은 인스턴스/그룹/프로젝트/사용자 설정을 도입하지 않기로 최종 결정할 때라는 의식적인 결정을 따라야 함을 기억하십시오.

제약 사항

  • default_enabled: 대부분의 경우 false로 설정해야 하며, 임시 확장 가능성 문제를 해결하거나 프로덕션 문제를 디버깅하는 데 도움이 되는 경우에만 활성화되어야 합니다. -  최대 수명: 12개월 -  문서: 이 유형의 피처 플래그는 GitLab의 모든 피처 플래그 페이지에 문서화할 뿐만 아니라 사용할 수 있는 환경에 대한 운영적인 런북과 연관되도록해야 합니다. -  롤아웃 이슈: 아마도 사용 여부를 예측하기 어려워 활성화 또는 비활성화될 때 언제인지가 예측하기 어려워 롤아웃 문제가 필요 없을 것입니다.

사용법

# 피처 플래그가 활성화되었는지 확인
Feature.enabled?(:my_ops_flag, project)

# 피처 플래그가 비활성화되었는지 확인
Feature.disabled?(:my_ops_flag, project)

# 프론트엔드로 피처 플래그 푸시
push_frontend_feature_flag(:my_ops_flag, project)

experiment 유형

experiment 피처 플래그는 GitLab.com에서 A/B 테스트에 사용됩니다.

experiment 피처 플래그는 beta 피처 플래그와 동일한 표준을 준수해야 하지만, 인터페이스에는 일부 차이점이 있습니다. 실험 피처 플래그는 Experiment Tracking template을 사용하여 만들어진 롤아웃 이슈를 가져야 합니다. 추가 정보는 실험 가이드에서 확인할 수 있습니다.

제약 사항

  • default_enabled: true로 설정해서는 안 됩니다. -  최대 수명: 기본 브랜치에 Merge된 후 6개월

worker 유형

worker 피처 플래그는 Sidekiq 작업을 연기하는 등 Sidekiq 워커 동작을 제어하는 특별한 ops 플래그입니다.

worker 피처 플래그는 이름 자체를 사용하여 동적으로 생성할 수 있기 때문에 대부분 YAML 정의가 없을 수 있습니다. 예를 들어 run_sidekiq_jobs_AuthorizedProjectsWorker와 같이 워커 이름을 사용하여 동적으로 생성된 이름이 될 수 있습니다. worker 유형 피처 플래그 사용 예시는 Sidekiq 작업 연기에서 찾을 수 있습니다.

(삭제됨) development 유형

개발 유형은 gitlab_com_derisk, wip, beta 피처 플래그 유형을 선호합니다.

피처 플래그 정의와 유효성 검사

개발 중(RAILS_ENV=development) 또는 테스트(RAILS_ENV=test) 중에 모든 피처 플래그 사용 사항이 엄격히 유효성을 검사됩니다.

이 프로세스는 코드베이스에서 일관된 피처 플래그 사용을 보장하기 위한 것입니다. 모든 피처 플래그는 반드시:

  • 알려져야 합니다. 명시적으로 정의된 피처 플래그만 사용합니다(experiment, workerundefined 유형의 피처 플래그는 예외).
  • 두 번 정의되어서는 안 됩니다. FOSS 또는 EE 중 하나에서만 정의되어야 합니다.
  • 정의 파일이 없는 피처 플래그의 경우, 모든 호출에서 유효하고 일관된 type:을 사용합니다.
  • 소유자가 있어야 합니다.

GitLab에서 알려진 모든 피처 플래그는 다음에 저장된 YAML 파일에 자체 문서화됩니다:

각 피처 플래그는 여러 필드로 구성된 별도의 YAML 파일에 정의됩니다:

필드 필수 설명
name 피처 플래그의 이름
type 피처 플래그의 유형
default_enabled 피처 플래그의 기본 상태
introduced_by_url 피처 플래그를 소개한 머지 요청의 URL
milestone 피처 플래그가 생성된 마일스톤
group 피처 플래그를 소유하는 그룹
feature_issue_url 아니요 원본 기능 이슈의 URL
rollout_issue_url 아니요 피처 플래그 롤아웃을 다루는 이슈의 URL
log_state_changes 아니요 피처 플래그의 상태를 기록하는 데 사용
note
RAILS_ENV=production에서 실행될 때 모든 유효성 검사가 건너뜁니다.

새로운 피처 플래그 생성

note
GitLab Pages는 다른 프로세스를 사용하여 피처 플래그를 사용합니다.

GitLab 코드베이스는 bin/feature-flag를 제공하여 새로운 피처 플래그 정의를 위한 전용 도구를 제공합니다. 이 도구는 새로운 피처 플래그에 대해 다양한 질문을 하고, 그런 다음 config/feature_flags 또는 ee/config/feature_flags에 YAML 정의를 생성합니다.

개발 또는 테스트 환경에서 실행될 때는 YAML 정의 파일이 있는 피처 플래그만 사용할 수 있습니다.

$ bin/feature-flag my_feature_flag
>> 피처 플래그 유형을 지정하세요.
?> beta
유형 'beta'를 선택했습니다.

>> 다음 디렉터리에서 피처 플래그가 속하는 그룹 레이블을 지정하세요:

1. group::group1
2. group::group2
?> 2
'group::group2'를 선택했습니다.

>> 원본 기능 이슈의 URL (건너뛰려면 입력):
?> https://gitlab.com/gitlab-org/gitlab/-/issues/435435

>> 피처 플래그를 소개하는 머지 요청의 URL(건너뛰고 Danger가 머지 요청에서 직접 제안하게하려면 입력):
?> https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141023

>> 피처 플래그 DRI의 사용자 이름(건너뛰려면 입력):
?> bob

>> EE 전용 기능인가요? (건너뛰려면 입력):
?> [Enter]

>> 아무 키나 누르고 클립보드에 복사한 이슈 내용을 붙여넣으세요! 🚀
?> [Enter를 누르면 "새 이슈" 페이지가 열리고 여기에 이슈 내용을 붙여넣기만 하면 됩니다]

>> 롤아웃 이슈의 URL (건너뛰려면 입력):
?> https://gitlab.com/gitlab-org/gitlab/-/issues/437162

config/feature_flags/beta/my_feature_flag.yml 생성됨
---
name: my_feature_flag
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/435435
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141023
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/437162
milestone: '16.9'
group: group::composition analysis
type: beta
default_enabled: false

모든 새로 도입된 피처 플래그는 기본적으로 비활성화되어야 합니다.

피처 플래그를 사용하여 개발 및 Merge된 기능은 변경 로그 항목이 포함되어서는 안 됩니다. 변경 로그 항목은 피처 플래그를 제거하는 머지 요청이나 피처 플래그의 기본 값이 활성화된 머지 요청 중 하나에 추가되어야 합니다. 기능에 데이터베이스 마이그레이션이 포함된 경우 데이터베이스 변경에 대한 변경 로그 항목이 포함되어야 합니다.

note
EE에서만 사용되는 피처 플래그를 만들려면 --ee 플래그를 추가하세요: bin/feature-flag --ee

새로운 플래그의 이름 지정

새로운 피처 플래그의 이름을 선택할 때 다음 가이드라인을 고려하세요:

  • 짧고 혼돈스러운 것보다는 긴 설명이 명확합니다.
  • 이름은 스네이크 케이스로 작성합니다(my_cool_feature_flag).
  • 부정적인 단어를 피하기 위해 이름에 disable를 사용하지 않으려고 합니다(double negatives를 생각하거나 문서화하는 것을 피합니다). 부정적인 이름을 부정 문구로 사용하여 기능을 기본적으로 비활성화하거나 기능을 플래그 뒤로 이동하여 기능을 제거하거나 배우 별로 플래그를 비활성화할 수 있습니다.

부서진 마스터(메인) 브랜치의 위험

caution
피처 플래그는 반드시 도입하는 MR에서 사용되어야 합니다. 그렇지 않을 경우 master 브랜치에서만 실행되는 rspec:feature-flags 작업으로 부서진 마스터 시나리오가 발생합니다.

옵션으로 .patch 파일을 추가하여 피처 플래그를 자동으로 제거

gitlab-housekeeperDeleteOldFeatureFlags keep를 사용하여 피처 플래그 코드를 자동으로 제거할 수 있습니다. 이 도구는 주기적으로 실행되어 코드에서 이전 피처 플래그를 자동으로 정리합니다.

이 도구가 코드에서 피처 플래그 사용을 자동으로 제거하려면 피처 플래그 YAML 파일과 동일한 이름의 .patch 확장자 파일을 추가할 수 있습니다. 파일 이름은 .yml 확장자 대신 .patch 확장자를 사용하여 완전히 동일해야 합니다.

예를 들어, 다음 단계를 사용하여 config/feature_flags/beta/my_feature_flag.yml에 대한 패치 파일을 생성할 수 있습니다:

  1. 이미 피처 플래그가 활성화되어 있고 진행 중이라고 가정하고 로컬에서 코드를 편집하여 피처 플래그 my_feature_flag 사용을 제거합니다.
  2. git diff > config/feature_flags/beta/my_feature_flag.patch을 실행합니다.
  3. 피처 플래그 사용을 제거한 파일을 되돌립니다.
  4. 이 파일 config/feature_flags/beta/my_feature_flag.patch을 피처 플래그를 추가하는 브랜치에 커밋합니다.

이후에 gitlab-housekeeper는 이 패치를 적용하여 피처 플래그를 자동으로 정리합니다.

모든 피처 플래그 나열

Slack에 환경의 모든 피처 플래그를 출력하려면 ChatOps를 사용하여 run feature list 명령을 사용할 수 있습니다. 예를 들어:

/chatops run feature list --dev
/chatops run feature list --staging

피처 플래그 전환

피처 플래그를 전환하는 방법에 대한 자세한 내용은 변경 사항 롤아웃을 참조하십시오.

피처 플래그 삭제

피처 플래그를 삭제하는 방법에 대한 자세한 내용은 피처 플래그 정리를 참조하십시오.

피처 플래그로 개발

GitLab 코드베이스에서 피처 플래그를 사용하는 주요 방법은 두 가지입니다:

백엔드

피처 플래그 인터페이스는 lib/feature.rb에 정의되어 있습니다. 이 인터페이스는 피처 플래그가 활성화되었는지 비활성화되었는지를 확인하는 일련의 메서드를 제공합니다:

if Feature.enabled?(:my_feature_flag, project)
  # 피처 플래그가 활성화되어 있는 경우 코드 실행
else
  # 피처 플래그가 비활성화되어 있는 경우 코드 실행
end

if Feature.disabled?(:my_feature_flag, project)
  # 피처 플래그가 비활성화되어 있는 경우 코드 실행
end

구성되지 않은 피처 플래그에 대한 기본 동작은 YAML 정의의 default_enabled:에서 제어됩니다.

피처 플래그에 YAML 정의 파일이 없는 경우 개발 또는 테스트 환경에서 오류가 발생하며 프로덕션 환경에서는 false가 반환됩니다.

YAML 정의 파일이 없는 피처 플래그(이 경우 experiment, worker, undefined 유형에만 해당)의 경우 Feature.enabled?Feature.disabled?를 호출할 때 type:을 전달해야 합니다.

if Feature.enabled?(:experiment_feature_flag, project, type: :experiment)
  # 피처 플래그가 활성화되어 있는 경우 코드 실행
end

if Feature.disabled?(:worker_feature_flag, project, type: :worker)
  # 피처 플래그가 비활성화되어 있는 경우 코드 실행
end

WARNING:
응용 프로그램 로드  피처 플래그를 사용하지 마십시오. 예를 들어, `config/initializers/*`에서 `Feature` 클래스를 사용하거나 클래스 수준에서 사용하는 것은 예기치 않은 오류를 일으킬  있습니다.  오류는 피처 플래그 어댑터가 의존하는 데이터베이스가 로드  존재하지 않을  발생하며(특히 새로 설치된 경우에는 특히 그렇습니다), 호출자가 데이터베이스의 존재 여부를 확인하는 것은 권장되지 않습니다(: HTTP 어댑터의 경우 데이터베이스가 전혀 필요하지 않을  있습니다). 피처 플래그 설치 확인은 `Feature` 네임스페이스에 추상화되어야 합니다.  접근 방식은 피처 플래그가 변경될  응용 프로그램을 다시로드해야 한다는 것을 의미합니다. 따라서 프로덕션에서 SRE에게 /API/Sidekiq 플릿을 다시로드하도록 요청해야 합니다. 이는 변경 사항을 완전히 롤아웃/되감기하는  시간이 걸립니다. 이러한 이유로 환경 변수(: `ENV['YOUR_FEATURE_NAME']`) 또는 `gitlab.yml` 사용하십시오.

다음은 피해야  패턴의 예입니다:

```ruby
class MyClass
  if Feature.enabled?(:...)
    new_process
  else
    legacy_process
  end
end

#### 재귀 탐지

많은 피처 플래그가 있는 경우 어디서 호출되었는지 항상 분명하지 않습니다. 하나의 피처 플래그를 평가하는 데 다른 피처 플래그의 평가가 필요한 경우가 있습니다. 이 때문에 순환이 발생하면 이를 중단하고 기본 값을 반환합니다.

이 재귀 탐지가 올바르게 작동하려면 항상 `Feature::enabled?`을 통해 기능 값을 액세스하고 낮은 수준의 `Feature::get` 사용을 피해야 합니다. 이 경우, 우리는 `Feature::RecursionError` 예외를 오류 추적기로 추적합니다.

### 프론트엔드

UI 요소에 피처 플래그를 사용할 때, 백엔드 코드에 대한 피처 플래그도 반드시 사용하십시오. 이렇게 하면 기능이 활성화될 때까지 절대로 기능을 사용할 수 없음이 보장됩니다.

`ApplicationController`에서 상속된 모든 컨트롤러에서 사용 가능한 `push_frontend_feature_flag` 메서드를 사용하십시오. 이 메서드를 사용하여 예를 들어 피처 플래그의 상태를 노출할 수 있습니다:

```ruby
before_action do
  # 프로젝트 또는 사용자 단위로 범위를 지정하는 것을 선호합니다
  push_frontend_feature_flag(:vim_bindings, project)
end

def index
  # ...
end

def edit
  # ...
end

그런 다음 JavaScript에서 피처 플래그의 상태를 다음과 같이 확인할 수 있습니다:

if ( gon.features.vimBindings ) {
  // ...
}

JavaScript에서의 피처 플래그의 이름은 항상 camelCase이므로 gon.features.vim_bindings을 확인하는 것은 작동하지 않습니다.

Vue 컴포넌트에서 피처 플래그 액세스에 대한 자세한 내용은 Vue 가이드를 참조하십시오.

YAML 정의 파일이 없는 피처 플래그(이 경우 experiment, worker, undefined 유형에만 해당)의 경우 push_frontend_feature_flag를 호출할 때 type:을 전달해야 합니다.

before_action do
  push_frontend_feature_flag(:vim_bindings, project, type: :experiment)

기능 액터

피처 플래그에 액터를 사용하는 것이 강력히 권장됩니다. 액터는 특정 프로젝트, 그룹 또는 사용자에 대해서만 플래그를 활성화하는 간단한 방법을 제공합니다. 이를 통해 디버깅이 쉬워지며, 예를 들어 액터 기반으로 로그 및 오류를 필터링할 수 있습니다. 또한 나머지 사용자에게 영향을 주지 않으면서 먼저 gitlab-org 또는 gitlab-com 그룹에서 기능을 활성화할 수 있습니다.

또한, 액터는 특정 퍼센트로 기능을 롤아웃하는 간단한 방법을 제공합니다. 예를 들어 1%의 롤아웃이 특정 액터에 대해 기능을 활성화했다면, 해당 액터는 10%, 50%, 100%에서도 기능이 계속해서 활성화됩니다.

현재 GitLab에서는 다음과 같은 피처 플래그 액터를 지원합니다:

  • User 모델
  • Project 모델
  • Group 모델
  • 현재 요청

액터는 Feature.enabled? 호출의 두 번째 매개변수입니다. 모든 Feature.enabled? 호출에 대해 일관되게 사용해야 하는 동일한 액터 유형을 사용해야 합니다.

# 나쁨
Feature.enabled?(:feature_flag, project)
Feature.enabled?(:feature_flag, group)
Feature.enabled?(:feature_flag, user)

# 좋음
Feature.enabled?(:feature_flag, group_a)
Feature.enabled?(:feature_flag, group_b)

# 또 좋음 - 각 액터 유형에 대해 별도의 플래그를 사용하는 방법
Feature.enabled?(:feature_flag_group, group)
Feature.enabled?(:feature_flag_user, user)

FeatureGate를 포함하는 모델은 .actor_from_id 클래스 메서드를 가지고 있습니다. 모델의 ID가 있고 피처 플래그 상태를 확인하는 것 이외에 모델이 필요하지 않은 경우에는 Project.actor_from_id를 사용하여 데이터베이스 쿼리없이 피처 플래그 상태를 확인할 수 있습니다.

# 나쁨 -- 불필요한 쿼리가 실행됨
Feature.enabled?(:feature_flag, Project.find(project_id))

# 좋음 -- 프로젝트에 대한 쿼리가 없음
Feature.enabled?(:feature_flag, Project.actor_from_id(project_id))

# 좋음 -- 피처 플래그 확인 후에 프로젝트 모델 사용
project = Project.find(project_id)
return unless Feature.enabled?(:feature_flag, project)
project.update!(column: value)

GitLab에서 제공하는 환경인 스테이징 및 프로덕션과 같은 환경에서 피처 플래그를 선택적으로 활성화 또는 비활성화하기 위해 ChatOps를 사용하는 방법에 대한 자세한 내용은 GitLab에서 피처 플래그 사용을 참조하세요.

현재 요청 액터

특정 시간의 롤아웃 사용은 권장되지 않으며, 각 호출마다 일관되지 않은 결과를 반환할 수 있습니다.

대신 현재 요청을 액터로 사용하는 것이 좋습니다.

# 나쁨
Feature.enable_percentage_of_time(:feature_flag, 40)
Feature.enabled?(:feature_flag)

# 좋음
Feature.enable_percentage_of_actors(:feature_flag, 40)
Feature.enabled?(:feature_flag, Feature.current_request)

현재 요청을 액터로 사용할 때, 요청 범위 내에서 피처 플래그는 동일한 값을 반환해야 합니다. 현재 요청 액터는 SafeRequestStore를 사용하여 구현되었기 때문에 Rack 요청, Sidekiq 작업 실행, ActionCable 작업 실행 내에서 일관된 피처 플래그 값을 가져야 합니다.

기존의 시간 백분율에서 현재 요청 액터로의 기능 이전을 위해 새로운 피처 플래그를 만드는 것이 좋습니다. 기존의 percentage_of_time 값, 코드 변경 배포 및 percentage_of_actors 사용으로 전환하는 타이밍을 제어하기 어려우므로 이렇게 하는 것이 좋습니다.

프로덕션에서 확인을 위한 액터 사용

caution
프로덕션을 테스트 환경으로 사용하는 것은 권장되지 않습니다. 프로덕션 준비가 되지 않은 기능을 테스트하기 위해서는 테스트 환경을 사용하세요.

스테이징 환경은 프로덕션과 유사한 환경에서 기능을 테스트할 수 있는 방법을 제공하지만, 프로덕션 환경과 관련된 이전 및 이후 성능 메트릭을 비교하는 것을 허용하지 않습니다. 개발 피처 플래그가 활성화된 상태에서 프로덕션에 프로젝트를 가지고 있는 것은 새로운 코드의 메트릭을 Sitespeed 보고서와 같은 도구를 사용하여 공개합니다.

기존에도 Sitespeed에서 이전 코드베이스를 추적하고 있다면 이러한 접근 방식은 새로운 피처 플래그 롤아웃 전후의 성능을 정확하게 비교할 수 있도록 도와줍니다.

추가 객체를 액터로 활성화

액터 기반의 기능 게이트를 사용하려면 모델은 flipper_id에 응답해야 합니다. 예를 들어, Foo 모델을 활성화하려면:

class Foo < ActiveRecord::Base
  include FeatureGate
end

FeatureGate를 포함하거나 flipper_id 메서드를 노출시키는 모델만이 Feature.enabled?의 액터로 사용될 수 있습니다.

라이선스 기능용 피처 플래그

라이선스 기능명과 동일한 이름의 피처 플래그를 사용할 수 없습니다. 그렇게 함으로써 이름 충돌이 발생하기 때문에 해당 기능은 사용할 수 없습니다. 이는 널리 논의되었고 제거되었음으로 인한 것입니다.

라이선스 기능을 확인하려면, 다른 이름으로 전용 피처 플래그를 추가하고 명시적으로 확인하세요. 예를 들어:

Feature.enabled?(:licensed_feature_feature_flag, project) &&
  project.feature_available?(:licensed_feature)

기능 그룹

기능 그룹은 lib/feature.rb (.register_feature_groups 메서드)에 정적으로 정의해야 하지만, 구현은 동적으로 할 수 있습니다(DB 쿼리 등).

lib/feature.rb에서 정의한 후, features API의 feature_group 매개변수를 통해 특정 기능 그룹에 대해 기능을 활성화할 수 있습니다.

사용 가능한 기능 그룹은 다음과 같습니다:

그룹 이름 범위 설명
gitlab_team_members 사용자 gitlab-com의 구성원에게 기능을 활성화함

기능 그룹은 그룹 이름을 통해 활성화할 수 있습니다:

Feature.enable(:feature_flag_name, :gitlab_team_members)

로컬에서 피처 플래그 활성화(개발용)

Rails 콘솔(rails c)에서 다음 명령을 입력하여 피처 플래그를 활성화할 수 있습니다:

Feature.enable(:feature_flag_name)

마찬가지로, 다음 명령은 피처 플래그를 비활성화합니다:

Feature.disable(:feature_flag_name)

특정 게이트에 대해 피처 플래그를 활성화할 수도 있습니다:

Feature.enable(:feature_flag_name, Project.find_by_full_path("root/my-project"))

로컬에서 피처 플래그 비활성화(개발용)

Rails 콘솔에서 피처 플래그를 매뉴얼으로 활성화 또는 비활성화할 경우, 기본값이 덮어씌워집니다. 이는 플래그의 default_enabled 속성을 변경할 때 혼란을 줄 수 있습니다.

피처 플래그를 기본 상태로 재설정하려면 Rails 콘솔(rails c)에서 다음과 같이 비활성화하세요:

Feature.remove(:feature_flag_name)

로깅

피처 플래그의 사용 및 상태가 로그에 기록됩니다.

  • log_state_changes가 피처 플래그 정의에서 true로 설정된 경우
  • 마일스톤이 현재 GitLab 버전보다 크거나 같은 마일스톤을 참조하는 경우

피처 플래그의 상태가 로그에 기록될 때, Kibana에서 "json.feature_flag_states": "feature_flag_name:1" 또는 "json.feature_flag_states": "feature_flag_name:0" 조건을 사용하여 식별할 수 있습니다. 여기 예제를 확인할 수 있습니다.

note
요청의 20%만 피처 플래그의 상태를 로깅합니다. 이것은 feature_flag_state_logs 피처 플래그로 제어됩니다.

변경 로그

기능이 끝 사용자에게 직접적으로(예: 기능 사용 가능 여부) 또는 간접적으로(예: 배경 작업 활용 가능 여부, 성능 향상 또는 데이터베이스 마이그레이션 업데이트) 액세스할 수 없을 때 변경 로그를 도입하지 않도록하려고 합니다.

  • 데이터베이스 마이그레이션은 간접적으로 실험 요청에 의해 항상 액세스할 수 있는데, 이는 Self-managed 고객이 업그레이드하기 전에 데이터베이스 변경 사항을 인지해야하기 때문입니다. 이러한 이유로 데이터베이스 마이그레이션에는 변경 로그 항목이 있어야합니다.
  • 기본적으로 비활성화된 피처 플래그 뒤의 변경 사항에는 변경 로그 항목이 없어야 합니다.
  • 기본적으로 활성화된 피처 플래그 뒤의 변경 사항에는 변경 로그 항목이 있어야합니다.
  • 피처 플래그 자체의 변경(플래그 제거, 기본 켜기 설정)은 변경 로그 항목에 포함되어야합니다. 변경 로그 항목 유형을 결정하기 위해 플로차트를 사용하세요.

    flowchart LR FDOFF(플래그가 현재\n`기본: 꺼짐`인 경우) FDON(플래그가 현재\n`기본: 켜짐`인 경우) CDO{`기본: 켜짐`으로\n변경} ACF(추가됨 / 변경됨 / 수정됨 / '...') RF{플래그 제거} RF2{플래그 제거} NC(변경 로그 없음) RC(제거됨 / 변경됨) OTHER(기타) FDOFF -->CDO-->ACF FDOFF -->RF RF-->|새 코드 유지?| ACF RF-->|이전 코드 유지?| NC FDON -->RF2 RF2-->|이전 코드 유지?| RC RF2-->|새 코드 유지?| OTHER
  • 피처 플래그의 변경 로그는 플래그가 아닌 기능을 설명해야합니다. 기본으로 활성화된 피처 플래그가 제거되면(플로차트에서 '기타'), 새 코드를 유지해야합니다.
  • 피처 플래그는 버그 수정 또는 유지 보수 작업을 롤아웃하는 데 사용될 수 있습니다. 이 경우, 변경 로그는 이와 관련이 있어야합니다. 예: 수정됨 또는 기타.

테스트에서 피처 플래그

코드베이스에 피처 플래그를 도입하면 추가적인 코드 경로가 생성되어야합니다. 피처 플래그에 영향을 받는 모든 코드에 자동화된 테스트를 포함하는 것이 강력히 권장됩니다. 자동화된 테스트가 두 상태(활성화비활성화)에 대해 포함되지 않은 경우, 테스트되지 않은 코드 경로와 관련된 기능이 배포 전에 매뉴얼으로 테스트되어야합니다.

테스트 환경을 사용할 때 모든 피처 플래그는 기본적으로 활성화됩니다. 피처 플래그는 spec/spec_helper.rb 파일에서 기본적으로 비활성화할 수 있습니다. 가능한 경우 이유를 설명하는 인라인 주석을 추가할 수 있습니다. 가능하면 참고용 이슈 URL을 첨부하세요.

caution
이는 기본적으로 피처 플래그를 활성화하지 않는 종단간(품질 보증) 테스트에는 적용되지 않습니다. 종단간 테스트에서 피처 플래그를 사용하는 다른 프로세스가 있습니다.

테스트에서 피처 플래그를 비활성화하려면 stub_feature_flags 도우미를 사용하세요. 예를 들어, 테스트에서 ci_live_trace 피처 플래그를 전역적으로 비활성화하려면 다음과 같이 합니다.

stub_feature_flags(ci_live_trace: false)

Feature.enabled?(:ci_live_trace) # => false

두 경로 모두 테스트하는 일반적인 방법은 다음과 같습니다.

it 'ci_live_trace 작동 확인' do
  # 테스트는 기본적으로 ci_live_trace가 활성화되었다고 가정합니다
  Feature.enabled?(:ci_live_trace) # => true
end

context 'ci_live_trace가 비활성화된 경우' do
  before do
    stub_feature_flags(ci_live_trace: false)
  end
  
  it 'ci_live_trace이 작동하지 않음' do
    Feature.enabled?(:ci_live_trace) # => false
  end
end

특정 액터로만 피처 플래그를 활성화하려면 도우미에 전달된 옵션에 지정할 수 있습니다. 예를 들어 특정 프로젝트에 ci_live_trace 피처 플래그를 활성화하려면 다음과 같이 할 수 있습니다.

project1, project2 = build_list(:project, 2)

# 프로젝트1에서만 기능 활성화됩니다
stub_feature_flags(ci_live_trace: project1)

Feature.enabled?(:ci_live_trace) # => false
Feature.enabled?(:ci_live_trace, project1) # => true
Feature.enabled?(:ci_live_trace, project2) # => false

FlipperGate의 동작은 다음과 같습니다.

  1. 지정된 액터에 대한 재정의를 활성화할 수 있습니다.
  2. 지정된 액터에 대한 비활성화(제거)를 수행하여 기본 상태로 복귀할 수 있습니다.
  3. 명시적으로 지정된 액터를 비활성화한 모델링 방법은 없습니다.
Feature.enable(:my_feature)
Feature.disable(:my_feature, project1)
Feature.enabled?(:my_feature) # => true
Feature.enabled?(:my_feature, project1) # => true

Feature.disable(:my_feature2)
Feature.enable(:my_feature2, project1)
Feature.enabled?(:my_feature2) # => false
Feature.enabled?(:my_feature2, project1) # => true

have_pushed_frontend_feature_flags

have_pushed_frontend_feature_flags를 사용하여 push_frontend_feature_flag가 HTML에 피처 플래그를 추가했는지 테스트합니다.

예시:

stub_feature_flags(value_stream_analytics_path_navigation: false)

visit group_analytics_cycle_analytics_path(group)

expect(page).to have_pushed_frontend_feature_flags(valueStreamAnalyticsPathNavigation: false)

stub_feature_flags vs Feature.enable*

테스트 환경에서 피처 플래그를 활성화하는 데는 stub_feature_flags를 사용하는 것이 좋습니다. 이 방법은 간단하고 잘 설명된 인터페이스를 제공하여 간단한 사용 사례에 적합합니다.

그러나 경우에 따라 피처 플래그의 복잡한 동작을 테스트해야 하는 경우가 있습니다. 예를 들어 피처 플래그의 백분율 롤아웃과 같이요. 이를 위해 .enable_percentage_of_time 또는 .enable_percentage_of_actors를 사용할 수 있습니다.

# Good: feature needs to be explicitly disabled, as it is enabled by default if not defined
stub_feature_flags(my_feature: false)
stub_feature_flags(my_feature: true)
stub_feature_flags(my_feature: project)
stub_feature_flags(my_feature: [project, project2])

# Bad
Feature.enable(:my_feature_2)

# Good: enable my_feature for 50% of time
Feature.enable_percentage_of_time(:my_feature_3, 50)

# Good: enable my_feature for 50% of actors/gates/things
Feature.enable_percentage_of_actors(:my_feature_4, 50)

각 정의된 상태를 가진 피처 플래그는 테스트 실행 시 유지됩니다.

Feature.persisted_names.include?('my_feature') => true
Feature.persisted_names.include?('my_feature_2') => true
Feature.persisted_names.include?('my_feature_3') => true
Feature.persisted_names.include?('my_feature_4') => true

Actor 스텁

특정 Actor에 대해 피처 플래그를 활성화하려면 해당 표현을 스텁 처리할 수 있습니다. Feature.enabled?Feature.disabled?에 전달되는 게이트는 FeatureGate를 포함하는 객체여야 합니다.

스펙에서는 사용자 정의 Actor를 빠르게 만들어 사용할 수 있는 stub_feature_flag_gate 메서드를 사용할 수 있습니다.

gate = stub_feature_flag_gate('CustomActor')

stub_feature_flags(ci_live_trace: gate)

Feature.enabled?(:ci_live_trace) # => false
Feature.enabled?(:ci_live_trace, gate) # => true

특정 Actor를 위해 피처 플래그를 비활성화할 수도 있습니다.

gate = stub_feature_flag_gate('CustomActor')

stub_feature_flags(ci_live_trace: false, thing: gate)

테스트에서 피처 플래그 엔진 제어

테스트 환경에서 Flipper 엔진은 메모리 모드인 Flipper::Adapters::Memory에서 작동합니다. productiondevelopment 모드는 Flipper::Adapters::ActiveRecord를 사용합니다.

Flipper::Adapters::Memory 또는 ActiveRecord 모드를 사용할지 제어할 수 있습니다.

stub_feature_flags: true (기본 및 기본 설정)

이 모드에서 Flipper는 Flipper::Adapters::Memory를 사용하도록 구성되며 모든 피처 플래그를 기본적으로 켜고 처음 사용시 유지되도록 표시됩니다.

특정 컨텍스트에 특정 동작을 테스트하지 않도록 주의하세요.

stub_feature_flags: false

이것은 메모리로 스텁 처리된 플리퍼를 비활성화하고 productiondevelopment에서 사용되는 Flipper::Adapters::ActiveRecord를 사용합니다.

이 모드는 ActiveRecord와 상호 작용하는 Flipper의 측면을 테스트하려는 경우에만 사용해야 합니다.

종단 간 (QA) 테스트

종단 간 (QA) 테스트에서 피처 플래그를 전환하는 방식은 다릅니다. 종단 간 테스트 프레임워크는 Rails나 데이터베이스에 직접적으로 액세스할 수 없으므로 Flipper를 사용할 수 없습니다. 대신, 공개 API를 사용합니다. 각 종단 간 테스트는 테스트 중에 피처 플래그를 활성화 또는 비활성화할 수 있습니다. 또한 GitLab 리포지터리의 qa 디렉터리에서 실행하거나 GitLab QA를 통해 테스트를 실행할 때 하나 이상의 테스트 전에 피처 플래그를 활성화 또는 비활성화할 수 있습니다.

위에서 언급한 바와 같이, 종단 간 테스트에서 피처 플래그는 기본적으로 활성화되지 않습니다. 이는 종단 간 테스트가 소스 코드에 구현된 기본 상태 또는 테스트 중인 GitLab 인스턴스의 피처 플래그의 현재 상태로 실행됨을 의미합니다. 또한, 테스트가 명시적으로 피처 플래그를 활성화/비활성화하도록 작성되지 않는 한, 피처 플래그를 활성화/비활성화하는 데는 영향을 주지 않습니다.

피처 플래그가 Staging 또는 GitLab.com에서 변경되면 #qa-staging 또는 #qa-production 채널에 Slack 메시지가 게시되어 파이프라인 담당자가 어떤 실패가 피처 플래그 변경과 관련이 있는지 쉽게 확인할 수 있도록 돕습니다. 그러나 변경 작업 중이라면 피처 플래그를 활성화하여 종단 간 테스트가 통과하는지 확인하여 예기치 않은 실패를 방지하는 데 도움을 줄 수 있습니다.

Sidekiq 워커 동작 제어 피처 플래그

worker 타입을 가진 피처 플래그를 사용하여 Sidekiq 워커의 동작을 제어할 수 있습니다.

Sidekiq 작업 연기

비활성화된 상태일 때 run_sidekiq_jobs_{WorkerName} 형식을 가진 피처 플래그는 작업을 나중에 예약하여 나중에 실행되도록 합니다. 이 피처 플래그는 모든 워커에 대해 기본적으로 활성화됩니다. 작업을 지연시키는 것은 워커 인스턴스의 격렬한 동작이 인프라 리소스(예: 데이터베이스 및 데이터베이스 연결 풀)를 포화시키는 사고 발생 시 유용합니다. 구현 내용은 SkipJobs Sidekiq 서버 미들웨어에서 찾을 수 있습니다.

note
피처 플래그가 비활성화된 상태로 작업이 무기한 연기됩니다. 워커가 안전하게 처리할 수 있다고 판단되면 피처 플래그를 제거하는 것이 중요합니다.

false로 설정하면 모든 작업의 100%가 연기됩니다. 처리를 재개하려면 시간의 백분율 롤아웃을 사용할 수 있습니다. 예:

# 작업을 실행하지 않고 모든 작업을 연기함
/chatops run feature set run_sidekiq_jobs_SlowRunningWorker false

# 작업을 10%만 실행하고 나머지 90%를 연기함
/chatops run feature set run_sidekiq_jobs_SlowRunningWorker 10

# 작업을 50%만 실행하고 나머지 50%를 연기함
/chatops run feature set run_sidekiq_jobs_SlowRunningWorker 50

# 모든 작업을 다시 정상적으로 실행함
/chatops run feature delete run_sidekiq_jobs_SlowRunningWorker

Sidekiq 작업 삭제

작업 연기 대신에, 작업을 완전히 삭제하려면 피처 플래그 drop_sidekiq_jobs_{WorkerName}를 활성화하세요. 이 피처 플래그를 사용하여 작업이 안전하게 삭제될 수 있는 경우, 즉 미래에 처리할 필요가 없는 경우에 사용합니다.

# 모든 작업 삭제
/chatops run feature set drop_sidekiq_jobs_SlowRunningWorker true

# 작업을 정상적으로 처리
/chatops run feature delete drop_sidekiq_jobs_SlowRunningWorker
note
작업 삭제 피처 플래그(drop_sidekiq_jobs_{WorkerName})는 작업 연기 피처 플래그(run_sidekiq_jobs_{WorkerName})보다 우선합니다. 즉, drop_sidekiq_jobs가 활성화되고 run_sidekiq_jobs가 비활성화되면 작업이 완전히 삭제됩니다.