このページでは、ビルドシステムとは何か、ビルドシステムの機能、ビルドシステムを使用する理由、組織の規模が拡大し始めたときにコンパイラとビルドスクリプトが最適な選択肢ではない理由について説明します。ビルド システムの経験があまりないデベロッパーを対象としています。
ビルドシステムとは
基本的に、すべてのビルドシステムには、エンジニアが記述したソースコードをマシンが読み取れる実行可能バイナリに変換するという明確な目的があります。ビルドシステムは人間が作成したコードだけでなく、テストや本番環境へのリリースなど、マシンが自動的にビルドを作成することも可能にします。エンジニアが数千人いる組織では、ほとんどのビルドはエンジニアが直接トリガーするのではなく、自動的にトリガーされるのが一般的です。
コンパイラを使用すればよいのではないですか?
ビルドシステムの必要性はすぐに明らかにならない場合があります。ほとんどのエンジニアは、コードの学習中にビルドシステムを使用しません。ほとんどのエンジニアは、コマンドラインから gcc
や javac
などのツールを直接呼び出すか、統合開発環境(IDE)で同等の操作を行うことから始めます。すべてのソースコードが同じディレクトリにある限り、次のようなコマンドは正常に機能します。
javac *.java
これにより、Java コンパイラは現在のディレクトリにあるすべての Java ソースファイルを取得し、バイナリ クラスファイルに変換します。最も単純なケースでは、これだけで十分です。
しかし、コードが拡張されると、複雑さが増します。javac
は、現在のディレクトリのサブディレクトリを検索して、インポートするコードを見つけることができます。しかし、ファイル システムの他の部分(複数のプロジェクトで共有されるライブラリなど)に保存されたコードを見つけることはできません。また、Java コードのビルド方法しか認識していません。大規模なシステムでは、さまざまなプログラミング言語で記述されたさまざまな部分が、それらの部分間の依存関係の網目状の構造を伴うことが多く、単一の言語のコンパイラではシステム全体をビルドできません。
複数の言語や複数のコンパイル単位のコードを扱う場合、コードのビルドは 1 つのステップで完了するプロセスではなくなります。コードが何に依存しているかを評価し、それらの部分を適切な順序でビルドする必要があります。各部分に異なるツールセットを使用することもできます。依存関係が変更された場合は、このプロセスを繰り返して、古いバイナリに依存しないようにする必要があります。コードベースが中規模であっても、このプロセスはすぐに面倒になり、エラーが発生しやすくなります。
コンパイラは、Java のサードパーティ JAR
ファイルなどの外部依存関係の処理方法についても認識していません。ビルドシステムがない場合、インターネットから依存関係をダウンロードし、ハードドライブの lib
フォルダに貼り付け、そのディレクトリからライブラリを読み取るようにコンパイラを構成することで、これを管理できます。時間の経過とともに、これらの外部依存関係の更新、バージョン、ソースを維持することが困難になります。
シェル スクリプトはどうですか?
趣味のプロジェクトが、コンパイラだけで構築できるほど単純なものだったとします。しかし、前述の問題が発生し始めました。ビルドシステムは必要ないと考えているかもしれません。ビルドを正しい順序で行う簡単なシェル スクリプトを使用して、面倒な部分を自動化できるかもしれません。これはしばらくの間は役立ちますが、すぐにさらに多くの問題が発生し始めます。
退屈になります。システムが複雑になるにつれて、実際のコードと同じくらいの時間をビルドスクリプトの作業に費やすようになります。シェル スクリプトのデバッグは、ハックが次々と重ねられていくため、困難です。
動作が遅い。古いライブラリに誤って依存しないように、ビルドスクリプトを実行するたびに、すべての依存関係を順番にビルドします。どの部分を再構築する必要があるかを検出するロジックを追加することを検討していますが、スクリプトとしては非常に複雑でエラーが発生しやすくなります。または、毎回再構築する必要がある部分を指定することを検討しますが、振り出しに戻ります。
リリースする準備が整いました。最終ビルドを作成するために jar コマンドに渡す必要があるすべての引数を把握しておくことをおすすめします。アップロードして中央リポジトリに push する方法を覚えておいてください。ドキュメントの更新をビルドしてプッシュし、ユーザーに通知を送信します。うーん、別のスクリプトが必要かもしれません。
みなさんにハードドライブがクラッシュし、システム全体を再作成する必要がある。ソースファイルはすべてバージョン管理下に置くという賢明な判断をしましたが、ダウンロードしたライブラリはどうでしょうか?それらをすべて再度見つけて、最初にダウンロードしたときと同じバージョンであることを確認できますか?スクリプトは、特定の場所にインストールされた特定のツールに依存している可能性があります。スクリプトが再び動作するように、同じ環境を復元できますか?コンパイラを適切に動作させるために設定して、その後忘れてしまった環境変数についてはどうでしょうか?
問題はあったものの、プロジェクトは十分に成功しており、エンジニアの増員を開始できる状態です。前の問題は、災害が発生しなくても発生することがわかりました。新しいデベロッパーがチームに参加するたびに、同じ苦痛なブートストラップ プロセスを繰り返す必要があります。また、最善を尽くしても、各ユーザーのシステムにはわずかな違いが残ります。多くの場合、あるユーザーのパソコンで動作するものが別のユーザーのパソコンでは動作しません。そのたびに、デバッグツールパスやライブラリのバージョンを数時間かけて調べて、違いを見つける必要があります。
ビルドシステムを自動化する必要があると判断します。理論的には、新しいパソコンを入手して、cron を使用して毎晩ビルド スクリプトを実行するように設定するのと同じくらい簡単です。面倒な設定プロセスは必要ですが、人間の脳が小さな問題を検出して解決できるというメリットはなくなります。毎朝出社すると、昨夜のビルドが失敗したことがわかります。これは、昨日、開発者が自分のシステムでは動作するものの、自動ビルドシステムでは動作しない変更を行ったためです。1 回の修正は簡単ですが、頻繁に発生するため、毎日多くの時間を費やしてこれらの簡単な修正を見つけて適用することになります。
プロジェクトが大きくなるにつれて、ビルドの速度が遅くなります。ある日、ビルドの完了を待っている間に、休暇中の同僚のアイドル状態のデスクトップを悲しげに見つめ、無駄になっているコンピューティング能力をすべて活用する方法があればいいのにと思いました。
これは、スケールの典型的な問題です。最大 1 ~ 2 週間で最大数百行のコードを扱う 1 人の開発者(大学を卒業したばかりのジュニア デベロッパーのこれまでの経験全体である可能性もあります)の場合、必要なのはコンパイラだけです。スクリプトを使用すると、もう少し先に進めるかもしれません。しかし、複数のデベロッパーとそのマシン間で調整が必要になると、完璧なビルド スクリプトでも不十分になります。それらのマシンのわずかな違いを考慮することが非常に難しくなるためです。この時点で、このシンプルなアプローチは機能しなくなるため、実際のビルドシステムに投資する必要があります。