DevOps 技術: トランクベース開発

デベロッパー チームがバージョニングを使用して共同作業を行う場合、主に 2 つのパターンがあります。1 つは機能ブランチを使用する方法です。デベロッパーまたはデベロッパー グループは通常、トランク(マスター、メインラインともいいます)からブランチを作成し、構築している機能が完了するまで、そのブランチで分離して作業を行います。機能の準備が整ったと判断したら、機能ブランチをトランクにマージします。

もう 1 つのパターンはトランクベース開発です。それぞれのデベロッパーが自分の作業を小さなバッチに分割し、その作業を 1 日に少なくとも 1 回(場合によっては数回)トランクにマージします。このアプローチの主な違いはスコープです。通常、機能ブランチには複数のデベロッパーが関与し、作業が終わるまでに数日から数週間かかります。対照的に、トランクベース開発のブランチは数時間以内で終わり、多くのデベロッパーが個々の変更を頻繁にトランクにマージします。

次の図は、典型的なトランクベース開発のタイムラインを示しています。

バージョン 1.0 と 1.1 のタイムライン。バグ修正がバージョン 1.0 からバージョン 1.1 のトランクにマージされている。

トランクベース開発では、デベロッパーがコードを直接トランクに push します。通常、リリース ブランチで行われた変更(リリースの準備ができたときのコードのスナップショット)はできるだけ早い段階でトランクにマージされます(下向きの矢印で示されています)。このアプローチでは、バグの修正を選択してリリースにマージする場合があります(上向きの矢印で示されています)が、これらのケースはトランクで新機能を開発する場合ほど頻繁ではありません。リリースが 1 日に複数回発生する場合、変更をマスターに直接 push し、そこからデプロイできるため、リリース ブランチはまったく必要ありません。トランクベースのアプローチの重要な利点の 1 つは、イベントをマージする複雑さを解消し、開発行数が少なくなる点です。また、小規模なマージを頻繁に行うことで、コードを常に最新の状態に保つことができます。

次の図は、非トランクベースの典型的な開発スタイルを示しています。

複数の長期ブランチのタイムライン。マージパスが複雑になっている。マージの競合でリリースが遅れる可能性があるポイントが複数存在している。

このアプローチの場合、デベロッパーは長期間にわたってブランチに変更を加えます。トランクベースの開発と比較すると、これらの変更は、より大きく複雑なマージイベントを必要とします。また、大規模なマージによってバグやリグレッションが頻繁に発生するため、ソフトウェアの状態を安定化する作業を行い、「コードロック」または「コードフリーズ」の期間を用意する必要があります。また、マージ後のコードを徹底的にテストする必要があり、バグの修正も必要になります。

トランクベース開発の実装方法

トランクベース開発は継続的インテグレーションに欠かせない要素です。継続的インテグレーション(CI)を実現するには、トランクベース開発を実践し、トランクに commit するたびに一連の自動テストを迅速に行い、システムを常に稼働させておく必要があります。

継続的インテグレーションを使用するポイントは、コードの小さなバッチを頻繁に統合することで、統合フェーズと安定化フェーズを短縮することにあります。デベロッパーは、他のデベロッパーやテスターと共同作業を進めることができるので、統合フェーズで大規模なマージを行う必要がありません。

CI パラダイムでは、デベロッパーがビルドプロセスを green(稼働中)に維持する役割を担います。つまり、CI プロセスが失敗した場合、デベロッパーは作業を中止し、問題をすぐに修正するか、数分で修正できない場合は変更を元に戻す必要があります。

トランクベース開発を実践するには、デベロッパーが作業を小さなバッチに分割する方法を理解する必要があります。この方法で作業することに慣れていないデベロッパーにとって、これは大きな変更です。

2016 年(PDF)と 2017 年(PDF)の DevOps Research and Assessment(DORA)の分析結果は、チームが次のプラクティスに従うことで、より高いレベルのソフトウェアを配信し、運用パフォーマンス(配信速度、安定性、可用性)を改善できることを示しています。

  • アプリケーションのコード リポジトリに 3 つ以下のアクティブなブランチを用意する。
  • 少なくとも 1 日に 1 回、ブランチにトランクをマージする。
  • コードフリーズや統合フェーズをなくす。

主な注意点

トランクベース開発を完全に導入する場合、次のような課題があります。

  • 過剰なコードレビュー プロセス。多くの組織は、変更をトランクにマージする前に複数の承認を必要とする膨大なコードレビュー プロセスを実施しています。コードレビューが面倒で、数時間から数日かかる場合、デベロッパーは小さなバッチで作業せず、多くの変更を一つにまとめようとする傾向があります。この場合、レビューアが大規模なコードレビューを先延ばしにする可能性があり、下向きのスパイラルにつながります。

    結果として、デベロッパーがマージ リクエストを避けるようになり、マージプロセスが遅延する可能性があります。大きな変更がシステムに与える影響を検査から判断することは難しいため、レビューアが欠陥を見逃す可能性が高く、トランクベース開発のメリットは少なくなります。

  • 非同期でのコードレビュー。チームがペア プログラミングを実践している場合、コードは 2 人でレビューされています。さらにレビューが必要な場合は、レビューを同期する必要があります。デベロッパーがコードを commit する準備ができたら、チームの他のメンバーにコードのレビューをすぐに依頼する必要があります。たとえば、ツールにリクエストを送信してレビュー結果を待っている間に別のタスクを始めるなど、非同期のレビューを行わないでください。マージが遅れるほど、競合に関連する問題が発生する可能性が高くなります。同期レビューを実施するには、他の作業よりもお互いのコードのレビューを優先するようにチーム内で合意を形成する必要があります。

  • コードを commit する前に自動テストを実行しない。トランクの作業状態を維持するには、commit する前にコードの変更をテストすることが重要です。これはデベロッパーのワークステーションで実行できます。また、多くのツールは、ローカルの変更に対してリモートからテストを実行し、合格時に自動的に commit する機能を備えています。デベロッパーが多くの作業を行わなくてもコードをトランクに入れることができれば、その結果は自ずと理解しやすく、レビューやテストも簡単で、本番環境にも迅速に移行できる小さなコード変更になるはずです。

トランクベース開発の改善方法

上記の課題に基づいて、トランクベース開発を改善するために実装できるいくつかの方法についてみてみましょう。

  • 小さなバッチで開発する。トランクベース開発の最も重要なポイントの 1 つは、小さなバッチで開発する方法をチームで学習しているかどうかです。そのためには、デベロッパー チームでトレーニングを行うだけでなく、組織的なサポートも必要になります。
  • コードの同期レビューを行う。前述のように、コードの同期レビューを行うか、デベロッパーがコードレビューの優先順位を設定することにより、変更がトランクにマージされるまで数時間または数日も待つ必要がなくなります。
  • 包括的な自動テストを実装する。包括的な単体テストを自動化し、このテストを commit 前に実行する必要があります。たとえば、GitHub を使用している場合、ブランチを保護して、すべてのテストに合格するまで pull リクエスト マージをブロックできます。GitHub のチェックCloud Build を統合する方法については、GitHub チェックを使用したビルドの実行チュートリアルをご覧ください。
  • ビルドを迅速に実行する。ビルドとテストプロセスを数分で完了する必要があります。この実現が難しいと思われる場合は、システム アーキテクチャの改善が必要かもしれません。
  • チームをリードするコアグループを形成する。トランクベース開発は、多くのデベロッパーにとって大きな変化であり、ある程度の抵抗が予想されます。多くのデベロッパーは、この新しい開発作業を想像できないかもしれません。この方法で作業を行っているデベロッパーに他のデベロッパーの指導役になってもらうことも検討しましょう。また、一部のチームをトランクベースのスタイルで作業するようにシフトすることも重要です。そのためには、少なくとも 1 つのチームがトランクベース開発を実践できるように、トランクベース開発の経験者を数多く集める必要があります。このチームが期待どおりに機能していることが確認できたら、他のチームもこのスタイルに移行していきます。

トランクベース開発の測定方法

トランクベース開発の有効性は次の方法で測定できます。

テスト項目 測定データ 目標
アプリケーションのコード リポジトリでアクティブなブランチ。 アプリケーション リポジトリのバージョニング システムにあるアクティブなブランチ数を測定し、この数をすべてのチームに提示します。次に、目標に対する進捗状況を記録します。 アクティブなブランチを 3 つ以下にする。
コードフリーズの期間。 チームが担当しているコードフリーズの数と、コードの持続時間を測定します。これらの測定値は、マージによる競合、コードのフリーズ、安定化などに費やされる時間を分類することもできます。 誰もコードを送信していない状態で、コードフリーズがないこと。
ブランチとフォークをマスターにマージする頻度。 マージされる各ブランチをバイナリ値(yes / no)で測定するか、毎日マージされるブランチとフォークの割合を測定します。 少なくとも 1 日 1 回マージします。
コード変更の承認にかかる時間。 コードレビューを非同期で実行する場合、変更リクエストの承認にかかる平均時間を測定し、平均よりも大幅に時間がかかるリクエストがあるかどうか確認します。 開発の一環として実行されるコードレビューを同期アクティビティとして行う方法を見つける。

次のステップ