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