ビルドシステムを選ぶ理由

このページでは、ビルドシステムの概要、機能、ビルドシステムを使用すべき理由、コンパイラとビルド スクリプトが組織の規模拡大に適さない理由について説明します。ビルドシステムの経験がそれほど多くないデベロッパーを対象としています。

ビルドシステムとは

基本的に、すべてのビルドシステムには、エンジニアが記述したソースコードをマシンで読み取れる実行可能なバイナリに変換するという明確な目的があります。ビルドシステムは、人が作成したコードだけを対象とするものではなく、テストまたは本番環境へのリリースにおいても、マシンがビルドを自動的に作成できます。何千人ものエンジニアがいる組織では、ほとんどのビルドはエンジニアによって直接トリガーされるのではなく、自動的にトリガーされるのが一般的です。

コンパイラしか使えないのですか?

ビルドシステムの必要性は、すぐにはわからない場合があります。ほとんどのエンジニアは、コーディングを学習している間、ビルドシステムを使用することはありません。ほとんどのエンジニアは、gccjavac などのツールをコマンドラインから直接呼び出すか、統合開発環境(IDE)で同等のツールを呼び出すことから始めます。すべてのソースコードが同じディレクトリにある場合、次のようなコマンドは正常に機能します。

javac *.java

これは、現在のディレクトリ内のすべての Java ソースファイルを取得してバイナリ クラスファイルに変換するよう Java コンパイラに指示します。最もシンプルなケースでは これで十分です

しかし、コードが展開されるとすぐに、複雑化が開始します。javac を使用すると、現在のディレクトリのサブディレクトリを確認してインポートするコードを見つけることができます。ただし、ファイル システムの他の部分(複数のプロジェクトで共有されるライブラリ)に保存されているコードを見つける方法はありません。また、Java コードのビルド方法しか認識しません。大規模なシステムでは、さまざまなプログラミング言語で記述されたさまざまな要素と、それらの要素間に依存関係が存在します。つまり、1 つの言語のコンパイラがシステム全体を構築することはできません。

複数の言語や複数のコンパイル単位から生成されたコードを扱っている場合、コードのビルドは 1 ステップのプロセスではなくなり、今度は、コードが依存しているものを評価し、それらの要素を適切な順序で構築する必要があります。場合によっては、部分ごとに異なるツールセットを使用する必要があります。依存関係が変更された場合は、古いバイナリに依存しないように、このプロセスを繰り返す必要があります。中程度のサイズのコードベースでは、このプロセスはすぐに面倒でエラーが発生しやすくなります。

また、コンパイラは、Java でサードパーティの JAR ファイルなど、外部依存関係を処理する方法も把握していません。ビルドシステムを使用しない場合、これはインターネットから依存関係をダウンロードし、ハードドライブ上の lib フォルダに保存し、そのディレクトリからライブラリを読み取るようにコンパイラを構成することで対処できます。時間の経過とともに、このような外部依存関係の更新、バージョン、ソースを保守することは困難になります。

シェル スクリプトについてはどうでしょうか。

趣味のプロジェクトは、コンパイラだけでビルドできるほど簡単に始まったが、前述のいくつかの問題に直面したとします。それでもビルドシステムは必要なく、正しい順序でビルドする単純なシェル スクリプトを使用して、面倒な部分を自動化できるかもしれません。しばらくはこれで解決しますが、すぐに次の問題に遭遇します。

  • 煩わしさが増します。システムが複雑になるにつれ、ビルド スクリプトの作成に実際のコードの編集とほぼ同じ時間を費やすようになります。シェル スクリプトのデバッグは負担の大きい作業です。多くのハッキングが重ねられてきました。

  • 動作が遅い。古いライブラリを誤って使用しないようにするため、ビルド スクリプトでは、実行するたびにすべての依存関係が順番にビルドされるようにします。再構築が必要な部分を検出するためにロジックを追加することを検討します。しかし、これはスクリプトにとって非常に複雑で、エラーが発生しやすいように思えます。あるいは、毎回再構築する必要がある部品を指定しようとして、その後は 1 平方面に戻ります。

  • このたび、リリースが開始されました。最終的なビルドを行うために jar コマンドに渡す必要がある引数をすべて把握した方がよいでしょう。アップロードし 中央リポジトリに プッシュする方法を覚えておきましょうドキュメントの更新をビルドおよび push し、ユーザーに通知を送信します。うーん、 別のスクリプトが必要かもしれない...

  • みなさんにハードドライブがクラッシュし、システム全体を再作成する必要がある場合。バージョン管理ではすべてのソースファイルを管理できましたが、ダウンロードしたライブラリについてはどうでしょうか。もう一度見つけて、最初にダウンロードしたときと同じバージョンであることを確認できるか。スクリプトは、特定の場所にインストールされている特定のツールに依存している可能性があります。同じ環境を復元してスクリプトを再び機能させることができますか?コンパイラが正常に動作するように、かなり前に設定していた環境変数のことを忘れていたのはどうでしょうか。

  • そうした問題はあるものの、プロジェクトは順調に進んでおり、エンジニアの増員を開始することができます。これで、以前の問題が発生しても問題がないことがわかりました。新しいデベロッパーがチームに加わるたびに、同じ痛いブートストラップ プロセスを行う必要があります。最善を尽くしても、システムには若干の違いが残っています。多くの場合、あるユーザーのマシンでは機能しても別のマシンでは機能せず、デバッグツールのパスまたはライブラリのバージョンがどこにあるかを把握するために、毎回数時間かかります。

  • そこで、ビルドシステムを自動化する必要があると判断しました。理論上、これは新しいコンピュータを入手し、cron を使用して毎晩ビルド スクリプトを実行するように設定するだけです。やはり手間のかかるセットアップ プロセスを行う必要がありますが、人間の脳では軽微な問題を検出して解決できるというメリットがありません。今では毎朝、ビルドが失敗したことがわかります。前夜に、デベロッパーが行った変更はシステム上では機能していたが、自動ビルドシステムでは機能しなかったからです。毎回簡単な修正ではありますが、非常に頻繁に発生するため、これらの単純な修正を見つけて適用するために毎日多くの時間を費やすことになることになります。

  • プロジェクトが拡大するにつれて、ビルドは徐々に遅くなります。ある日、ビルドが完了するのを待っている間に、休暇中の同僚のアイドル状態のデスクトップを嘆きながら、無駄な計算能力をすべて活用できる方法があればいいと思いました。

昔のスケールの問題に直面しました。1 人のデベロッパーが最大 100 行のコードを最大で 1 週間または 2 週間(大学を卒業したばかりの若手デベロッパーにとっては経験どおりかもしれません)、コンパイラがあれば十分です。スクリプトを使うと もう少し進めやすくなりますしかし、複数のデベロッパーとそのマシンを連携させる必要が生じた場合は、それらのマシンの微妙な違いを考慮することは非常に困難になるため、完璧なビルド スクリプトだけでは不十分です。この時点で、このシンプルなアプローチはうまく機能しません。次に、実際のビルドシステムに投資します。