継続的インテグレーションを理解しよう

継続的インテグレーションまたは CI は、マージのたびに自動的にコードベースのビルドとテストを行う手法です。

継続的インテグレーションとは?

継続的インテグレーション(CI)は開発チームが作業効率を上げ、ソフトウェアをより確実に提供できるように考案された DevOps 手法です。 CI では変更がマージされるたびに CI サーバーが自動的にコードのビルドとテストを実行するため、作業内容に対するフィードバックを迅速に得られます。 この迅速かつ確実なフィードバックサイクルによって本番環境に到達するバグの数を減らしながら、変更のリリース頻度を上げることができます。

CI を使用しない開発

継続的インテグレーションを使用しないソフトウェア開発について考察すると、それが必要な理由を理解できます。 たとえば Git のようなバージョン管理システムを使用して作業している場合、 あなたと同僚が個別にリポジトリのコピーを持ち、各自がそれを使用してローカルで開発した後、作業内容を共有リポジトリにプッシュすることになります。

新機能を開発している場合、数日間その作業を行ってから変更を共有するでしょう。 その間、あなたの同僚もローカルにあるリポジトリのコピーを使って機能を構築しています。 作業が完了した後は個々の機能が他の機能と組み合わさった状態で期待通りに動作することをテストするため、各自が共有リポジトリに変更をプッシュし、指定されたブランチへのマージを開始します。

残念ながら、複数の開発者がプッシュする大量の変更が組み合わさると、コードがビルドされなくなるリスクが高まります。 あなたと同僚は時間をかけて問題の原因となった変更を特定し、対象となるコミットを取り消した後、より緊急性の高い他の変更のリリースを進めるか、さらにコード変更を加えて問題を修正することになります。

コードをビルドした後、変更が組み合わさることでさまざまなバグが混入したことに気づく場合もあります。 そのような場合は各貢献者によるコードの変更を再度確認し、問題の根本的原因を突き止め、解決し、ビルドプロセスを最初からやり直すことになります。

CI の必要性

継続的インテグレーションは指定のブランチに変更がマージされるたびに自動的にビルドとテストのステップを実行することで、このプロセスを高速化します。 これらのステップを自動化すると、数週間ごとではなく、数時間ごとにコードベースをビルドしてテストできるようになります。

このような小さな単位で作業することで、コード変更に起因する問題をより素早く特定して修正することができます。 問題の根本的原因を発見するのに何百行または何千行もの変更を調べる代わりに、調査範囲をはるかに少ない数の変更に限定することができます。 また、このような変更はまだ記憶に新しいため、コンテキストスイッチングによる余計な負荷が生じません。

CI では変更のたびにソフトウェアが継続してビルドされ、期待通りに動作することを確認することで、コードをデプロイ可能な状態に維持することができます。 そのため、本番環境に変更をリリースする際の苦労が軽減され、機能と修正の提供頻度を上げられるようになります。

継続的インテグレーションは複数の貢献者が参加する大規模なソフトウェア開発プロジェクトで発生する問題を解決するように考案されたものですが、開発プロセスへの CI の追加は早すぎるということはありません。 1 人で作業している開発者であっても、小さな単位で作業を進めながら自動テストで変更を検証することにより、作業効率とコードの品質を改善することはできます。

継続的インテグレーション

CI の実践

効率的な CI ワークフローを実現するには、ツール、プロセス、およびチームの実践手法を組み合わせる必要があります。 それぞれを順に詳しく見てみましょう。

バージョン管理システムを使用する

継続的インテグレーションでは、コードベース全体をソース/バージョン管理システムに保存します。 保存の対象には、すべてのソースコードファイル、ライブラリ、構成ファイル、およびスクリプトを含める必要があります。 バージョン管理を使用することで、複数の開発者が同時に作業を進め、変更を共有し合うのがはるかに簡単になります。 CI サーバーはバージョン管理システムと統合し、コード変更のビルドとテストを行います。

定期的に変更をコミットする

全員が同じコードに基づいてビルドするには、共通のリポジトリで作業し、変更を頻繁に共有する必要があります。 経験則的には全員が毎日共有リポジトリの CI ブランチにコミットをマージすることが推奨されますが、コミットの頻度をさらに上げることも可能です。 その一方、共有リポジトリを使用してローカルのコピーを最新状態に維持することで、プッシュするたびにマージの競合が発生するリスクを抑えることができます。

自動ビルドとテスト

コード変更をマージした後の次のステップは、ソリューションをビルドし、リンティング、ユニットテスト、静的解析などの一連のチェックに通すことです。 手動でのビルドやテストは時間がかかる上にミスが発生しやすく、毎日変更の統合を行うのは非現実的であるため、自動化が不可欠です。 すべての主要プログラミング言語にはビルドツールと自動テストフレームワークが提供されており、CI サーバーを使用して自動的にプロセスを起動し、さまざまなステップを調整することができます。

失敗に迅速に対応する

継続的インテグレーションのメリットを活用するには、プロジェクトに貢献する全員が自動ビルドまたはテストの失敗に迅速に対応する必要があります。 そうすることで、全員が新機能を動かないコードではなく、信頼できるコードに追加できるようになります。 これはチームメンバーに作業を中断させて失敗したビルドやテストの修正を依頼しているかのように見えるかもしれませんが、自動 CI プロセスは最初の結果を数分以内に提供できるため、コードの変更内容がまだ記憶に新しい段階で問題を解決することができます。

プロセスを管理する

ビルドとテストの自動化を完了したら、CI のフローを管理する必要があります。 これには、新しいコードを書く過程でユニットテストを追加したり、フィードバックループの速度を管理したりすることが含まれます。

リポジトリの監視、ビルドの起動、自動テストの実行、結果の照合を実施できる CI サーバーを追加すると、これらすべての機能を関連付け、カスタム自動化ロジックの作成にかかる時間を節約することができます。 CI サーバーが適切であれば、コードカバレッジのメトリクスやビルド履歴など、その他のインサイトも得られます。

CI のメリット

継続的インテグレーションから期待できるメリットを理解することで、チームメンバーが新しい手法を試すことを促進し、関係者に新しいプロセスを支援することを納得させることができます。

CI には個人と開発チーム全体に以下のようなメリットがあります。

  • マージの円滑化: より小さな単位で作業し始めると、マージ競合の数が少なくなります。 これを実現するには、ローカルリポジトリを他の人がプッシュした変更で定期的に更新することが重要です。
  • ワークフローの効率化: 自動ビルドとテストのプロセスから迅速なフィードバックを得られるため、変更をプッシュした数分後にはコードの問題を発見できるようになります。 それとは対照的に、手動によるビルドやテストプロセスに頼っている場合、変更によって生じたバグを発見するまで数日または数週間を要する可能性があります。
  • コードベースの管理性向上: 自動カバレッジを追加して CI プロセスを適切に動作させると、コードベースがより理解しやすく、管理しやすくなります。
  • コミュニケーションとコラボレーションの改善: 作業単位を小さくして変更の共有頻度を上げることで、他の人が作業している内容を確認することも可能になります。 これによって同僚と機能のデザインについて話し合う機会が増え、プロダクトマネージャーとユーザビリティエキスパートに進捗を示し、必要に応じて方向性を調整することができます。

継続的インテグレーションには、以下のようにより幅広い業務上のメリットがあります。

  • バグの削減: 継続的インテグレーションによってバグの混入が阻止されるわけではありませんが、開発者がバグを特定して修正するのがはるかに簡単になります。 そのため、バグが本番環境にリリースされ、ユーザーに影響を及ぼす可能性が大幅に低くなります。
  • リリースの迅速化と頻度の増加: ビルドとテストのプロセスを自動化することで、時間を節約し、ステップを確実に一貫して実施できるため、ソフトウェアのリリース準備にかかる手動作業が少なくなります。 CI プロセスに対するチームの自信が高まることで、変更をより頻繫にリリースできるようになります。

継続的インテグレーション、デリバリー、およびデプロイのメリットについての詳細は、CI/CD の 12 のメリットに関するガイドをご覧ください。

CI の課題

継続的インテグレーションには開発者にもより幅広い業務にもメリットがありますが、必ずしも手放しで受け入れられるわけではありません。

多くの開発部門にとって、DevOps は業務のあり方を大きく変え、既存のプロセスを否定する存在として捉えられています。 そのため、チーム間の努力を調整してコラボレーションの文化を浸透させるには、十分な話し合いが必要となります。

すでにアジャイル手法を実践している方はフィードバックに耳を傾けることの重要性と自己組織化チームの概念に対する関心があると言えるため、DevOps へ移行するのは通常は容易です。

容易でない場合は、CI が重要な変化であることを認識して関係者と対話し、小規模な構成から始めてメリットを示していくことで、CI がもたらすメリットを同僚に理解させることができます。

継続的インテグレーションはより実際的な課題にも直面しています。 大規模なモノリシックアプリケーションに取り組んでいる場合はビルド時間が長くなり、テスト環境が不足している場合はテストの実行を並列化するのが難しい可能性があります。

継続的インテグレーションのワークフローを可視化し、メトリクスを使用してボトルネックを特定することで、アーキテクチャへの変更、追加インフラストラクチャ、およびテストカバレッジの自動化に投資するコストとメリットを定量化しやすくなります。

継続的インテグレーションを始める

CI ワークフローのセットアップは困難に思えるかもしれません。 検討できるオプションは多数あり、自動化できるものも多数あります。 幸いにも、このプロセスはより小さな単位に分割するのに適しています。なぜならば、各ステップで何らかのメリットが得られるためです。

以下の内容から着手することをお勧めします。

  1. より小さな単位で作業を開始する: コードをバージョン管理しているのであれば、より小さな単位で作業を開始して変更の共有頻度を上げることで、マージの競合を減らすことができます。 それを促すには、バックログを調整する際に開発タスクの細分化から着手したほうがいいかもしれません。
  2. ブランチ作成戦略について合意する: どのブランチを CI フローに通し、どのように変更をリリースするかを決定します。 一般的には、トランクベース開発や GitFlow(特にバージョン管理されたソフトウェアの場合)などが選択されます。
  3. コーディングしながらユニットテストを追加する: 既存のユニットテストがある場合でも、新規に作成する場合でも、ユニットテストをチームの「完了の定義」に組み込むことで継続的にコードカバレッジを改善することができます。 自動テストがまったくないよりは少しでもある方が良いに決まっているため、少数の自動テストだけでも CI を実践し始めることができます。
  4. 段階的に自動化する: CI フローのすべてのステージを一気にスクリプト化しようとするのではなく、最も時間を要するものや、最も多くフィードバックを得られるものに専念してください。 準備ができたら、CI サーバーを使用してステップを自動 CI プロセスに関連付けられるようになります。

CI と CD の両方のセットアップについての詳細は、CI/CD のベストプラクティスに関するガイドをご覧ください。

まとめ

継続的インテグレーションを採用することで、コードの品質を高めながら開発プロセスを加速させることが可能になります。 これらのステップを自動化することで作業効率が上がり、ユーザー価値を高めることに専念できるようになります。 ただし、継続的インテグレーションは CI/CD パイプラインの始まりに過ぎません。 この次のステージである継続的デリバリーは、DevOps の原則を CI プロセスの後のプロセスに適用します。

TeamCity のメリット

TeamCity はニーズに合わせてカスタマイズできる柔軟な CI/CD プラットフォームです。 Git、Perforce、Mercurial、Subversion を含むすべてのバージョン管理システムのサポートと主要なプログラミング言語用のビルドおよびテストツールを提供します。 幅広い CI トリガーが備わっているため、指定ブランチへのコミットのたびにビルドとテストのプロセスを起動し、フィーチャーブランチに対して一連のチェックを実行し、ナイトリービルドのスケジュールを設定し、ローカルで CI チェックを実行するオプションをチームメンバーに提供することができます。

できるだけ迅速にフィードバックを得られるようにするため、TeamCity ではテストやその他のビルドタスクを並列化できるようになっています。 Slack と IDE を統合すると、作業場所に関係なくフィードバックを得られ、詳細なテストレポートを使用して失敗の原因を素早く特定することができます。 TeamCity には広範なメトリクスも用意されており、CI プロセスを最適化し、ユニットテストのカバレッジを評価するのに役立てることができます。

TeamCity には CI プロセスを拡張して継続的デリバリーまたはデプロイを採用する際に環境を管理し、デプロイを自動化するのに必要なあらゆる機能が備わっています。