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 개발의 기능 플래그 문서에서 더 자세히 다룹니다). 이 명령은 실험에 접하는 모든 사람의 절반이 control_로 할당되도록 하는 시나리오를 만듭니다. 25%는 _red 변형으로, 25%는 blue 변형으로 할당됩니다:
/chatops run feature set pill_color 50 --actors
이 예제의 경우, 균등 분포를 위해 명령을 50이 아닌 66%로 설정하도록 변경하세요.
주의:
실험 실행을 즉시 중지하려면 /chatops run feature set pill_color false 명령을 사용하세요.
경고:
ChatOps 명령을 사용할 때 --actors 플래그를 사용하는 것을 강력히 권장합니다. 다른 것은 변형 할당의 캐싱 처리 방식으로 인해 이상한 동작을 초래할 수 있습니다.
또한 HTML 래핑이 있는 HAML 파일에서도 이 실험을 구현할 수 있습니다:
#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일 경우 “클라이언트”)에게 “sticky”합니다. -
{ project: project }: 변형을 할당하고 현재 보고 있는 프로젝트에 “sticky”합니다. 특정 사용자가 어느 프로젝트를 보고 있을 때보다 프로젝트를 보는 것이 실험을 실행하는 데 더 유용하다면 이 방식을 고려하세요. -
{ group: group }: 프로젝트 예제와 유사하지만, 더 넓은 범위의 프로젝트와 사용자에게 적용됩니다. -
{ actor: current_user, project: project }: 변형을 할당하고 주어진 프로젝트를 보고 있는 사용자에게 “sticky”합니다. 이렇게 하면current_user가 보는 각 프로젝트에 대해 다른 변형 할당 가능성이 생성됩니다. 이는 이러한 실험이 높은 트래픽 부분에서 수행될 경우 큰 캐시 크기를 초래할 수 있음을 이해하세요. -
{ wday: Time.current.wday }: 현재 주의 요일에 따라 변형을 할당합니다. 이 예제에서는 금요일에 하나의 변형이 지속적으로 할당되고, 토요일에는 잠재적으로 다른 변형이 할당됩니다.
컨텍스트는 실험을 정의하고 보고하는 데 중요한 요소입니다. 이는 일반적으로 실험을 구현하는 방식에서 가장 중요한 측면이므로 신중하게 고려하고, 필요 시 더 넓은 팀과 논의하세요. 또한 선택한 컨텍스트가 캐시 크기에 영향을 미친다는 점을 염두에 두세요.
위의 예를 통해 우리는 일반적인 경우를 진술할 수 있습니다: 특정하고 일관된 컨텍스트를 제공하면 일관된 경험을 제공하고 해당 경험에 대한 이벤트를 추적할 수 있습니다. 구현 세부 사항을 좀 더 깊이 탐구하면, 제공된 컨텍스트에서 컨텍스트 키가 생성됩니다. 이 컨텍스트 키를 사용하여:
- 할당된 변형을 결정합니다.
- 해당 컨텍스트 키에 대해 추적된 이벤트를 식별합니다.
이것은 우리가 렌더링한 경험으로 생각할 수 있으며, 이는 컨텍스트 키에 의해 결정되고 추적됩니다. 컨텍스트 키는 우리가 렌더링한 경험의 상호작용과 결과를 추적하는 데 사용됩니다. 이러한 개념은 초기에는 다소 추상적이고 이해하기 어려울 수 있지만, 이 접근 방식은 우리에게 사용자 행동 이상으로 실험에 대해 소통할 수 있게 해줍니다.
주의:
actor:를 사용하면 current_user가 nil일 경우 쿠키를 사용합니다. 그러나 쿠키가 필요하지 않다면 - 즉, 노출된 기능이 인증된 사용자에게만 표시되도록 해야 한다면 - { user: current_user }도 효과적입니다.
경고:
변형 할당의 캐시는 이 컨텍스트를 사용하여 처리되므로 실험을 정의할 때 캐시 크기에 미치는 영향을 고려하세요. { time: Time.current }를 사용하면 실험이 실행될 때마다 캐시 크기가 증가하게 됩니다. 뿐만 아니라, 귀하의 실험은 “sticky”하지 않으며 이벤트가 해결되지 않을 것입니다.
고급 실험
실험을 구현하는 두 가지 방법이 있습니다:
- 이전에 설명한 기본 실험 스타일.
- 실험 클래스가 제공되는 더 고급 스타일.
고급 스타일은 네이밍 규칙에 의해 처리되며, Rails에서 기대하는 것과 유사하게 작동합니다.
기본값을 재정의할 수 있는 사용자 정의 실험 클래스를 생성하려면 Rails 생성기를 사용하십시오:
rails generate gitlab:experiment pill_color control red blue
그러면 사용자 정의한 _behaviors_가 포함된 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
우리가 실험 클래스에서 정의한 _behaviors_는 기본 구현을 나타냅니다. 그러나 이러한 _behaviors_를 재정의하기 위해 블록 구문을 사용할 수 있으므로, 다음과 같은 방식도 유효합니다:
experiment(:pill_color, actor: current_user) do |e|
e.control { '<strong>control</strong>' }
end
experiment 메서드에 블록을 전달하면, run이 호출된 것처럼 암시적으로 실행됩니다.세분화 규칙
런타임 세분화 규칙을 사용하여 특정 변형으로 컨텍스트를 세분화할 수 있습니다. segment 메서드는 콜백(예: before_action)과 같으며 블록이나 메서드 이름을 제공할 수 있습니다.
이 예제에서는 이름이 'Richard'인 모든 사용자가 항상 red 변형에 할당되고, 2주 이상의 오래된 계정은 blue 변형에 할당됩니다:
class PillColorExperiment < ApplicationExperiment
# ...등록된 behaviors
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'인 모든 사용자가 계정 나이에 관계없이 항상 red 변형에 할당됩니다. 반대 논리를 원한다면 순서를 바꾸십시오.
배제 규칙
배제 규칙은 세분화 규칙과 유사하지만, 특정 컨텍스트가 실험에 포함되어 이벤트를 추적할 수 있는지 여부를 판단하는 데 사용됩니다. 배제란 주어진 컨텍스트와 관련된 이벤트에 대해서는 신경 쓰지 않는 것을 의미합니다.
이 예제에서는 이름이 'Richard'인 모든 사용자와 2주 이상 된 모든 계정을 배제합니다. 이들은 제어 행동이 주어지며 - 그것이 아무것도 아닐 수 있습니다 - 이 경우에는 아무 이벤트도 추적되지 않습니다.
class PillColorExperiment < ApplicationExperiment
# ...등록된 behaviors
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
# ...등록된 behaviors
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 이벤트가 그들에게 추적됩니다.
참고: GitLab은 추적과 관련하여 고객을 민감하게 존중하려고 하므로, 우리의 실험 라이브러리는 식별 ID를 추적하지 않고도 실험을 구현할 수 있게 합니다. 그러나 실험 보고 요구 사항에 따라 항상 가능하지는 않습니다. 때때로 실험에서 특정 레코드 ID를 추적하도록 요청받을 수 있습니다. 접근 방식은 구현을 만드는 PM과 엔지니어에 따라 크게 달라집니다. 현재 이와 관련하여 추천 사항은 제공되지 않습니다.
클라이언트 레이어의 실험
요청 생명주기에서 실행된 모든 실험은 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 슬롯이 존재할 경우 사용됩니다.
도움말