⛳
頑張って追いつくAgent Week : Flagship
今北産業
- Cloudflare上で遅延ゼロで動く、超高速な機能出し分けサービス「Flagship」
- ユーザー属性やパーセント指定で、新機能のON/OFFをコード再デプロイなしでダッシュボードから一瞬で切り替え可能
- いつでも安全にテストや段階的リリース(カナリアリリース)ができる。
何ができる?
要は : 機能の出し分けができる
内部実装はDO+KVらしい。
具体的にできること
- エッジ環境での「遅延ゼロ」の機能評価・ルーティング
- Workers内部やHonoなどでAPIを構築している場合、
env.FLAGSを使うことで、外部通信なしで即座にフラグを評価。 - リクエストの処理経路の瞬時切り替え。
- 例えば、移行テスト時や、新アルゴリズムの検証時などに、ユーザーの体感速度を落とさずにバックエンドのロジックを分岐。
- コンテキスト(ユーザー属性)に基づいた柔軟な出し分け
- フラグをただON/OFFするだけでなく、リクエストに含まれる様々な情報(ユーザーID、契約プラン、アクセス元の国、メールアドレスなど)を組み合わせてルール化できます。
- 「特定の管理者やスタッフ権限を持つユーザーにだけデバッグ用のUIを表示する」「特定のドメインからのアクセスにだけ先行機能を解放する」など、属性ベースのアクセス制御や機能提供を、コードを書き換えることなくダッシュボードから変更ができる。
- 段階的公開(パーセンテージロールアウト)
- 新機能をいきなり全員に公開するのではなく、「まずは5%のユーザーから」といったような公開ができる。
- 例えばモバイルやWebフロントで新UIをテストする際、
Sticky bucketing(固定割り当て)により、ユーザーIDをベースに同じユーザーには常に同じ状態(ONならずっとON)を提供。
- JSONオブジェクトや数値/文字列の動的配信
- フラグの戻り値は、単純な真偽値(Boolean)だけでなく、文字列、数値、JSONオブジェクトも扱えます。また、TypeScript環境では型安全に値を取得可能(getBooleanValue、getObjectValueなど)。
- 例えばテーマカラーの設定値、APIのレートリミットの上限、UIのレイアウト構成データなどをJSONで持たせておくことで、アプリ自体のアップデートやデプロイを介さずに、サーバー側から動的に変更ができるように。
- 「OpenFeature」対応
- Cloudflareにロックインせず、フィーチャーフラグの業界標準規格である「OpenFeature」を採用。
- もし将来的にFlagship以外のプロバイダー(LaunchDarklyなど)に移行したくなった場合でも、アプリケーション側の評価ロジックを大幅に書き換える必要がない。
うれしそうなこと
- Flagshipを読むWorkerを作成し、Service Bindingで連携させればWorkerごとに変更ができそう。
- なんならDynamic Workerと繋げたらもっと面白そう
- OpenFeature クライアントサイドSDKを使うことで直接取りに行くこともできるので、ボタンの表示・非表示などもこれで処理できる..?これは嬉しい。
- なんならServerside-SDKもあるそうなので、使うためにWorkers必須というわけでもないらしい。
書き方
サーバーサイド
export default {
async fetch(request, env) {
// 1. フラグの評価(コンテキストを渡して即判定)
const isNewUI = await env.FLAGS.getBooleanValue('new-ui', false, {
userId: 'user-123'
});
// 2. 処理の分岐
if (isNewUI) {
return new Response("新機能のデータを返す");
} else {
return new Response("従来のデータを返す");
}
}
}
クライアントサイド
import { OpenFeature } from '@openfeature/web-sdk';
// 1. 初期化(アプリ起動時に1度だけ実行し、フラグ一覧を取得)
await OpenFeature.setProviderAndWait(new FlagshipClientProvider({ ... }));
const client = OpenFeature.getClient();
// 2. 必要な画面でフラグの評価
function MyPage() {
const isNewUI = client.getBooleanValue('new-ui', false);
// 3. 画面の出し分け
if (isNewUI) {
return <NewDesignButton />
} else {
return <OldDesignButton />
}
}
Discussion