AI事業本部 オンライン接客事業部の村松です。オンライン接客システム「リモてなし」の開発チームの中で、バックエンドやインフラ周りを主に担当しています。

リモてなしでは、導入企業様ごとに「ニーズに合わせたカスタマイズ機能の提供」をできることを一つの売りにしていますが、フィーチャーフラグ [^1] を活用してカスタマイズ機能の出しわけを実現しています。

この記事では、リモてなしにおいて、どのように考えて現在のフィーチャーフラグの仕組みに至ったかについて説明し、現在のフィーチャーフラグの管理方法や実装について紹介します。

目次

リモてなしの概要

リモてなしの概要

リモてなしは接客DXを実現するためのオンライン接客システムです。ビデオ通話機能や予約管理機能などの標準的な機能に加え、導入企業様ごとのニーズや課題に合わせたカスタマイズ機能を開発・提供しています。サービスの提供形態としてはマルチテナント型のWebサービスで、Webブラウザから利用できるサービスとなっています。

主要部分のアーキテクチャは、フロントエンドがSPA、バックエンドがAmazon ECS上で動くGo製のモノリシックなAPIサーバーという構成になっています。また、ビデオ通話機能ではAmazon Chime SDKを利用しています。

りもてなしのさらなる詳細については以下のリンクをご覧ください。

リモてなしでのフィーチャーフラグの主な用途

ここまでで述べたように、リモてなしでは、導入企業様ごとの「カスタマイズ機能の出しわけ」を主な用途としてフィーチャーフラグを利用しています。これはフィーチャーフラグの分類 [^2] で言うところの「Permissioning Toggles (パーミッショントグル)」に該当すると思われます。

また、現状は一部でしか実施できていないですが、将来的にはフィーチャーフラグを活用してトランクベース開発やA/Bテストを実施していくことも考えています。

フィーチャーフラグの仕組みの変遷

リモてなしでは、サービス立ち上げの比較的早い段階からフィーチャーフラグの仕組みを導入していたのですが、初期の段階では簡易的な仕組みを利用していました。そこからサービスのフェーズが進み、サービスの方向性が定まってきたことや本番運用で見えてきた課題などを受けて、社内フィーチャーフラグシステム「Bucketeer」を利用した仕組みに置き換えました。このセクションでは、その変遷や理由について説明します。

[置き換え前] 初期の仕組み

置き換え前は「RDBによるフィーチャーフラグの管理」を自前で実装していました。RDBにフィーチャーフラグ用のテーブルがあり、各行でフラグのキーとbool値を管理する形で、以下のようなイメージでした。

フィールド名 概要
organization_id 導入企業様のID
key フィーチャーフラグのキー
value フィーチャーフラグの設定値 (enable/disableどちらか)

バックエンドでは直接RDBから設定値を取得し利用していました。またフラグとその設定値を取得するためのAPIも実装し、フロントエンドではAPI経由で取得し利用していました。運用に関しては、例えば新しいフラグを追加する場合、RDBに直接クエリを実行し追加を行なっていました。

[置き換え後] 社内フィーチャーフラグシステム「Bucketeer」を利用した仕組み

現在弊社では、社内フィーチャーフラグ&A/Bテストプラットフォーム、通称「Bucketeer(バケティア)」 [^3] が開発されており、社内から利用できるようになっています。Bucketeerを利用するためには様々なプログラミング言語用に提供されているSDKを導入する必要がありますが、リモてなしではサーバサイド用のGo SDKを導入しています。

それまでRDBで管理していたフィーチャーフラグ一覧をBucketeerの管理画面上で管理するように変更し、フラグの評価・取得はGo SDK経由で行う形に置き換えています。フロントエンドからの利用は今まで通り、バックエンドのAPI経由で (Go SDKを呼び出して) 利用しています。

変遷の理由

初期の段階で「RDBによるフィーチャーフラグの管理」を自前実装した理由

以下のような背景があり、まずは最小限の仕組み・導入コストで実現しつつ、本当に必要になったら置き換えを行おうと考えたためです。

  • ビジネスとしてどのような方向性を目指すのか定まっていなかったこと (汎用的なSaaSを目指すのか or カスタマイズありきにするのか)
  • BtoBのサービスということもあり、トランクベース開発やA/Bテストなどに取り組んでいくのか見えていなかったこと

置き換えを行った理由

その後、以下のような課題や要望が見えてきたことで置き換えを行いました。

  • カスタマイズありきの方針になったことで、フラグの数が増え、それらのenable/disableの組み合わせによって動作を制御するようになり、影響範囲の理解やコントロールができなくなりつつあったこと
  • 導入企業様ごとのフラグの運用が大変になってきたこと
  • トランクベース開発やA/Bテストに対する要望がチーム内から上がってきたこと

置き換えにより、フィーチャーフラグの高度な管理・運用機能を持つサービスを導入することで、シンプルな運用を目指しています。例えば、

  • enable/disable以外の値を設定できるようになったので、理解しやすいようにフラグを整理すること
  • 導入企業様の識別子を元に、1つのフラグから動的に設定値を返せるようにすること (詳しくは次のセクションで説明)

などを実践しています。

フィーチャーフラグの管理方法

環境や導入企業様ごとのフィーチャーフラグの管理方法

環境ごと (ステージング環境、プロダクション環境など) のフィーチャーフラグの管理に関しては、Bucketeerには環境ごとにネームスペースを分離する機能があるのでそれを利用しています。つまり、フラグ1つ1つの設定が環境ごとに存在している形です。

環境ごとのフラグ管理

導入企業様ごとのフィーチャーフラグの管理に関しては、Attribute (属性) によるターゲティングを利用しています。Go SDKからBucketeerにリクエストを送る際にAttributeを付与することで、フラグのターゲティングルールで設定した値が返却されます。例えば、以下の画像の設定では、 organization というAttributeが A-Org の場合は value-3 を、 B-Org の場合は value-2 を、それ以外の場合は value-1 を返すという設定になっています。

導入企業様ごとのフラグ管理

導入企業様ごとのフィーチャーフラグの管理については、導入企業様ごとに環境を分離するという方法もあり、その方が分離性は高くなります。ただ現在のリモてなしでは、運用の容易さを考慮して、1つの環境の各フィーチャーフラグの中でAttributeによるターゲティングを利用し、導入企業様ごとの「カスタマイズ機能の出しわけ」を行うという方法を採用しています。

フィーチャーフラグの実装

バックエンドとフロントエンドで実装の細部は異なりますが、大まかなイメージは似ているので、バックエンドのGoのコード例を用いて説明します。

まず、フィーチャーフラグごとの使用方法を明確にするために BoolFlagVariationFlag という2種類に分類しており、1つのファイルにまとめて定義しています。

// enable/disable (true/false) 用のフラグ
type BoolFlag string

// bool型以外で2つ以上の設定値を持つフラグ
type VariationFlag string

// フィーチャーフラグ一覧
var (
    XXX1Flag BoolFlag = "xxx1-flag"
    XXX2Flag BoolFlag = "xxx2-flag"

    YYY1Flag VariationFlag = "yyy1-flag"
    YYY2Flag VariationFlag = "yyy2-flag"
)

BoolFlag の使い方はシンプルで、フラグのbool値を取得してif文などの分岐で使用します。

// SDKを呼び出してXXX1Flagの評価結果を取得
if featureFlagService.EvaluateBoolFlag(XXX1Flag, ...) {
    // XXX1Flagがenableの場合の処理
    // ...
} else {
    // XXX1Flagがdisableの場合の処理
    // ...
}

VariationFlag に関しては、フラグごとに使用方法が変わってくるので、それぞれヘルパー関数を定義して使用しています。(例えば、JSON文字列を、何らかのAPI連携の利用可否と連携先を持ったstructに変換など。)

// SDKを呼び出してYYY1Flagの評価結果を取得し、helper関数を通して使用方法に合った形に変換
result := yyy1FlagHelperFunc(
    featureFlagService.EvaluateVariationFlag(YYY1Flag, ...),
)
// resultを使用
// ...

また、フラグの評価結果の取得タイミングは、バックエンドは使用箇所で都度取得、フロントエンドは画面リロードごとにローカルキャッシュを更新し、使用箇所ではキャッシュから取得するようにしています。フロントエンドに関しては、必要であれば、BucketeerのWeb SDKに置き換えることでキャッシュの更新が自動的にバックグラウンドで走るようにすることも検討しています。

今回は説明を省略しますが、フロントエンドでは、フラグのenable/disableに応じたメニューやタブの表示可否などについても共通コンポーネントを作成して共通化しています。

まとめ

以上で、現在のリモてなしにおける、フィーチャーフラグの仕組みの変遷、管理方法、実装についての事例を紹介しました。

まだまだできていない部分であったり、運用する中で変わる部分も出てくると思うので、引き続き改善していきたいと考えています。また、この記事を読んでいただいた方からも、自分達はこうしているという事例があれば、ぜひ知りたいと思っています。

最後に宣伝ですが、リモてなしチームでは、接客の新時代を一緒に築き上げるメンバーを絶賛募集中です!
ちょっとでも気になった方は、カジュアルにお話するところから始めましょう!
こちら のリンクからお気軽に申し込みができます!

 


脚注