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

問題を報告 ソースを表示 Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

このページでは、ビルドシステムの概要、仕組み、ビルドシステムを使用するべき理由、組織のスケーリングを始める際にコンパイラとビルド スクリプトが最適ではない理由について説明します。これは、ビルドシステムの経験があまりないデベロッパーを対象としています。

ビルドシステムとは

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

コンパイラを使用できないのですか?

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

javac *.java

これにより、Java コンパイラは、現在のディレクトリ内のすべての Java ソースファイルをバイナリ クラスファイルに変換します。最も単純なケースでは、これだけで十分です。

しかし、コードが拡張されるとすぐに複雑化が起こります。javac は、現在のディレクトリのサブディレクトリを検索して、インポートするコードを見つけることができるほどスマートです。ただし、ファイルシステムの他の部分(複数のプロジェクトで共有されているライブラリなど)に保存されているコードを見つける方法はありません。Java コードのビルド方法だけを認識します大規模なシステムでは、さまざまなプログラミング言語で記述されたさまざまな部分が、それらの部分の間に依存関係のウェブを形成していることがあります。つまり、単一言語のコンパイラではシステム全体をビルドできない可能性があります。

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

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

シェル スクリプトはどうですか?

趣味のプロジェクトが最初はコンパイラだけでビルドできるほどシンプルだったとしても、前述の問題に直面することがあります。ビルドシステムが必要ないと考えている場合でも、簡単なシェル スクリプトを使用して、退屈な部分を自動化し、正しい順序でビルドを処理できます。しばらくすると役に立ちますが、すぐにさらに多くの問題に遭遇するようになります。

  • この作業は面倒になります。システムが複雑になるにつれて、実際のコードと同じくらい多くの時間をビルド スクリプトの作成に費やすようになります。シェル スクリプトのデバッグは、ハックが重ねて追加されるため、困難です。

  • 動作が遅い。古いライブラリに誤って依存しないように、ビルド スクリプトは実行するたびにすべての依存関係を順番にビルドします。再ビルドが必要な部分を検出するロジックを追加することを検討しますが、スクリプトとしては複雑でエラーが発生しやすくなります。または、再ビルドする必要がある部分を毎回指定することを検討しますが、その場合、最初からやり直すことになります。

  • リリースの準備が整いました。最終ビルドを作成するために jar コマンドに渡す必要があるすべての引数を把握しておいてください。また、アップロードして中央リポジトリに push する方法を覚えておきます。ドキュメントの更新をビルドして push し、ユーザーに通知を送信します。うーん、別のスクリプトが必要かも...

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

  • 問題があっても、プロジェクトは十分に成功しているため、エンジニアの採用を開始できます。災害が起きなくても、以前の問題が発生する可能性があることがわかりました。新しいデベロッパーがチームに加わるたびに、同じ面倒なブートストラップ プロセスを繰り返す必要があります。最善を尽くしても、各人のシステムには小さな違いがあります。多くの場合、ある人のマシンで動作するものが、別のユーザーのマシンでは機能しません。また、違いを特定するのに毎回、デバッグツールパスやライブラリ バージョンに数時間かかります。

  • あなたは、ビルドシステムを自動化する必要があると判断しました。理論上は、新しいパソコンを入手して、cron を使用して毎晩ビルド スクリプトを実行するようにセットアップするのと同じくらい簡単です。面倒なセットアップ プロセスは引き続き必要ですが、人間の脳が小さな問題を検出して解決できるというメリットがなくなります。毎朝出社すると、昨日のビルドが失敗したことがわかります。昨日、デベロッパーが変更を加えたものの、その変更はデベロッパーのシステムでは機能したものの、自動ビルド システムでは機能しなかったためです。毎回簡単な修正ですが、頻繁に発生するため、これらの簡単な修正を見つけて適用することに毎日多くの時間を費やしていることになります。

  • プロジェクトが大きくなるにつれて、ビルドの速度はどんどん遅くなります。ある日、ビルドの完了を待っている間、休暇中の同僚のアイドル状態のデスクトップを悲しげに見つめ、無駄になっている計算能力をすべて活用する方法があればいいのに、と願っています。

スケーリングという古典的な問題に遭遇しました。1 人のデベロッパーが最大でも 1 ~ 2 週間で数百行ものコードに取り組み(これは、大学を卒業したばかりの若手のデベロッパーにとってはそういった経験でしょう)、必要なのはコンパイラだけです。スクリプトを使用すると、さらに高度な作業を行うことができます。しかし、複数の開発者とそのマシン間で調整が必要になると、たとえ完璧なビルド スクリプトであっても、これらのマシンのわずかな違いを説明することが非常に困難になるため、十分ではありません。この時点で、このシンプルなアプローチは機能しなくなり、本物のビルドシステムに投資する時期です。