満を持してリリースはやめにしたい
Railsアプリで新機能をリリースするとき、こんな不安を感じたことはないでしょうか。
- 本番にデプロイした瞬間、全ユーザーに影響が出てしまう
- 一部の顧客だけに先行リリースしたい
- 問題が起きたらすぐに機能を止めたい
こうした課題を解決するのが Feature Flag(機能フラグ) です。
そして、そのための Ruby gem として非常によく設計されているのが flipper です。
この記事では flipper の導入方法や使い方のイメージなどについて記します。
Feature Flagとは何か
Feature Flag(機能フラグ)とは、
コードは本番にあるが、機能としてはまだ有効化しない
という状態を作る仕組みです。
つまり、
デプロイ = コードを本番に置く
リリース = ユーザーに見せる
この2つを分離する技術です。
これがないと、Railsアプリは
- デプロイ = 即ユーザー影響
- 問題があればロールバック
という非常にリスクの高い運用になります。
Feature Flagを使えば、
- 社内だけで有効化
- 特定の会社だけでON
- 少しずつ対象を広げる(カナリアリリース)
といった運用が可能になります。
flipper の思想
flipper は README でこう定義されています。
A simple, flexible feature flagging solution for Ruby.
しかし実際の設計を見ると、もう少し踏み込んだ思想があります。
flipper は
「Feature Flag の判断を、外部サービスに丸投げせず、アプリケーションのドメイン側で管理する」
という設計をしています。
保存先は Redis や DB などアダプタで差し替えられますが、
「誰にこの機能を見せるのか」という判断ロジックは、
あくまで Rails アプリの中にあります。
ActiveRecord アダプタを使えば、その判断はそのまま DB に保存されます。
これはつまり、
機能フラグは、ただの設定ではなく、業務ルールとして扱える
という状態を Rails の中に作れる、ということです。
Railsのモデルやドメインと一緒に
「この会社にはこの機能を出す」というルールを管理できる。
そこが flipper の大きな特徴です。
flipper を ActiveRecord で導入する
今回は flipper の中でも、Railsと最も相性が良い
ActiveRecordアダプタを使います。
Gemfile
gem 'flipper'
gem 'flipper-active_record'
bundle install
マイグレーション
rails generate flipper:active_record
rails db:migrate
これで次のテーブルが作られます。
- flipper_features
- flipper_gates
この時点で、Feature Flagは
RailsのDBに保存されるデータ になっています。
flipperのDB構造
flipper_features
| id | key |
|---|---|
| 1 | new_ui |
| 2 | beta_export |
→ 機能フラグの一覧です。
flipper_gates
| feature_key | key | value |
|---|---|---|
| new_ui | boolean | true |
| new_ui | actor | Company;42 |
| new_ui | group | admins |
ここが flipper の本体です。
flipper は Feature Flag を「3種類のゲート」で管理します。
| ゲート | 意味 |
|---|---|
| boolean | 全体ON / OFF |
| actor | 特定のユーザー・会社 |
| group | 管理者・βユーザーなど |
単なる true / false ではなく、
誰に対して有効なのか まで DB に保存されます。
単純なON / OFF
Flipper.enable(:new_ui)
Flipper.disable(:new_ui)
このとき、DBにはこう保存されます。
| feature_key | key | value |
|---|---|---|
| new_ui | boolean | true |
「この機能は全員に対してON」という意味です。
特定の会社だけONにする(カナリアリリース)
ここが flipper の真価です。
company = Company.find(42)
Flipper.enable_actor(:new_ui, company)
このとき DB にはこう保存されます。
| feature_key | key | value |
|---|---|---|
| new_ui | actor | Company;42 |
flipper は ActiveRecord オブジェクトを
"Company;42"
という ドメイン識別子 に変換して保存します。
User ID やメールアドレスではなく、
Railsのモデルそのもの をキーにしてフラグを管理する。
これが flipper の思想です。
なぜDBで持つ設計が強いのか
Redis や外部サービスと違い、ActiveRecord を使うと
- マイグレーションで変更を管理できる
- バックアップ・復旧の対象になる
- 「誰に何をONにしたか」が業務データとして残る
つまり Feature Flag が
設定ファイルではなく、契約データになる
という状態になります。
これは BtoB の Rails アプリでは特に重要です。
flipperで実現するカナリアリリース
Flipper.enable(:new_ui) # 社内
Flipper.enable_actor(:new_ui, Company.find(5))
Flipper.enable_actor(:new_ui, Company.find(8))
これだけで、
- まず社内
- 次に数社
- 問題なければ全体
というリリースが 再デプロイなし で実現できます。
問題が起きたら、DBからフラグを消すだけです。
flipperとは何か
flipper は単なる if 文のラッパーではありません。
flipper が提供しているのは、
「この機能を、どのユーザー・どの会社に出すか」
という判断を、コードではなくデータとして管理できる仕組み
です。
ActiveRecord アダプタを使えば、
- この会社には new_ui をON
- あの会社にはまだOFF
- 管理者だけON
といったリリース状態が、そのまま Rails の DB に残ります。
つまり flipper は、
機能の公開範囲を、デプロイとは切り離してコントロールできるようにするgem
です。
段階リリースや顧客ごとの出し分けが必要な Rails アプリでは、
運用と設計の両方をシンプルにしてくれる、かなり実戦的な選択肢だと感じています。