概要
リリースとは、コードが本番環境に届くタイミングとは独立に、変更をいつ・どのようにユーザーへ見せるかを決める一連の判断です。核となる原則は「デプロイ」と「リリース」の分離です。デプロイはコードを本番環境へ反映する機械的な作業であり、リリースは機能を公開するという判断です。 本ページではこの分離の考え方、それを実装するFeature Flagの仕組み、トランクベース開発との関係、そして安全なロールアウト・切り戻し・フラグの掃除までを解説します。 デプロイ自体を自動化するパイプラインはCI/CDのページで扱い、本ページは「いつユーザーに見せるか」の判断と手法を扱います。デプロイとリリースは別の出来事
コードのデプロイと機能のリリースは同じ瞬間に起こることが多いものの、答える問いも、判断の主体も異なります。デプロイ
コードを本番環境へ反映することです。自動化でき、1日に何度でも実行できる、機械的で反復可能なステップです。
リリース
機能をユーザーが使える状態にすることです。告知やサポート体制、ビジネス上の節目との調整を含む、タイミングの判断です。
Feature Flag
Feature Flagは、コードを変更せずに振る舞いのオン・オフを切り替える条件分岐です。最もシンプルで確実な実装は、コード内の1箇所の分岐点で環境変数を読むことです。 次の例では、環境変数FEATURE_NEW_LABELが'true'のときだけ新しいラベルを表示します。ローカル環境でのみ有効にして実装を進め、本番環境では無効のままマージします。
FEATURE_NEW_LABEL=trueの追加という設定変更であり、無効化はその行を取り除くだけです。
フラグによって「コードが本番環境にある」ことと「機能が見えている」ことが独立した事実になります。これにより次が可能になります。
未完成の作業をマージできる
開発途中の機能をフラグの裏に隠したままメインブランチへマージできます。長命なブランチで寝かせる必要がありません。
頻繁にデプロイし、慎重にリリースする
1日に何度も本番環境へデプロイしながら、各機能をいつリリースするかを選べます。
即時の切り戻し
リリース済みの機能に問題があればフラグをオフにするだけです。復旧にかかる時間は軽微です。
本番環境で安全に確認できる
検証環境や社内利用でだけ先に有効化し、本番環境のユーザーには従来の挙動を見せたまま確認できます。
環境変数ベースのフラグは追加のインフラ無しで実現できるため、はじめの一歩としてはオススメです。フラグ管理のライブラリやサービスの導入を検討するのもいいでしょう。
トランクベース開発
トランクベース開発は、すべての作業を小さな単位でメインブランチへ統合し続け、数日から数週間生き続けるブランチを避けるプラクティスです。長命なブランチはconflictを蓄積し、統合の問題を最後まで隠し、レビューしにくい大きなプルリクエストを生みます。 複数のプルリクエストにまたがる機能でこれを成立させるのがFeature Flagです。各増分はレビューを通過し次第フラグに守られてマージされ、最後のピースが揃ったときに初めて機能を有効化します。 結果として、同じ領域を複数人で開発してもconflictが起きにくく、すべてのマージが適切にレビューできる大きさに保たれます。 次の図では、1つの機能を3つの増分に分け、それぞれフラグをオフにしたままbaseブランチへマージし、最後の増分がマージされた後にフラグをオンにしてリリースしています。 これは作業を小さな単位に分割する原則と同じ考え方です。作業の切り方はタスク分解を、個々のマージをレビュー可能に保つ方法はプルリクエストを参照してください。topic branch運用で本番環境への影響を切り離す
フラグの裏に隠せない変更もあります。画面全体の刷新やフレームワークの移行のように、本番環境への影響を隠すことが出来ない場合です。 topic branch運用は、そうした変更でも粒度を維持するための、baseブランチと作業ブランチの間にtopic branchを挟む3層のブランチ構成です。レビューと統合はtopic branch上で完結し、baseブランチにはリリースまで変更が反映されないため、本番環境に影響を与えずに小さなプルリクエストを出し続けられます。 運用の流れは次のとおりです。- baseブランチからtopic branchを切り、そこからさらに作業用のdevelop branchを切ります。
- develop branchからtopic branchへのプルリクエストでレビューします。粒度を維持するのはこの段階です。
- 本番環境への反映の準備が整ったら、topic branchからbaseブランチへのプルリクエストをマージします。このタイミングのレビューは必要最低限で問題ありません。手順2で既にレビュー済みだからです。
- baseブランチの修正内容は最低1日1回はtopic branchへ取り込み、conflictを最小限に抑えます。
段階的ロールアウトと切り戻し
デプロイとリリースが分離されていると、リリースは一度きりのイベントではなく、制御された一連のステップになります。1
フラグをオフにしたままデプロイする
コードは無効化された状態で本番環境に到達します。ユーザーには何の変化も見えず、デプロイ自体のリリースリスクはほぼゼロです。
2
検証環境で有効化する
まず検証環境でフラグをオンにします。ユーザーに公開される前に問題が表面化し、欠陥は早く見つかるほど修正コストが小さくなります。
3
本番環境でリリースする
選んだタイミングで本番環境のフラグをオンにします。公開範囲を絞れる場合は、特定のユーザーから展開を始め、徐々に公開範囲を広げます。
4
問題があればフラグをオフにして切り戻す
機能に問題があればフラグを無効化します。
両方の状態をテストし、フラグを削除する
フラグはコードが取りうる状態を2倍にし、機能のライフサイクルのどこかで両方の状態が本番環境で動きます。分岐の両側にテストを書きます。関連ページ
タスク分解
フラグの裏でマージできる大きさまで機能を分割します。
プルリクエスト
個々のマージを小さくレビュー可能に保ちます。
テストコード
フラグの両状態を守り、フラグの削除を安全にするテストです。