概要
リリースとは、コードが本番環境に届くタイミングとは独立に、変更をいつ・どのようにユーザーへ見せるかを決める一連の判断です。核となる原則は「デプロイ」と「リリース」の分離です。デプロイはコードを本番環境へ反映する機械的な作業であり、リリースは機能を公開するという判断です。 この分離がないチームでは、リリースは緊張を伴うイベントになります。変更は公開日まで大きなバッチとして溜まり、マージと同時に未確認の機能がユーザーの目に触れ、問題が起きたときの復旧は再デプロイ頼みになります。分離ができているチームでは、デプロイは1日に何度でも繰り返せる日常作業になり、リリースは設定変更ひとつで進めることも戻すこともできる、リスクの小さい判断になります。 本ページでは、この分離の原則、それを最小構成で実装する環境変数ベースのFeature Flag、複数のプルリクエストにまたがる機能を安全に届ける開発フロー、そして段階的ロールアウト・切り戻し・フラグの掃除までを解説します。デプロイ自体を自動化するパイプラインはCI/CDを参照してください。原則
デプロイとリリースを別の出来事として扱う
コードのデプロイと機能のリリースは同じ瞬間に起こることが多いものの、答える問いも、判断の主体も異なります。デプロイ
コードを本番環境へ反映することです。自動化でき、1日に何度でも実行できる、機械的で反復可能なステップです。
リリース
機能をユーザーが使える状態にすることです。告知やサポート体制、ビジネス上の節目との調整を含む、タイミングの判断です。
小さく頻繁にデプロイし、リリースのタイミングは選ぶ
両者の分離は継続的デリバリーの土台です。ソフトウェアを常にリリース可能な状態に保ち、小さな変更を高頻度でデプロイし、リリースのタイミングを意図して選びます。小さく頻繁なデプロイは、個々の変更のレビュー・テスト・取り消しを容易にするため、速度と安定性を同時に高めます。 この分離を追加のインフラなしで実装できるのが、次のFeature Flagです。Feature Flagで分離を実装する
環境変数の1分岐から始める
Feature Flagは、コードを変更せずに振る舞いのオン・オフを切り替える条件分岐です。最もシンプルで確実な実装は、コード内の1箇所の分岐点で環境変数を読むことです。 次の例では、環境変数FEATURE_NEW_LABELが'true'のときだけ新しいラベルを表示します。ローカル環境でのみ有効にして実装を進め、本番環境では無効のままマージします。
FEATURE_NEW_LABEL=trueの追加という設定変更であり、無効化はその行を取り除くだけです。
フラグが可能にすることを知る
フラグによって「コードが本番環境にある」ことと「機能が見えている」ことが独立した事実になります。これにより次が可能になります。未完成の作業をマージできる
開発途中の機能をフラグの裏に隠したままメインブランチへマージできます。長命なブランチで寝かせる必要がありません。
頻繁にデプロイし、慎重にリリースする
1日に何度も本番環境へデプロイしながら、各機能をいつリリースするかを選べます。
即時の切り戻し
リリース済みの機能に問題があればフラグをオフにするだけです。復旧にかかる時間はごくわずかです。
本番環境で安全に確認できる
検証環境や社内利用でだけ先に有効化し、本番環境のユーザーには従来の挙動を見せたまま確認できます。
環境変数ベースのフラグは追加のインフラなしで実現できるため、はじめの一歩に適しています。フラグ管理のライブラリやサービスの導入も検討に値します。
複数のプルリクエストにまたがる機能を届ける
1回のプルリクエストでは完成しない機能こそ、デプロイとリリースの分離の恩恵を最も受けます。フラグに隠せる変更と隠せない変更で開発フローが変わるため、ここでは2つのフローを適用条件とともに扱います。トランクベース開発
トランクベース開発は、すべての作業を小さな単位でメインブランチへ統合し続け、数日から数週間生き続けるブランチを避けるプラクティスです。長命なブランチは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倍にし、機能のライフサイクルのどこかで両方の状態が本番環境で動きます。分岐の両側にテストを書きます。役目を終えたフラグは削除する
フラグは設計上、一時的な存在です。フラグをオンにした状態で安定稼働し、オフに戻すシナリオがなくなったら、フラグ・不要になった分岐・オフ側のテストを1つのプルリクエストでまとめて削除します。 放置されたフラグは、誰もテストしていない状態の組み合わせとして積み上がります。信頼できるテストスイートがあるからこそ、この削除を先送りせずに実行できます。関連ページ
CI/CD
フラグをオフにしたままのデプロイを、1日に何度でも実行できるようにする自動パイプラインです。
タスク分解
フラグの裏でマージできる大きさまで機能を分割します。
プルリクエスト
個々のマージを小さくレビュー可能に保ちます。
テストコード
フラグの両状態を守り、フラグの削除を安全にするテストです。