GO Feature Flagでお手軽フィーチャーフラグ導入

この記事は、CYBOZU SUMMER BLOG FES '24 (kintone Stage) DAY 3の記事です。

こんにちは、kintoneチームの川向です。

今回は簡単に使えるフィーチャーフラグシステムのGO Feature Flagを紹介します。

フィーチャーフラグとは

フィーチャーフラグは、コードを変えずに挙動を切り替える仕組みです。

コードのイメージはこちらです。newFeatureFlag.enabled()の結果が外部の設定ファイルやフィーチャーフラグシステムの設定によって変わり、それによって機能を切り替えます。

if ( newFeatureFlag.enabled() ) {
    newFeature();
} else {
    oldFeature();
}

これにより、新しい機能の一部のユーザへの段階的公開や、A/Bテストなどが可能になります。

フィーチャーフラグシステム: GO Feature Flag

フィーチャーフラグの仕組みはそれほど複雑ではないので自前で実装することもできますが、SaaSやOSSもあります。LaunchDarklyUnleashなどが有名です。

今回はすぐに使えるOSSのフィーチャーフラグシステムのGO Feature Flagを紹介します。

GO Feature Flagは以下のような特徴があります:

  • 設定ファイルでフラグを制御する。DBを使用しないので、運用が容易
  • フラグの公開制御が柔軟に行える
  • 複数言語のSDKがある
  • GO Feature Flag relay proxyというHTTPサーバーが提供されている
  • OpenFeatureをサポートしている

relay proxyを使った場合のシステム構成はこのようになります。

ソフトウェア内のコードがSDKを使ってHTTP経由でGO Feature Flag relay proxyにアクセスする。relay proxyは設定ファイルを参照している

使ってみよう

さっそく簡単なフラグをGO Feature Flagで使ってみましょう。

GO Feature Flag relay proxyの準備

まずは設定ファイルを2つ用意します。

# goff-proxy.yaml
# GO Feature Flag relay proxyの設定ファイル
retriever:
  kind: file
  path: /goff/flag.goff.yaml

# flag.goff.yaml
# フラグの定義ファイル
# newFeatureFlagというtrueかfalseを返すフラグを定義している
newFeatureFlag:
  variations:
    enable: true
    disable: false
  # 初期値はdisable(値はfalse)
  defaultRule:
    variation: disable

GO Feature Flagのrelay proxyをdockerで起動します。 先程の設定ファイルはワーキングディレクトリに配置している想定です。

$ docker run -v $(pwd)/goff:/goff/ -p 1031:1031 \
  gofeatureflag/go-feature-flag:v1.31.1
█▀▀ █▀█   █▀▀ █▀▀ ▄▀█ ▀█▀ █ █ █▀█ █▀▀   █▀▀ █   ▄▀█ █▀▀
█▄█ █▄█   █▀  ██▄ █▀█  █  █▄█ █▀▄ ██▄   █▀  █▄▄ █▀█ █▄█

     █▀█ █▀▀ █   ▄▀█ █▄█   █▀█ █▀█ █▀█ ▀▄▀ █▄█
     █▀▄ ██▄ █▄▄ █▀█  █    █▀▀ █▀▄ █▄█ █ █  █ 

GO Feature Flag Relay Proxy
_____________________________________________
{"level":"info","ts":1721955130.511597,"msg":"flag added","key":"newFeatureFlag"}
{"level":"info","ts":1721955130.511656,"caller":"api/server.go:115","msg":"Starting go-feature-flag relay proxy ...","address":"0.0.0.0:1031","version":"1.31.1"}

これで準備OKです。

JavaからGO Feature Flag relay proxyを参照する

次にGO Feature Flagを参照するコードを書いてみます。 今回はGO Feature FlagのJava SDKのページを参考に、Javaで書いてみます。

まずはライブラリのインストールを行います。 今回はGradleを使うので、build.gradleに以下を追記します。

implementation group: 'dev.openfeature', name: 'javasdk', version: '1.9.0'
implementation group: 'dev.openfeature.contrib.providers', name: 'go-feature-flag', version: '0.2.23'

いよいよこれを参照するコードを書きます。

// GO Feature Flagの設定
GoFeatureFlagProviderOptions options = GoFeatureFlagProviderOptions.builder().endpoint("http://localhost:1031/").build();
GoFeatureFlagProvider provider = new GoFeatureFlagProvider(options);

// OpenFeatureAPIへの登録
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProviderAndWait(provider); // 登録が完了するのを待つ
Client featureFlagClient = api.getClient();

// Contextの設定
String targetingKey = "abc"; // 何らかのユニークな値を指定する
EvaluationContext userContext = new MutableContext(targetingKey)
        .add("username", "john");

// 値の取得
Boolean newFeatureFlag = featureFlagClient.getBooleanValue("newFeatureFlag", false, userContext);
if (newFeatureFlag) {
    newFeature();
} else {
    oldFeature();
}

// 終了処理
api.shutdown();

これでフィーチャーフラグを使って機能を制御できるようになりました。

もとの設定ではdisable(値はfalse)だったので、oldFeature()が実行されます。 flag.goff.yamlを以下のように書き換えてrelay proxyを再起動すると、フラグがenable(値はtrue)に変わります。この状態で再度実行するとnewFeature()が実行されます。

...
   defaultRule:
-    variation: disable
+    variation: enable

他にもできること

先程の例のフラグは単純なON/OFFを切り替えるだけでしたが、 条件に応じて値を変えることもできます。

# flag.goff.yaml
# 特定のユーザーだけ新機能を有効化する
newFeatureFlag:
  variations:
    enable: true
    disable: false
  defaultRule:
    variation: disable
  targeting:
    # Contextで渡した値をもとにした条件を書くことができる
    # 条件に合致したときだけ評価値を変える事ができる
    - name: Johnだけ機能を有効にする
      query: username eq "john"
      variation: enable

A/Bテストのように、割合に応じた制御もできます。

# flag.goff.yaml
colorFlag:
  variations:
    yellow: "#FFFF00"
    green: "#008000"
  defaultRule:
    # 70%のユーザでyellowを選択し、30%のユーザでgreenを選択する
    percentage:
      yellow: 70
      green: 30

先程の例ではローカルファイルを直接参照していましたが、外部(S3やHTTP、GitHub)のファイルも取得できます。

# goff-proxy.yaml
retriever:
  # HTTP経由でフラグの設定ファイルを参照する
  kind: http
  url: https://example.com/flag.goff.yaml

OpenFeatureや他のフィーチャーフラグシステムについて

GO Feature FlagはOpenFeatureという仕様に沿っています。これはフィーチャーフラグの標準として策定が行われているものです。

このため、GO Feature Flagから他のツールに移行するときも、OpenFeatureに対応しているものであればproviderを差し替えるだけでOKです。

OpenFatureに対応しているフィーチャーフラグシステムは公式サイトで紹介されています。 前述のLaunchDarklyUnleashのproviderもあります。

まとめ

フィーチャーフラグとそれを実現するGO Feature Flagを紹介しました。

GO Feature Flagは他にも様々な機能があります。 KubernetesやAWSでの運用方法なども公式サイトで紹介されているので、 気になる方はぜひ調べてみてください。