본문 바로가기
프로그래밍 개발/IT 서비스 개발 운영

서비스 운영 A/B 테스트 적용기 (feat. Firebase)

by Jinseok Kim 2023. 8. 14.
반응형

서비스 운영 A/B 테스트 적용기

A/B 테스트는 여러 많은 서비스에서 쓰이고 있는 아주 기본적인 테스트입니다. 해외 서비스는 인스타그램, 국내는 토스 등등 대표적인 서비스들도 많이 사용하는 테스트입니다. 말 그대로 A, B 두 조건의 기능 두 개를(두 개 이상이도 됩니다.) 50대 50으로 기능을 사용자들에게 골고루 배포하여 사용자들의 기능 사용 수치와 효율성을 비교하여 따져보는 것입니다.

무작정 예측으로만 기능을 때려박아 수치가 올라가는 것을 지켜보기만 하는 것이 아니라 직접 기능의 수치를 측정하여 사용자들이 진심으로 원하는 것을 현실적으로 파악하여 냉정하게 기능을 빼기도 하며 많은 도움이 되지 못할 것 같은 예상치 못한 기능들이 들어가는 경우도 있었습니다.

실제 제가 운영중인 서비스도 A/B 테스트를 통해 사용자들이 진심으로 원하는 것과 프로덕트팀에서 이게 더 사용자들이 원할 것이라는 것과 정말 달랐다는 것도 알게 되기도 하였습니다.

A/B 테스트 기능을 구현하려면 프론트단이 아닌 동적으로 컨트롤할 수 있는 서버단이 필요하게 되는데 제가 지금 운영 중인 서비스에서는 Firebase에서 제공하는 A/B 테스트 기능을 적극 활용하여 구현하였습니다.

 

 

 

 

 

 

 

Firebsae A/B 테스트 Firebase Console 세팅 적용


 

 


지금 이 글을 포스팅하고 있는 시점(2023.08.14)에 현재 진행중인 A/B 테스트 케이스를 예를 들어 설명해 드려고 합니다.

휴대폰 인증을 하라는 UX 문구를 수정하여 어떤 문구가 더 회원가입 성공 전환율을 높이는지 테스트하는 케이스입니다. 기존 문구와 위의 이미지 두 케이스를 포함하여 총 3개 A, B, C 케이스를 테스트하게 되었습니다.

 

즉 2개의 가설을 추가하여 사용자들에게 직접 테스트 한다는 의미입니다.

기존 문구를 포함시킨 이유는 기존 문구가 새로운 문구 두 케이스보다 못한 가능성이 있기 때문이었습니다. 

 

 



 

Firebase | Google’s Mobile and Web App Development Platform

Discover Firebase, Google’s mobile and web app development platform that helps developers build apps and games that users will love.

firebase.google.com

Firebase 프로젝트를 생성했다는 가정하에 프로젝트 콘솔에 진입하여 왼쪽 사이드 메뉴를 보시면 A/B Testing이라고 친절하게 표시되어 있으니 클릭하여 진입합니다.


 

 

 

바로 실험 만들기 버튼을 클릭하여 A/B 테스트를 위한 본격적인 세팅을 시작합니다.




 

 

 


1.  기본사항에서 실험 이름을 정의합니다. 고유하고 실험의 의미가 잘 표현되도록 이름을 정의하면 될 거 같습니다. 저는 실험을 크게 OS별로 나눠 생성합니다. 그래서 ios, aos가 이름에 포함되어 생성하였습니다.

 

 

 

 

 

 

 

 

2. 타켓팅입니다. 중요한 세팅입니다. 위의 이미지의 예시는 OS가 Android인 앱이므로 앱은 안드로이드 프로젝트로 선택, 버전은 앞으로 A/B 테스트를 적용하여 업데이트 배포할 앱 버전, 국가는 서비스가 배포될 국가로 선택하면 됩니다.

저는 A/B 테스트를 위한 조건값들이 잘 들어오는 체크가 필요할때가 있습니다. 그래서 운영 중인 서비스에 영향이 있지 않도록 하기 위해 한국의 사용자는 개발팀밖에 없으니 국가/지역을 한국으로 설정하여 A/B 테스트가 잘 작동하는지 기능 테스트 합니다.



 

 

 

3. 목표는 sign_up이라는 변수로 설정하였습니다. sign_up은 저희 프로젝트 내에 유저가 회원가입이 성공하면 받아내는 값으로, 구글의 데이터 분석 기능인 GA에서 받은 값이라고 이해하시면 될 거 같습니다.

즉 궁긍적인 목표인 사용자가 회원가입에 성공하여 sign_up을 받아낸다면 설정한 A, B, C 케이스 중에 하나가 측정이 된다고 보시면 됩니다.



 

 

 

 

4. 마지막으로  변형입니다. 앞서 말씀드린 것처럼 기존의 값 그리고 새로운 두 개의 문구까지 해서 총 3개의 케이스를 설정하였습니다. 객체 형식처럼 key / key 값을 설정할 수 있습니다. default / case1 / case2 이렇게 저는 설정하였습니다.

대안 가중치는 각각 케이스별로 얼마큼 유저들에게 비중을 주어 노출시킬지 설정하는 값입니다. 보통은 케이스가 두 개면 50 대 50, 세 개면 3등분하는게 기본이 아닐까 싶습니다.

 

 

 

 

이제 세팅 설정이 끝나 검토 버튼을 클릭하여 마무리합니다.




검토후에 실험 조건들이 문제가 없으면 바로 실험 시작을 눌러 테스트를 바로 진행하게나 테스트를 시작하기 원하는 시간 때에 실험 시작을 할 수도 있습니다.

저는 A/B 테스트가 적용된 프로젝트 앱 버젼이 정식으로 스토어에 배포가 완료될 때 실험 시작을 합니다.

 

 

 

 

 

 

 

Firebsae A/B 테스트 프로젝트 세팅 및 적용


 

 

운영중인 앱 서비스는 React Native로 되어 있어  React Native을 기준으로 환경세팅을 하겠습니다.

    "@react-native-firebase/analytics": "^17.5.0",
    "@react-native-firebase/app": "^17.5.0",
    "@react-native-firebase/messaging": "^17.5.0",
    "@react-native-firebase/remote-config": "^17.5.0",

위와 같은 버전으로 Firebase 라이브러리를 npm 인스톨하였습니다.

 

 

또 Firebase Console에 적용하려는 프로젝트를 등록하고 프로젝트 Native 코드 또한 환경세팅이 필요합니다. 세팅 과정은 아래 제가 작성한 포스팅을 참고하시면 될 거 같습니다.

 

React native - 파이어베이스(FireBase) Ios, Android 세팅하기

파이어베이스 환경 세팅하기 파이어베이스를 react native 프로젝트에서 세팅하기 위해서는 ios 별 android별 환경 세팅을 각각 해줘야합니다. 일단 파이어베이스 홈페이지에 들어가서 공통적으로 프

k0502s.tistory.com

 

 

위의 세팅들이 끝나면 바로 스크립트단의 기능 구현으로 들어가면 됩니다.

 

 

 

 

저희 프로젝트에서는 React 커스텀 Hooks을 만들어 앱이 최초 실행하면 필수로 필요한 호출로 포함하여 앱이 실행하고 주요 기능들이 실행되기 전에 A/B 테스트 관련 조건 값들을 호출 및 Get 하여 리덕스 스토어에  데이터를 담고 있도록 하였습니다.

 


useAB.ts

import {useCallback} from 'react';
import remoteConfig from '@react-native-firebase/remote-config';
import {RootState, useAppDispatch, useAppSelector} from 'store';
import {setRemoteConfigValue, UIState} from 'store/ui';
import {Platform} from 'react-native';

const isAndroid = Platform.OS === 'android';

interface UseAB {
  remoteValue: {[key: string]: any};
  matchValue: (key: string, value: any) => boolean;
  fetchRemoteConfig: () => void;
}

const useAB = (): UseAB => {
  const {remoteValue}: UIState = useAppSelector((state: RootState) => state.ui);
  const dispatch = useAppDispatch();

  const fetchRemoteConfig = useCallback(async () => {
    // ? new feature A/B test
    await remoteConfig().setDefaults({
      // ? 1. set default Value
      // example : test_value:banner : 'default'
    });

    const fetchedRemotely = await remoteConfig().fetchAndActivate();

    // ! remoteConfig().fetchAndActivate()이 Aos에서 최초 한번 호출 후 false 반환하는 이슈때문에 Aos는 바로 통과
    if (fetchedRemotely || isAndroid) {
      const params = remoteConfig().getAll(); // A/B 테스트 조건 값 모두 가져오기
      let store: any = {};
      Object.entries(params).forEach(value => {
        const [key, entry] = value;
        store[key] = entry.asString();
      });
      dispatch(setRemoteConfigValue(store)); // 객체로 잘 가공한 A/B 테스트 조건 데이터 값들 리덕스 스토어에 저장
    }
  }, [dispatch]);

  const matchValue = useCallback(
    (key: string, value: any) => {
      return remoteValue[key] === value;
    },
    [remoteValue],
  );

  return {fetchRemoteConfig, remoteValue, matchValue}; // fetchRemoteConfig 함수를 hooks로 선언하여 앱이 실행할때 바로 호출
};

export default useAB;

 

 

 

리덕스 스토어에 담은 조건 값들을 A/B 테스트가 필요한 페이지 컴포넌트에서 가져와 아래와 같이 조건 케이스별로 분기처리할 수있는 값을 선언하여 A/B 테스트가 앱 업데이트 배포 후 테스트 시작 및 측정가능하도록 할 수 있게 되었습니다.

 

SubmitPhoneNumber.tsx

....  

const {remoteValue}: UIState = useAppSelector(
    (state: RootState) => state.ui,
  );

...

// 아래 선언한 값들을 통해 의도하려는 A/B 테스트 따른 조건을 분기처리하여 개발할 수 있게 되었습니다.

const isDefaultUxWriting = useMemo(
    () => remoteValue?.['조건 키값1'] === 'default',
    [remoteValue],
  );

const isCase1UxWriting = useMemo(
    () => remoteValue?.['조건 키값2'] === 'case1',
    [remoteValue],
  );

 

 

 

 

 

 

 

 

 

A/B 테스트 측정 결과 보기


 

 

 

현재 진행 중인 휴대폰 입력 안내 UX 문구 관련 A/B 테스트의 결과들입니다. 테스트 시작 한지 거의 보름이 지나고 있는데 B 케이스가 전환율이 더 높은 것을 확인할 수 있습니다. 

아마 곧 테스트를 마무리하고 프로덕트팀에서 검토후 B 케이스 UX 문구로 확정 지을 듯합니다.

반응형

댓글