A/B/n 실험 구현
실험 구현
일반적인 개발 피처 플래그처럼 bin/feature-flag
명령을 사용하여 특징 플래그를 생성하여 실시할 수 있습니다. 반드시 타입으로 experiment
를 사용하고 피처 플래그(실험)를 pill_color
라고 이름 지어주세요. 이는 다음과 같습니다.
bin/feature-flag pill_color -t experiment
원하는 특징 플래그를 생성한 후, 코드에서 즉시 실험을 구현할 수 있습니다. 기본 실험 구현은 다음과 같습니다.
experiment(:pill_color, actor: current_user) do |e|
e.control { 'control' }
e.variant(:red) { 'red' }
e.variant(:blue) { 'blue' }
end
해당 코드를 실행하면 실험이 실행되고 변형이 할당되며(컨트롤러나 뷰 내) 클라이언트 레이어에 window.gl.experiments.pill_color
과 같은 세부 정보가 사용 가능한 객체가 생깁니다.
- 할당된 변형.
- 클라이언트 추적 이벤트에 대한 컨텍스트 키.
또한 실험이 실행되면 실험 :assignment
를 위해 이벤트가 추적됩니다. 나중에 이벤트, 추적, 클라이언트 레이어에 대해 더 많이 배웁니다.
로컬 개발에서 특징 플래그 인터페이스를 사용하여 실험을 활성화할 수 있습니다. 또한, 관련 실험을 제공하여 특징 플래그를 활성화할 때 특정한 경우를 대상으로 할 수 있습니다.
# 모든 사용자에게 활성화
Feature.enable(:pill_color)
# `experiment` 메서드 가져오기 -- 이미 컨트롤러, 뷰 및 메일러에 있음
include Gitlab::Experiment::Dsl
# 첫 번째 사용자에게만 활성화
Feature.enable(:pill_color, experiment(:pill_color, actor: User.first))
환경에 실험 특징 플래그를 롤아웃하려면 다음과 같이 ChatOps를 사용하여 명령을 실행하세요(GitLab에서 개발 중인 피처 플래그s 문서에서 자세히 다룹니다). 이 명령은 실험을 만날 모든 사람 중 절반은 컨트롤_에 할당되고, 25%는 _빨간색 변형에 할당되며, 25%는 파란색 변형에 할당될 수 있는 시나리오를 생성합니다.
/chatops run feature set pill_color 50 --actors
이 예를 기준으로 고르게 분배하려면 여기 있는 명령을 50% 대신 66%로 변경하세요.
/chatops run feature set pill_color false
명령을 사용하세요.--actors
플래그를 사용하는 것을 강력히 권장합니다. 그렇지 않으면 변형 할당의 캐시 처리 방식 때문에 이상한 동작이 발생할 수 있습니다.이 실험은 HAML 파일에 HTML 래핑을 사용하여 구현할 수도 있습니다:
#cta-interface
- experiment(:pill_color, actor: current_user) do |e|
- e.control do
.pill-button control
- e.variant(:red) do
.pill-button.red red
- e.variant(:blue) do
.pill-button.blue blue
컨텍스트의 중요성
이전 예시 실험에서 컨텍스트(중요한 용어)는 { actor: current_user }
로 설정된 해시입니다. 컨텍스트는 실험 실행 방식에 기반하여 고유해야 하며, 하위 수준에서 이해되어야 합니다.
이로부터 보고를 간소화하기 위해 이러한 컨텍스트 중 일부를 사용하는 것이 기대되고 권장됩니다.
-
{ actor: current_user }
: 변형을 할당하여 실험에 참여하는 각 사용자(또는current_user
가 nil이면 “클라이언트”)에 대해 “고정”됩니다. -
{ project: project }
: 보기 위한 프로젝트에 변형을 할당하며 “고정”됩니다. 특정 사용자가 아닌 모든 프로젝트를 보는 것이 별로 유용할 때 실험을 실행할 때 이 방식을 고려하세요. -
{ group: group }
: 프로젝트 예제와 유사하지만 보다 넓은 범위의 프로젝트 및 사용자에 적용됩니다. -
{ actor: current_user, project: project }
: 특정 사용자가 주어진 프로젝트를 보고 있는 경우 변형을 할당하여 “고정”됩니다. 이는 응용 프로그램의 높은 트래픽 부분에 이러한 실험을 실행할 때 큰 캐시 크기를 생성할 수 있다는 것을 이해해야 합니다. -
{ wday: Time.current.wday }
: 현재 요일에 기반하여 변형을 할당합니다. 이 예에서는 금요일에는 항상 동일한 변형을 할당하고 토요일에는 다른 변형을 할당할 것입니다.
컨텍스트는 실험을 정의하고 보고하는 방식에 중요합니다. 실험을 어떻게 구현할지 신중하게 고려하고 필요하면 팀과 의논하세요. 또한, 선택한 컨텍스트가 캐시 크기에 영향을 미친다는 것을 고려하세요.
위의 예시를 통해 일반적인 경우를 명시할 수 있습니다: 특정하고 일관된 컨텍스트가 제공되면 해당 경험에 대한 일관된 경험을 제공하고 해당 경험에 대한 이벤트 추척을 할 수 있습니다. 구현 세부사항에 대해 조금 더 깊게 들어가보면, 컨텍스트 키는 제공된 컨텍스트에서 생성됩니다. 이 컨텍스트 키를 사용하여 다음을 수행할 수 있습니다.
- 할당된 변형 결정.
- 해당 컨텍스트 키에 대한 추적된 이벤트 식별.
우리는 이를 사용자 동작 이상으로 넓은 무언가로 실험에 대해 의사소통할 수 있도록 하는 접근으로 생각할 수 있습니다. 이러한 개념은 처음에는 다소 추상적이고 이해하기 어렵지만, 이 방식을 사용하면 실험의 결과와 상호 작용을 추적할 수 있습니다.
actor:
를 사용하면 current_user
가 nil인 경우 쿠키를 사용합니다. 그러나 쿠키가 필요하지 않다면 - 즉 노출된 기능이 인증된 사용자에게만 표시될 경우 - { user: current_user }
역시 효과적입니다.{ time: Time.current }
을 사용하면 실험이 실행될 때마다 캐시 크기가 증가합니다. 뿐만 아니라 실험은 “고정”되지 않으며 이벤트는 해결되지 않습니다.심화된 실험
실험을 구현하는 두 가지 방법이 있습니다.
- 이전에 설명한 기본적인 실험 스타일.
- 실험 클래스를 제공하는 더 심화된 스타일.
고급 스타일은 명명 규칙으로 처리되며, Rails에서 예상하는 대로 작동합니다.
ApplicationExperiment
의 기본값을 재정의할 수 있는 사용자 지정 실험 클래스를 생성하려면 다음 Rails 생성기를 사용하세요.
rails generate gitlab:experiment pill_color control red blue
이렇게 하면 제공된 _동작_으로 app/experiments/pill_color_experiment.rb
에 실험 클래스가 생성됩니다. 여기에 있을 게 아니라 우리가 초기에 제공했던 블록을 재정의하기 위해 _동작_을 실험 클래스에 정의해보겠습니다.
class PillColorExperiment < ApplicationExperiment
control { 'control' }
variant(:red) { 'red' }
variant(:blue) { 'blue' }
end
이제 실험을 실행하는 곳을 다음 호출로 간소화할 수 있습니다. 초기에 제공했던 블록을 제공하는 대신 명시적으로 run
을 호출합니다.
experiment(:pill_color, actor: current_user).run
실험 클래스에서 정의한 _동작_은 기본 구현을 나타냅니다. 그러나 이러한 _동작_을 재정의하기 위해 여전히 블록 구문을 사용할 수 있으므로 다음과 같은 것도 유효합니다.
experiment(:pill_color, actor: current_user) do |e|
e.control { '<strong>control</strong>' }
end
experiment
메서드에 블록을 전달할 때는 암시적으로 run
이 호출된 것처럼 암시적으로 호출됩니다.세분화 규칙
런타임 세분화 규칙을 사용하여 예를 들어 컨텍스트를 특정 변형으로 세분화할 수 있습니다. segment
메서드는 before_action
과 같이 콜백이므로 블록이나 메서드 이름을 제공할 수 있습니다.
이 예에서는 'Richard'
라는 이름의 사용자는 항상 빨간 변형이 할당되고, 2주 이상 된 계정은 파란 변형이 할당됩니다.
class PillColorExperiment < ApplicationExperiment
# ...등록된 동작들
segment(variant: :red) { context.actor.first_name == 'Richard' }
segment :old_account?, variant: :blue
private
def old_account?
context.actor.created_at < 2.weeks.ago
end
end
실험이 실행될 때 세분화 규칙이 정의된 순서대로 실행됩니다. 참 값 결과를 생성하는 첫 번째 세분화 규칙이 변형을 할당합니다.
이 예에서는 계정 연령에 관계없이 어떤 사용자든 'Richard'
라는 이름을 가진 사용자는 항상 빨간 변형이 할당됩니다. 반대로 논리를 바꾸려면 순서를 바꿔야 합니다.
제외 규칙
제외 규칙은 세분화 규칙과 유사하지만, 실험에 대한 이벤트를 추적하고 포함해야 하는지를 결정하는 데 사용됩니다. 제외는 주어진 컨텍스트에 대한 이벤트에 관심을 두지 않는다는 것을 의미합니다.
이 예에서는 'Richard'
라는 이름을 가진 모든 사용자와 2주 이상 된 계정을 제외합니다. 그들에게는 통제 동작이주어지고 - 아무것도 될 수 있습니다 - 아직 이러한 경우에는 이벤트도 추적되지 않습니다.
class PillColorExperiment < ApplicationExperiment
# ...등록된 동작들
exclude :old_account?, ->{ context.actor.first_name == 'Richard' }
private
def old_account?
context.actor.created_at < 2.weeks.ago
end
end
사용자 정의 추적 로직에서 제외를 확인해야 할 수도 있습니다. should_track?
를 호출하여 사용자 정의 추적 로직에서 제외를 확인해야 할 수도 있습니다:
class PillColorExperiment < ApplicationExperiment
# ...등록된 동작들
def expensive_tracking_logic
return unless should_track?
track(:my_event, value: expensive_method_call)
end
end
이벤트 추적
실험의 가장 중요한 측면 중 하나는 데이터를 수집하고 보고하는 것입니다. track
메서드를 사용하여 실험 구현 전체에 걸쳐 이벤트를 추적할 수 있습니다. 실험에 대한 동일한 컨텍스트를 제공한다면 호출 시마다 일관되게 이벤트를 추적할 수 있습니다. 컨텍스트를 이해하지 못하면 지금 바로 컨텍스트에 대해 읽어야 합니다.
우리는 실험을 한 곳이나 몇 군데에서 실행했다고 가정할 수 있지만, 이벤트를 여러 군데에서 추적할 수 있습니다. 추적 호출은 여전히 동일하며, 일반적으로 snowplow를 사용하여 이벤트를 추적할 때 사용하는 인수들과 동일합니다. 루비에서 이벤트를 추적하는 가장 간단한 예는 다음과 같습니다:
experiment(:pill_color, actor: current_user).track(:clicked)
지금까지의 예제 중 하나를 실행하면 기본적으로 :assignment
이벤트가 자동으로 추적됩니다. 실험에서 추적되는 모든 이벤트에는 특별한 실험 컨텍스트가 이벤트에 추가됩니다. 이는 일반적으로 데이터 팀에 의해 사용되어 실험의 이벤트 간에 연결을 만드는 데 사용될 수 있습니다.
만일 사용자가 실험에 아직 만나지 않았다면(실험이 실행된 위치) 그리고 우리가 그들을 위해 이벤트를 추적하면, 그들은 변형이 할당되어 나중에 실험을 만났을 때 해당 변형이 표시되며, 해당 사용자에 대해 그 때 :assignment
이벤트가 추적됩니다.
클라이언트 레이어의 실험
요청 라이프사이클에서 실행된 실험은 window.gl.experiments
에 표면화되며, 이 스키마와 일치합니다. 따라서 클라이언트 레이어에서 실험을 해결할 때 사용될 수 있습니다.
우리가 실험에 대한 클래스를 정의했고, 그에 대한 변형을 정의했다면, 이를 몇 가지 방법으로 발표할 수 있습니다.
첫 번째 방법은 실험을 실행하는 것입니다. 실험이 실행된 경우 특별한 작업을 수행할 필요 없이 클라이언트 레이어에 표면화됩니다.
두 번째 방법은 실험을 실행하지 않고, 실험이 반드시 클라이언트 레이어에 표면화되어야 하는 경우에 사용됩니다. 이를 위해 실험을 .publish
할 수 있습니다. 이는 어떤 로직도 실행하지 않지만 실험 세부 정보를 클라이언트 레이어에 표면화하여 거기서 사용할 수 있도록 합니다.
예를 들어, 컨트롤러의 before_action
에서 실험을 발표할 수 있습니다. 위에서 정의한 PillColorExperiment
클래스를 가정했을 때 실험을 실행하는 대신에 실험을 발표하기 위해 다음과 같이 할 수 있습니다:
before_action -> { experiment(:pill_color).publish }, only: [:show]
그러면 JavaScript 콘솔에서 다음을 확인할 수 있습니다:
window.gl.experiments // => { pill_color: { excluded: false, experiment: "pill_color", key: "ca63ac02", variant: "candidate" } }
Vue에서 실험 사용
gitlab-experiment
컴포넌트를 사용하면 window.gl.experiments
에 푸시된 변형의 이름과 일치하는 슬롯을 정의할 수 있습니다.
우리는 Vue 컴포넌트에서 정의된 동작에 일치하는 이름의 슬롯을 사용할 수 있습니다:
<script>
import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
export default {
components: { GitlabExperiment }
}
</script>
<template>
<gitlab-experiment name="pill_color">
<template #control>
<button class="bg-default">기본 버튼 클릭</button>
</template>
<template #red>
<button class="bg-red">빨간 버튼 클릭</button>
</template>
<template #blue>
<button class="bg-blue">파란 버튼 클릭</button>
</template>
</gitlab-experiment>
</template>
window.gl.experiments
객체에 실험 이름에 대한 실험 데이터가 없는 경우, control
슬롯이 사용됩니다(있는 경우).