# Feature flags 下的 A/B 测试

如今,大多数互联网产品野蛮生长的时代已经过去,人口红利到顶,产品策略需要从快糙猛的跑马圈地方式转向深耕细作的精细化运营方式,要精细化运营,就需要采用数据来驱动。

何为数据驱动?试想以下几种场景:

  • 小 A 凭着丰富的经验直接修改了产品的线上策略,一周后发现效果不升反降,遂下线。
  • 小 B 和小 C 同时上线了两个产品功能,一周后产品数据有下降,都认为是对方的问题,谁也不肯接锅。
  • 小 D 上线了一个新策略,随后进入十一黄金周,用户交互有所下降,小 D 觉得一定是假期埋没了自己的辛苦贡献,但也辩不明白,无处申冤。
  • 小 E 辛苦工作一整年,开发了 365 个不同的功能上线,年终写总结时却写不出到底在哪些方面究竟贡献了多少。
  • 小 F 被老板质疑功能为什么不按照他的想法做,但是小 F 却觉得自己的方案才更好。

因此,我们需要设计并坚持使用一套数据驱动的方法,使得业务人员可以以较小的风险对新 feature 进行评估,积极试错积累经验;并且我们设计的该方法有能力排除其他因素(比如同时开发的其他 feature 以及时间因素等)的干扰;最后,除了“好”或者“不好”,我们希望这个方法最好也能够给出定量的结果。

为了解决上述问题,普遍使用的方法论是小流量随机实验,也就是我们常说的 A/B 测试又叫 A/B 实验。

# A/B 测试

# 什么是 A/B 测试

我们在线上流量中取出一小部分(较低风险),完全随机地分给原策略 A 和新策略 B(排除干扰),再结合一定的统计方法,得到对于两种策略相对效果的准确估计(量化结果)。

# 为什么要开启 A/B 测试

策略的改变,不是由我们随便“拍脑袋”得出,而是一种建立在数据基础上的思维方式,数据反馈会告诉我们做的好不好,哪里有问题,以及衡量可以带来多少确定性的增长。

  1. 提高用户体验:AB 测试可以帮助你理解哪些功能、设计或内容能够提供更好的用户体验。

  2. 降低风险:在做出重大改变之前,你可以先进行 AB 测试来预测改变的影响,这样可以降低因改变导致的负面影响。

  3. 提高转化率:通过 AB 测试,你可以找出哪些因素能够提高转化率,如点击率、购买率等。

  4. 数据驱动决策:AB 测试提供了实证数据,帮助你做出更好的决策,而不是依赖于猜测或个人偏好。

# 怎么做 A/B 测试

  1. 确定测试目标:首先,肯定需要明确你想要改进或优化的目标。例如,提高转化率、增加用户点击率等。确保你的测试目标明确而具体,这样才能有针对性地进行测试。

  2. 选择测试变量:确定你想要进行测试的变量,这可以是页面布局、颜色方案、按钮文本等。根据测试目标选择合适的变量进行测试,确保你只改动一个变量,这样才能准确评估测试结果和效果。

  3. 制定测试假设:针对测试的变量和目标,制定一个明确的假设。例如,如果我将按钮颜色从红色改为蓝色,那么点击率将会提高。

  4. 随机分组:将你的用户随机分成两组,一组是控制组(Group A),应用原有的设计或策略;另一组是实验组(Group B),尝试新的设计或策略。确保两组之间没有明显的区别,以减少其他因素的干扰。

  5. 实施测试:根据测试的变量对控制组和实验组进行相应的设计或策略调整。确保对两个组别同等地应用这些变化,并确保测试环境和设置的一致性。

  6. 收集数据:在测试期间,收集有关用户行为和指标的数据。这可以包括点击率、转化率、用户满意度等。确保根据事先定义的指标去收集数据,以便后续的分析和比较。

  7. 分析结果:基于收集到的数据,对两个组别的指标进行比较和分析。使用合适的统计方法来评估测试结果的显著性和可靠性。

  8. 得出结论:根据分析结果,评估实验组和控制组之间的差异,并得出结论。如果实验组的指标显著优于控制组,那么改动是成功的。否则,需要重新考虑变量和策略的设计。

对于开发人员而言,其中 4,5,6 是我们关心的重点。如何创建一个随机分组,如何随机分流展示不同的分组,如何收集数据?

# Feature Management (功能管理平台)

# Feature flags(功能标记📌) (opens new window)

Feature flags 是一种将 "功能开关+ 灰度发布 + 远程配置 + ab 测试 + 版本控制 + 持续交付 + 订阅管理 + 等等" 多个能力融为一体的技术。

58F9F65F-3901-4754-8ED4-22D6E9B8E46B.png

在理解 Feature flags 的常规用法后,可以自己也可以通过简单的数据库+API 的方式实现一个简单的 Feature flags 系统。但在真正的使用时,往往需要性能更高、更稳定的系统,也同时需要考虑更复杂的应用场景、团队协同和企业生态集成等场景。

主流的一些功能管理平台:

  1. launchdarkly (opens new window):行业独角兽。是用来学习 feature flags 的应用场景和实施手段的好产品。但是他不支持中文。.. 且在国内调用有很高的延迟。他的部分 sdk 是开源的。
  2. Featbit (opens new window):国人独立团队发起的面对全世界的 Feature Management 开源项目。已有数十家来自全球的中大型企业购买其高级服务。以 .NET 为主要开发语言。
  3. Flagsmith (opens new window):一个做了有 2、3 年的 Open Core 开源的 feature flags 工具。以 Python 为主要开发语言。
  4. Unleash (opens new window):一个 Open Core 开源的工具,并且被 Gitlab 集成。但是想使用其高级功能,无论是在官网还是通过 gitlab,都需要单独付费。使用 Typescript 为主要开发语言。
  5. GrowthBook (opens new window):与其说是 Feature Flags,其实是家 AB 测试公司。是著名伪 Feature Flags 产品(实际上是 AB 测试产品) StatSig 的开源 Alternative。使用 Typescript 为主要开发语言。

more... (opens new window)

# FeatureProbe (opens new window)

一款国内功能管理平台:FeatureProbe 包含『功能粒度』的发布管理、灰度放量、降级预案、AB 实验等一系列管理操作。它可以让开发人员、运营人员、运维人员安全、高效的完成功能交付,同时精细控制变更风险 FeatureProbe 提供高性能的服务,所有主流语言的 SDK,可以为各类技术栈的软件项目提供持续交付时代下的最先进的『功能管理』服务。

C141F8F0-B4C6-4285-98DC-C57DABE5FA2C.png

FeatureProbe 架构:

  1. 用户通过 FeatureProbe UI 界面去管理和发布 功能开关(flags)

  2. 前端用户访问的时候,使用提供的各端 SDK 访问远程 API 接口,获取功能开关的配置,开发者根据获取的变量值,实现不同的逻辑处理。

在开始实验之前,我们先创建一个 FeatureProbe Server 环境。

# FeatureProbe Server 环境搭建 (opens new window)

使用 docker 部署

  1. 用 git 下载最新版本 FeatureProbe 代码

    git clone https://gitee.com/featureprobe/FeatureProbe.git
    
  2. 使用 docker composer 拉取镜像并启动 ( docker 报错可能需要更新 docker )

    cd FeatureProbe
    docker compose up
    
  3. 等待镜像拉取,视网络状况,可能需要 5-10min

    50BFF948-AA0C-414D-9A4F-64B5758DD232.png

  4. 等待镜像启动,大约 1min 左右,启动成功后命令行可以看到日志滚动。也可在 docker GUI 工具中查看镜像启动状况,全部绿色即为启动成功

  5. 验证结果 打开浏览器,访问 http://localhost:4009 (opens new window) 账号:admin ,密码:Pass1234

  6. 创建一个 demo 的项目,为后续实验做准备

594E07C5-F5FC-45E0-B853-EC078B5211E8.png

# 前端环境搭建

FeatureProbe 当前支持的客户端 SDK 为:

我们以 vite + react 前端项目来进行实例展示:

  1. 创建项目

    # pnpm
    pnpm create vite AB-demo --template react-ts
    
  2. 安装依赖

    cd AB-demo
    pnpm install
    pnpm run dev
    
  3. 安装 React SDK (opens new window)

    pnpm add featureprobe-client-sdk-react
    
  4. 接入 React SDK 异步初始化开关:AsyncFPProvider (opens new window)

    // src/main.tsx
    
    import React from "react";
    import ReactDOM from "react-dom/client";
    import App from "./App.tsx";
    import "./index.css";
    
    import { AsyncFPProvider, FPUser } from "featureprobe-client-sdk-react";
    const user = new FPUser();
    (async () => {
      const FPProvider = await AsyncFPProvider({
        remoteUrl: "http://127.0.0.1:4007", // docker 启动地址
        clientSdkKey: "client-8df679ff642ccd8194cb6d80f60e93cb627a3a4a", // 项目 key 
        user,
        refreshInterval: 5000,
      });
    
      const root = ReactDOM.createRoot(document.getElementById("root"));
    
      root.render(
        <FPProvider>
          <App />
        </FPProvider>
      );
    })();
    
    

    remoteUrl 和 clientSdkKey 从项目入口获取

    CE92E5A5-FCE4-46E0-8936-3EECD3ADF135.png

# 开始 A/B 测试

按照上文中的如何做 A/B 测试,我们以一个实际例子来带大家一步步实现:

某 APP 的支付按钮的颜色想由红色改为了蓝色,针对这两种颜色对用户做个实验,看到底哪个颜色点击率更高

  1. 确定测试目标:我们想提高点击下单按钮的点击率。
  2. 选择测试变量:支付按钮的颜色想由红色改为了蓝色。
  3. 制定测试假设:如果我将按钮颜色从红色改为蓝色,那么点击率将会提高。
  4. 随机分组:A 组红色按钮,B 组蓝色按钮。
  5. 实施测试:按照规则将流量分别分配到 A 组和 B 组(开发中通过刷新来模拟不用用户的进入)。
  6. 收集数据:点击上报数据,对比两个实验组的点击数。
  7. 分析结果:使用合适的统计方法来评估测试结果的显著性和可靠性。
  8. 得出结论:根据结果分析,得出结论。

# 创建一个红蓝按钮开关

5280E114-5ECE-4D09-8085-F3CB7E972851.png

  1. 配置分流规则并发布生效:

    E24ECA07-88A3-446C-9A59-DCBC248B3C90.png

    这里我们配置最简单的规则,根据流量随机平均分配,在实际的业务场景中,会根据用户、设备、地区、VIP 等特征点进行精细化去设置分流规则。

  2. 在前端代码中使用

    使用 useFPClient (opens new window) hooks 去获取 client 实例,调用 boolValue 传入开关标识符获取结果,根据结果去处理不同逻辑。

    import "./App.css";
    import { useFPClient } from "featureprobe-client-sdk-react";
    
    function App() {
      const client = useFPClient();
      const flag = client?.boolValue("isRed", true); // flag 标识
      return (
        <>
          <h3>AB 测试:支付按钮红色好,还是蓝色好</h3>
          <div>
            {flag ? (
              <button
                type="button"
                onClick={() => {
                  console.log("红色按钮");
                }}
                style={{ backgroundColor: "red" ,color:'white'}}
              >
                立即支付
              </button>
            ) : (
              <button
                type="button"
                onClick={() => {
                  console.log("蓝色按钮");
                }}
                style={{ backgroundColor: "blue",color:'white' }}
              >
                立即支付
              </button>
            )}
          </div>
        </>
      );
    }
    
    export default App;
    
    
  3. 不断刷新模拟新用户进来的效果,可以看到每次都是在红蓝按钮之间改变。

    按钮刷新。gif

    在实际场景中,我们应该永远保证单个用户进来看到的效果始终相同。用户稳定进入灰度组 (opens new window)

  4. 流量观测

    415C458E-3060-4C69-A682-554C9E3725F5.png

  5. 数据分析

    • 我们可以通过 FeatureProbe 自带的指标分析,创建一个自定义事件 2AC69522-97AC-46B4-9B2F-0EEB37085558.png
    • 上报数据
      ···
      <button
        type='button'
        onClick={() => {
          client?.track('isRedClick');// 添加自定义事件上报
        }}
        style={{ backgroundColor: 'red', color: 'white' }}>
        立即支付
      </button>
      ···
    

    FA7D4B6F-1AEE-4136-9526-3D71DF567DEC.png

    • 查看指标分析(FeatureProbe 上报数据似乎有点 BUG,已经提交 Issues (opens new window),下图非正式数据)

    DECA5DD4-8777-4CBC-8018-F56566A4DDF3.png

    • 得出实验结论。

目前为止一个简单的 A/B 实验就完成了。

# 总结

通过上面一个简单的 A/B 测试实验,发现对于服务端而言,基本的功能主要是 flags 数据存储规则分流,对于客户端而言是通过 API 请求 flags 的结果进行逻辑处理。

A/B 测试 Flag 是 Boolean 类型,还有其他的功能特性一样也是:

功能开关:可以针对白名单规则分流,将功能开发给指定的用户。

灰度发布:我们发布一个新功能或上线一个新运营活动时,可以先为一小部分用户启用这些功能,而不影响大多数用户,确保降低发布的风险。如果这些用户在使用中没有问题,我们就可以向更多的用户开放新版本。

在回到上面对于 Feature flags 的定义会发现:

功能开关+ 灰度发布 + 远程配置 + ab 测试 + 版本控制 + 持续交付 + 订阅管理 ...

就是通过 Feature flags,团队可以在运行时动态地更改功能的状态,实现按需启用、禁用和调整功能的能力。

那么对于前端而言,在中间就要处理的是不同的返回类型,才能更优雅的封装使用不用返回值,并在大量实验的开关过程中保持一定的可阅读和可维护性是前端所要解决的(下期再见👋🏻)。

# 参考网址