SaaSのためのDevOps SaaS controlle.io の体験が良かったのでご紹介。
DevOpsと謳っていますが厳密には下記の粒度の支援を行ってくれます。
- Feature management
- SaaSによくあるアップセル対象になるオプション機能管理
- プライシングによって変わる利用ユーザー数の管理とか(というかプライシングに関わるもの全て?)
- プロダクト開発界のStripe, Zuoraみたいなイメージ
- ダークローンチ
- カナリアリリース
- ABテスト(多分beta)
Feature flag(toggle) + managementみたいなイメージです。
具体的な実装は最後のほうに載せてます。
ちなみに管理画面は英語ですが、LPが日本語にも対応しているので期待してもいいかもです。
ダークローンチ
新機能を本番環境にデプロイ後、
「開発者」や「社内」のようにセグメントを切って、対象者のみに機能を有効にする手法
つまり本番環境でQAができる。
よくあるのがSQLのパフォーマンスチューニングしてステージングでいい結果出たけど
いざ本番環境で動かすとデータの大きさから逆にパフォーマンス悪くなるみたいなやつが事前にテストできる。
本番環境でテスト出来る is 正義。
カナリアリリース(ロールアウト)
カナリアリリースをアプリケーションで制御する最大のメリットは、
新機能を有効にする単位がサーバーじゃなくてユーザー(組織)である事だと思います。
新機能をいきなりARR1000万とかのエンタープライズに解放するの怖いじゃないですか...
Controlleはここの設計が素晴らしいです。
1番伝えたいのはセグメント機能の優秀さ。
既存のfeature flagのライブラリは起点がユーザーなのですが
Controlleは組織、プロジェクト、ワークスペースのように細分化できます。
Slackが導入してるとして例えると、
スレッドの表示の遅さを改善するためにSQLパフォーマンスチューニングして、
そのコードをスレッドID起点にロールアウトできます。
なんならスレッドにコメントが10件以上あるもののみ有効とかもできます。
この辺の小回りの良さがすごく気に入りました。
あとはダイナミックロールアウトという機能もあって、
- リクエストがきたブラウザがchromeなら有効
- IPアドレスがUSなら無効
みたいな割と柔軟な対応もできます。
ちょうど弊社プロダクトでダークテーマを実装しましたが、各ブラウザのテストが不十分
でも早めにユーザーの反応を知りたい!みたいな時に
chromeアクセスユーザーだけに開放しよう!みたいなユースケースが想定できました。
Feature management
Controlleの一番の売りです。
ユースケースとしては下記の感じ
- 松竹梅プランがあり、松プラン、竹プランには○○機能を開放
- 竹プランはユーザー数5名まで、松プランは10名まで
- 自社でわざわざAdmin画面作らなくていい、Controlleが代替してくれる
SaaSは毎年プライシングや制限変わることも多いと思います。
プライシング変更時、初期顧客に「値上げしました!」の一言で突破できるならいいのですが、実際はそうとはなりません
これを繰り返してく内にプランが10個になったりしてテーブルの設計やアプリケーションロジックが複雑になっていきます。(弊社で実際ありました... old_free_plan
, new_free_plan
...)
これらをControlleに預けると複雑さから開放されます。
またSalesforceやStripeと連携できるみたいなので、CRMを正として各種スペックを定める事もできるようです。(このへんでZuoraっぽさを感じた)
導入、実装
client(js)側の導入は充実してて、cdn, npmから利用できます。
useEnableFeatureはfeature
flagの呼び出しです。
引数にフィーチャーキーとターゲットID(useId, projectId, threadId...)を渡すと
対象のターゲットに対して機能が有効か無効かを返してくれます。
useTargetはControlle
へのターゲットの追加です。
第1引数にダッシュボードで設定したグループキーを指定します。
例では users ですが、projectsとかteamとかなんでも登録できます。
第2引数でターゲットに対するメタデータを追加できます。
このメタデータを充実させると、ロールアウト時に詳細なセグメントを作成できます。
import { LoadControlle } from '@controlle/controlle-js'
import { ControlleProvider } from '@controlle/controlle-react-js'
const controlle = LoadControlle('Your client sdk key')
const App = () => (
<ControlleProvider controlle={controlle}>
<Component />
</ControlleProvider>
)
const Component = () => {
// useEnableFeature
const { loading, enable } = useEnableFeature({
featureKey: 'new-ui',
target: user.id
})
// useTarget
const { register } = useTarget()
const handleSignUp = () => {
register('users', {id: user.id, email: user.email, name: 'LeBron James'})
}
return (
<>
{enable ? <NewUI /> : <OldUI />}
<button onClick={handleSignUp}>Sign up</button>
</>
)
}
defaultTarget mode
defaultTargetをProviderに渡すことで初期化時に対象のターゲットのfeatureを全てフェッチしてきてくれます。
上記の useEnableFeature
使用時のローディング状態がなくなるので、UI的に体験はよくなりそうです。
const App = () => {
const target = {
groupKey: 'team',
targetId: 'your_target_id'
}
return (
<ControlleProvider controlle={controlle} target={target}>
<Component />
</ControlleProvider>
)
}
サーバーサイドSDK
試してないです...
サーバーサイドのSDKはクライアントと違い全てのfeatureの情報を初期化時にフェッチしてきてくれるそうです。
import { Controlle } from '@controlle/controlle-node-js'
const controlle = new Controlle('Your server side sdk key')
まだまだ書きたい事があるので時間がある時に続編を書きます。