GitLab의 특징 플래그

참고: 이 문서는 GitLab 제품의 개발 및 운영에 기여하는 방법에 대해 설명합니다. 만약 여러분이 자신의 애플리케이션에서 기능을 표시하거나 숨기기 위해 특징 플래그를 사용하고 싶다면, 대신 이 특징 플래그 정보를 참조하십시오.

주의: 새롭게 도입된 특징 플래그는 기본적으로 비활성화되어야 합니다.

주의: 새롭게 도입된 특징 플래그는 배우자를 포함하여 사용되어야 합니다.

블루프린트:

이 문서는 특징 플래그의 내부 사용 개선을 위한 에픽의 일환으로 계속해서 작업 중입니다. 새로운 문제를 제기하고 해당 에픽에 첨부하세요.

특징 플래그 라이프사이클 개요특징 플래그를 사용할지 결정하는 데 도움이 필요한 경우에 대해서는 특징 플래그 라이프사이클 핸드북 페이지를 참조하세요.

언제 특징 플래그를 사용해야 하는가

핸드북의 “언제 특징 플래그를 사용해야 하는가” 섹션으로 이동하였습니다.

GitLab 개발에서의 특징 플래그

다음과 같은 강조 사항을 고려하여 특징 플래그를 사용할지 결정해야 합니다:

  • 특징 플래그는 기본적으로 비활성화되어야 합니다.
  • 특징 플래그는 특징 플래그 계정 필요성을 줄이기 위해 가능한 한 짧은 기간 동안 코드베이스에 유지되어야 합니다.
  • 특징 플래그를 운영하는 사람은 특징 플래그 뒤의 기능 상태를 문서화 및 기타 이해 관계자들에게 명확하게 전달해야 합니다. 특징 플래그가 필요한 것으로 판명되는 즉시 이슈 설명을 특징 플래그 이름과 함께 업데이트해야 합니다.
  • 특징 플래그를 도입하거나 상태를 업데이트하거나 안정적인 특징으로 간주되어 기존 특징 플래그를 제거하는 머지 리퀘스트는 ~"feature flag" 라벨을 지정해야 합니다.

특징 구현이 여러 개의 머지 리퀘스트를 통해 제공될 때:

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

특징 플래그 제거가 여러 개의 머지 리퀘스트를 통해 수행될 때:

  1. 특징 플래그의 값 변경은 머지 리퀘스트에서 유일한 변경 사항이어야 합니다. 특징 플래그가 코드베이스에 존재하는 한, 두 상태가 모두 완전히 기능해야 합니다(특징이 활성화 및 비활성화된 경우).
  2. 특징 플래그에 대한 모든 언급이 제거된 후에는 레거시 코드를 제거할 수 있습니다. 특징 플래그 롤아웃 이슈의 단계를 따라야 하며, 단계를 건너뛰어야 하는 경우 이유를 설명하는 코멘트를 이슈에 추가해야 합니다.

특징 플래그가 새로운 특징의 출시를 적어도 한 달 (= 하나의 릴리스) 지연시킬 것으로 생각될 수 있습니다. 그러나 사실은 아닙니다. 특징 플래그는 특정 시간(예를 들어, 적어도 하나의 릴리스 동안) 동안 유지되어야 할 필요가 없으며, 대신 특징이 안정될 때까지 유지되어야 합니다. 안정적이라 함은 GitLab.com에서 문제(장애와 같은)를 일으키지 않고 작동함을 의미합니다.

기본 브랜치의 손상 위험

기능 플래그는 도입하는 MR에서 사용되어야 합니다. 그렇지 않으면 기본 브랜치에서만 실행되는 rspec:feature-flags 작업으로 인해 손상된 기본 브랜치 시나리오가 발생합니다.

기능 플래그의 유형

예상된 사용 방식과 일치하는 기능 플래그 유형을 선택하세요.

gitlab_com_derisk 유형

gitlab_com_derisk 기능 플래그는 일시적인 기능 플래그로, GitLab.com 배포의 위험을 줄이기 위해 사용됩니다. GitLab에서 사용되는 대부분의 기능 플래그는 gitlab_com_derisk 유형입니다.

제한 사항

  • default_enabled: true로 설정해서는 절대로 안 됩니다. 이 유형의 기능 플래그는 GitLab.com의 위험을 낮추기 위한 것이므로, 한 번 GitLab.com에서 활성화된 후에는 더 이상 코드베이스에 플래그를 유지할 필요가 없습니다. 이 유형의 기능 플래그에는 default_enabled: true가 어떠한 영향도 미치지 않을 것입니다.
  • 최대 수명: 기본 브랜치로 병합된 후 2개월
  • 문서: 이 유형의 기능 플래그는 짧은 수명을 가지고 배포와 관련이 있기 때문에 GitLab의 모든 기능 플래그 페이지에 문서화할 필요가 없습니다.
  • 롤아웃 이슈: gitlab_com_derisk 유형의 기능 플래그는 기능 플래그 롤아웃 템플릿에서 생성된 롤아웃 이슈가 반드시 있어야 합니다.

사용 방법

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 기능 플래그를 사용하여 해당 변경 사항을 실제로 사용하지 않고도 주요 브랜치에 모든 변경 사항을 병합할 수 있습니다.

기능이 완료되면, 기능 플래그 유형을 해당 기능이 고객에게 제시/문서화될 방식에 따라 gitlab_com_derisk 또는 beta 유형으로 변경할 수 있습니다.

제한 사항

  • default_enabled: true로 설정해서는 절대로 안 됩니다. 필요하다면, 해당 유형은 기능이 완료된 후 beta로 변경할 수 있습니다.
  • 최대 수명: 기본 브랜치로 병합된 후 4개월
  • 문서: 이 유형의 기능 플래그는 완전히 구현되기 전에 대부분이 완성되지 않은 코드를 숨기기 때문에 GitLab의 모든 기능 플래그 페이지에 문서화할 필요가 없습니다.
  • 롤아웃 이슈: wip 기능 플래그는 활성화되기 전에 다른 유형으로 전환되어야 하므로 롤아웃 이슈가 필요하지 않을 가능성이 높습니다.

사용 방법

# 기능 플래그가 활성화되었는지 확인
Feature.enabled?(:my_wip_flag, project)

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

# Frontend에 기능 플래그 푸시
push_frontend_feature_flag(:my_wip_flag, project)

beta 유형

현재 양식으로는 특정 사용 사례에 대해 기능을 충분히 확장, 지원, 유지할 수 있다는 확신이 없을 수 있습니다 (예시). 또한 MVC로 고려하기에는 기능이 충분히 완료되지 않은 경우도 있습니다. 이 경우 플래그를 제공함으로써 엔지니어와 고객이 기능이 충분히 성능적으로 개선될 때까지 해당 기능을 사용하지 않을 수 있습니다.

제한 사항

  • default_enabled: 모든 사용 사례에 대해 현재 양식으로 기능을 확장, 지원, 유지할 수 있을지에 대한 확신이 없을 때를 대비하여 기능을 ‘릴리스’할 수 있도록 true로 설정할 수 있습니다. 정확도에 결여되어야 함(이상적으로 이러한 이유로 특정 온프레미스 설치에서만 사용할 때만 비활성화해야 함).
  • 최대 수명: 기본 브랜치로 병합된 후 6개월
  • 문서: 이 유형의 기능 플래그는 GitLab의 모든 기능 플래그 페이지에 반드시 문서화되어야 합니다.
  • 롤아웃 이슈: 기능 플래그 롤아웃 템플릿에서 생성된 롤아웃 이슈가 반드시 있어야 합니다.

사용법

# 기능 플래그가 활성화되었는지 확인합니다.
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 기능 플래그는 롤아웃 이슈를 가져야 하며 Experiment Tracking template을 사용하여 생성되어야 합니다. 자세한 정보는 실험 가이드에서 찾을 수 있습니다.

제한 사항

  • default_enabled: 반드시 true로 설정되어서는 안 됩니다.
  • 최대 수명: 기본 브랜치에 병합된 후 6개월

worker 유형

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

worker 기능 플래그는 이름 자체를 사용하여 동적으로 생성될 수 있기 때문에 아마도 YAML 정의가 없을 것으로 예상됩니다. 예를 들어, run_sidekiq_jobs_AuthorizedProjectsWorker와 같이 worker 이름을 사용하여 동적으로 생성될 수 있습니다. worker 유형 기능 플래그를 사용하는 몇 가지 예는 Sidekiq 작업 연기에서 찾을 수 있습니다.

(더 이상 사용되지 않음) development 유형

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 아니요 기능 플래그의 상태를 기록하는 데 사용됨.

참고: RAILS_ENV=production로 실행할 경우 모든 유효성 검사가 건너뜁니다.

새로운 기능 플래그 생성

참고: 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

>> 기능 플래그를 도입하는 MR의 URL(건너뛰려면 Danger가 MR에서 직접 제안하도록 건너뛰려면 입력):
?> https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141023

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

>> 이것이 EE 전용 기능입니까(건너뛰려면 입력):
?> [Return]

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

>> 롤아웃 이슈의 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

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

기능 플래그를 사용하여 개발되고 통합된 기능은 변경 로그 항목이 포함되지 않아야 합니다. 해당 항목은 기능 플래그를 제거하는 MR에 추가하거나 기능 플래그의 기본값이 활성화로 설정된 MR에 추가되어야 합니다. 기능에 데이터베이스 이전이 포함되어 있다면 데이터베이스 변경에 대한 변경 로그 항목을 반드시 포함해야 합니다.

참고: EE에서만 사용되는 기능 플래그를 만들려면 --ee 플래그를 추가하십시오: bin/feature-flag --ee

새로운 플래그의 명명

새로운 기능 플래그의 이름을 선택할 때 다음 가이드라인을 고려하십시오:

  • 짧지만 혼란스러운 것보다 길고 설명적인 이름이 더 좋습니다.
  • 이름은 스네이크 케이스로 작성하십시오 (my_cool_feature_flag).
  • 부정문이 사용되지 않도록 이름에 disable를 사용하지 않는 것이 좋습니다. 혼란을 피하기 위해 이름을 hide_, remove_, 또는 disallow_로 시작하는 것을 고려하십시오.

    소프트웨어 공학에서 이 문제는 “부울 변수의 부정적인 이름”로 알려져 있습니다. 그러나 부정적인 단어를 전면적으로 금지할 수는 없으므로 기본적으로 비활성화를 위해 플래그를 도입하거나 기능을 플래그 뒤로 이동하여 기능을 제거하거나 배우자에 의해 선택적으로 플래그를 비활성화할 수 있습니다.

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

경고: 기능 플래그는 도입하는 MR에서 사용되어야 합니다. 그렇지 않으면 이슈:rspec:feature-flags 작업이 master 브랜치에서만 실행되는 경우에 깨진 마스터 상황을 야기합니다.

자동으로 기능 플래그 제거를 위한 .patch 파일 추가(옵션)

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

이 도구가 코드에서 기능 플래그 사용을 자동으로 제거하도록 하려면 기능 플래그 YAML 파일과 동일한 이름의 .patch 파일을 추가할 수 있습니다. .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가 이 패치를 적용하여 자동적으로 기능 플래그를 정리할 것입니다.

모든 기능 플래그 나열

ChatOps를 사용하여 환경의 모든 기능 플래그를 Slack에 출력하려면 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 정의 파일이 없는 기능 플래그의 경우 (예: 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

경고:
응용 프로그램 로드  기능 플래그를 사용하지 마십시오. 예를 들어 `config/initializers/*` 클래스 수준에서 `Feature` 클래스를 사용하는 것은 예기치 않은 오류를 일으킬  있습니다.  오류는 기능 플래그 어댑터가 의존하는 데이터베이스가 로드 시간에 존재하지 않을  있기 때문에 발생합니다(특히 새로 설치하는 경우). 호출부에서 데이터베이스의 존재 여부를 확인하는 것은 권장되지 않으며, 일부 어댑터는 데이터베이스를 전혀 필요로하지 않을  있습니다(: HTTP 어댑터). 기능 플래그 설정 확인은 반드시 `Feature` 네임스페이스에서 추상화되어야 합니다.  접근 방식은 기능 플래그가 변경될  응용 프로그램을 다시로드해야 한다는 것을 의미합니다. 따라서 프로덕션에서 SRE에게 (: `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 가이드를 참조하십시오.

기능 플래그 정의 파일이 없는 경우(예: 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은 현재 다음과 같은 특징 플래그 액터를 지원합니다:

  • 사용자 모델
  • 프로젝트 모델
  • 그룹 모델
  • 현재 요청

액터는 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를 가지고 있고 해당 모델을 특징 플래그 상태를 확인하는 데 이외에는 필요하지 않은 경우, 데이터베이스 쿼리를 실행하지 않고도 .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 제공 환경(스테이징 및 프로덕션과 같은)에서 특징 플래그를 선택적으로 활성화 또는 비활성화하는 방법에 대한 자세한 내용은 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를 사용하여 구현되므로 다음과 같은 컨텍스트에서 일관된 특징 플래그 값을 가져야 합니다:

  • 랙 요청
  • Sidekiq 워커 실행
  • ActionCable 워커 실행

기존의 특징을 백분율에서 현재 요청 액터로 마이그레이션하려면 새로운 특징 플래그를 생성하는 것이 권장됩니다. 기존 percentage_of_time 값, 코드 변경 배포 및 percentage_of_actors 사용으로 전환하는 타이밍을 제어하기 어려우므로 이렇게 하는 것이 좋습니다.

프로덕션에서 확인하기 위해 액터 사용

경고: 프로덕션을 테스트 환경으로 사용하는 것은 권장되지 않습니다. 프로덕션 완료가 아닌 기능을 테스트하려면 테스트 환경을 사용하세요.

스테이징 환경은 프로덕션과 유사한 환경에서 기능을 테스트할 수 있는 방법을 제공하지만, 프로덕션 환경에 특정 프로덕션 환경에만 고유한 이전과 이후 성능 지표를 비교하는 기능은 제공하지 않습니다. 개발 중인 기능 플래그가 활성화된 프로젝트를 프로덕션 환경에 두는 것이 유용할 수 있으며, 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에서 정의된 후, 기능 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 콘솔에서 다음과 같이 비활성화할 수 있습니다:

Feature.remove(:feature_flag_name)

로깅

기능 플래그의 사용 및 상태는 다음 경우에 로그에 기록됩니다:

  • 기능 플래그 정의에서 log_state_changestrue로 설정되어 있는 경우.
  • 마일스톤이 현재 GitLab 버전보다 크거나 같은 마일스톤을 참조하는 경우.

기능 플래그의 상태가 로깅되면, Kibana에서 "json.feature_flag_states": "feature_flag_name:1" 또는 "json.feature_flag_states": "feature_flag_name:0" 조건을 사용하여 식별할 수 있습니다. 링크에서 예제를 확인할 수 있습니다.

참고: 기능 플래그 상태의 요청 중 20%만 로깅됩니다. 이는 feature_flag_state_logs 기능 플래그로 제어됩니다.

변경 로그

기능이 직접적으로(예: 기능 사용 가능) 또는 간접적으로(예: 백그라운드 작업 활용 가능, 성능 개선, 또는 DB 마이그레이션 업데이트) 종단 사용자에 의해 액세스되지 않을 때는 변경 로그를 도입하는 것을 피하고자 합니다.

  • DB 마이그레이션은 자체 관리형 고객이 업그레이드하기 전에 데이터베이스 변경 사항을 알아야 하므로 간접적으로 종단 사용자에게 항상 액세스 가능합니다. 이유로 인해 변경 로그 항목에 포함되어야합니다.
  • 기본적으로 비활성화된 기능 플래그 뒤에 있는 변경 사항은 변경 로그 항목에 포함되어서는 안 됩니다.
  • 기본적으로 활성화된 기능 플래그 뒤에 있는 변경 사항은 변경 로그 항목에 포함되어야합니다.
  • 기능 플래그 자체를 변경하는 경우 (플래그 제거, 기본 활성 설정)은 변경 로그 항목이 있어야 합니다. 변경 로그 항목 유형을 결정하려면 플로우차트를 사용하십시오.

    flowchart LR FDOFF(현재\n기본: off인 경우) FDON(현재\n기본: on인 경우) CDO{`기본: on`으로\n변경} ACF(추가 / 변경 / 고침 / '...') RF{플래그 제거} RF2{플래그 제거} NC(변경 로그 없음) RC(제거 / 변경됨) OTHER(다른) FDOFF -->CDO-->ACF FDOFF -->RF RF-->|신규 코드 유지?| ACF RF-->|기존 코드 유지?| NC FDON -->RF2 RF2-->|기존 코드 유지?| RC RF2-->|신규 코드 유지?| OTHER
  • 기능 플래그의 변경 로그는 플래그가 아니라 기능을 설명해야 하며, 기본적으로 켜진 기능 플래그의 경우에만 제거되는 기능 코드를 유지해야 합니다 (플로우차트에서 다른).
  • 기능 플래그는 버그 수정 또는 유지 보수 작업의 테스트를 위해 사용될 수도 있습니다. 이 경우 변경 로그는 그와 관련이 있어야 하며, 예를 들어 수정됨(fixed) 또는 다른(other)과 같은 내용이어야 합니다.

테스트에서의 기능 플래그

코드베이스에 기능 플래그를 도입하면 테스트해야 할 추가적인 코드 경로가 생성됩니다. 기능 플래그에 영향을 받는 모든 코드에 대한 자동화된 테스트를 포함하는 것이 강력히 권장되며, 기능 플래그가 활성화되었을 때와 비활성화되었을 때의 모든 코드에 대한 자동화된 테스트를 포함하여 기능이 올바르게 작동하는지 확인해야 합니다. 양쪽 상태에 대한 자동화된 테스트가 포함되지 않은 경우, 테스트되지 않은 코드 경로와 관련된 기능은 프로덕션 환경으로 배포되기 전 수동으로 테스트되어야 합니다.

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

경고: 이는 기본적으로 기능 플래그를 활성화하지 않는 종단간 (QA) 테스트에는 적용되지 않습니다. 종단간 테스트에서는 기능 플래그 사용을 위한 다른 절차가 있습니다.

테스트에서 기능 플래그를 비활성화하려면 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)

# 특정 프로젝트에 대해 기능이 활성화됩니다.
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를 사용하여 이를 수행할 수 있습니다.

# 좋음: 정의되지 않은 경우 기본적으로 기능을 명시적으로 비활성화해야 함
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])

# 나쁨
Feature.enable(:my_feature_2)

# 좋음: my_feature을 시간의 50% 동안 활성화해야 함
Feature.enable_percentage_of_time(:my_feature_3, 50)

# 좋음: my_feature을 사용자/게이트/무언가의 50%에게 활성화해야 함
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

Stubbing actor

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

스펙(specs)에서는 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

또한 특정 사용자에 대해 특징 플래그를 비활성화할 수도 있습니다.

gate = stub_feature_flag_gate('CustomActor')

stub_feature_flags(ci_live_trace: false, thing: gate)

Controlling feature flags engine in tests

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

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

stub_feature_flags: true (기본 및 권장)

이 모드에서 Flipper는 Flipper::Adapters::Memory를 사용하도록 구성되고 모든 특징 플래그가 기본적으로 켜져 있으며 최초 사용 시에 지속됩니다.

특징 플래그 아래 동작이 일부 비특정적인 컨텍스트에서 테스트되지 않도록 주의하십시오.

stub_feature_flags: false

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

이 모드는 실제로 Flipper가 ActiveRecord와 상호 작용하는 방식을 테스트하고 싶을 때에만 사용해야 합니다.

End-to-end (QA) 테스트

End-to-end (QA) 테스트에서는 특징 플래그를 전환하는 방법이 다릅니다. 엔드 투 엔드 테스트 프레임워크는 Rails 또는 데이터베이스에 직접 액세스할 수 없기 때문에 Flipper를 사용할 수 없습니다. 대신 공개 API를 사용합니다. 각 엔드 투 엔드 테스트는 테스트 중에 특징 플래그를 활성화 또는 비활성화할 수 있습니다. 또는 GitLab 저장소의 qa 디렉토리에서 하나 이상의 테스트를 실행할 때 테스트를 전에 특징 플래그를 활성화 또는 비활성화할 수 있습니다. 또는 GitLab QA를 통해 테스트를 실행할 때도 적용됩니다.

앞서 언급한 바와 같이, 엔드 투 엔드 테스트에서는 특징 플래그가 기본적으로 활성화되지 않습니다. 즉, 엔드 투 엔드 테스트는 소스 코드에서 구현된 기본 상태 또는 테스트 중인 GitLab 인스턴스의 현재 상태에서 특징 플래그가 실행됩니다. 단, 테스트가 특징 플래그를 명시적으로 활성화/비활성화하도록 작성되지 않는 한입니다.

특징 플래그가 스테이징 또는 GitLab.com에서 변경되면 Slack 메시지가 #qa-staging 또는 #qa-production 채널에 게시되어 파이프라인 triage DRI에게 알립니다. 이를 통해 장애가 특징 플래그 변경과 관련이 있는지 쉽게 판단할 수 있습니다. 그러나 변경 작업을 수행하는 경우 특징 플래그가 활성화된 상태에서 엔드 투 엔드 테스트가 통과하는지 확인하여 예기치 않은 실패를 방지할 수 있습니다.

Controlling Sidekiq worker behavior with feature flags

worker type의 특징 플래그를 사용하여 Sidekiq worker의 동작을 제어할 수 있습니다.

Sidekiq 작업 연기

비활성화되면 run_sidekiq_jobs_{WorkerName} 형식의 특징 플래그는 작업을 나중에 스케줄링함으로써 worker의 실행을 연기합니다. 이 특징 플래그는 모든 worker에 대해 기본적으로 활성화됩니다. 작업을 연기하는 것은 worker 인스턴스에서 경합적인 동작이 인프라 리소스(예: 데이터베이스 및 데이터베이스 연결 풀)를 포화시키는 사태 중에 유용할 수 있습니다. 구현은 SkipJobs Sidekiq 서버 미들웨어에서 찾을 수 있습니다.

참고: 기능 플래그가 비활성화된 상태에서 작업은 무기한으로 연기됩니다. worker가 안전하게 처리될 때 특징 플래그를 제거하는 것이 중요합니다.

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

# 어떤 작업도 실행되지 않으며 모든 작업이 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

참고: drop_sidekiq_jobs_{WorkerName} 특징 플래그는 run_sidekiq_jobs_{WorkerName}을 연기하는 특징 플래그보다 우선합니다. 즉, drop_sidekiq_jobs가 활성화되어 있고 run_sidekiq_jobs이 비활성화되어 있는 경우에는 작업이 완전히 삭제됩니다.