為什麼要建構系統?

回報問題 查看來源 Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

本頁面將說明建構系統的定義、用途、使用建構系統的理由,以及隨著貴機構規模擴大,編譯器和建構指令碼為何不是最佳選擇。這項工具適合對建構系統經驗不多的開發人員。

什麼是建構系統?

從根本上來說,所有建構系統都有一個簡單的用途:將工程師編寫的原始碼轉換為可供機器讀取的執行檔。建構系統不僅適用於人為撰寫的程式碼,也允許機器自動建立建構作業,無論是為了測試或發布至正式環境,在有數千名工程師的機構中,大多數的建構作業通常都是自動觸發,而非由工程師直接觸發。

我不能只使用編譯器嗎?

您可能不會立即發現需要建構系統。大多數工程師在學習編碼時不會使用建構系統:他們通常會從指令列直接叫用 gccjavac 等工具,或在整合式開發環境 (IDE) 中執行等效操作。只要所有原始碼都在同一目錄中,這類指令就能正常運作:

javac *.java

這會指示 Java 編譯器擷取目前目錄中的每個 Java 原始碼檔案,並將其轉換為二進位類別檔案。在最簡單的情況下,這樣就夠了。

但程式碼一擴充,問題就會接踵而來。javac 夠聰明,會查看目前目錄的子目錄,尋找要匯入的程式碼。但無法在檔案系統的其他部分 (可能是多個專案共用的程式庫) 找到儲存的程式碼。此外,它只知道如何建構 Java 程式碼。大型系統通常會涉及以各種程式設計語言編寫的不同部分,且這些部分之間存在依附元件網路,因此單一語言的編譯器不可能建構整個系統。

處理多種語言或多個編譯單元的程式碼時,建構程式碼不再是單一步驟的程序。現在您必須評估程式碼的依附元件,並以適當順序建構這些元件,可能需要為每個元件使用不同的工具組合。如果任何依附元件有所變更,您必須重複這個程序,避免依附於過時的二進位檔。即使是中等大小的程式碼集,這個程序很快就會變得繁瑣且容易出錯。

編譯器也不瞭解如何處理外部依附元件,例如 Java 中的第三方 JAR 檔案。如果沒有建構系統,您可以從網際網路下載依附元件,並將其放在硬碟的 lib 資料夾中,然後設定編譯器從該目錄讀取程式庫,藉此管理依附元件。隨著時間推移,維護這些外部依附元件的更新、版本和來源會越來越困難。

殼層指令碼呢?

假設您的興趣專案一開始很簡單,您可以使用編譯器建構,但後來開始遇到先前所述的一些問題。或許您還是認為不需要建構系統,可以使用一些簡單的殼層指令碼自動化處理繁瑣的部分,確保建構作業以正確順序進行。這段時間內還算順利,但很快地,您會遇到更多問題:

  • 這會變得非常繁瑣。隨著系統日益複雜,您花在建構指令碼的時間,幾乎與實際程式碼一樣多。對 Shell 指令碼進行偵錯非常麻煩,而且越來越多駭客會層層堆疊。

  • 速度緩慢。為確保您不會意外依附於過時的程式庫,每次執行建構指令碼時,系統都會依序建構每個依附元件。您考慮新增一些邏輯,偵測需要重建的零件,但這對指令碼來說似乎非常複雜且容易出錯。或者,您會考慮每次重建時指定需要重建的部分,但這樣又回到原點。

  • 好消息:可以發布了!請找出您需要傳遞至 jar 指令的所有引數,以建立最終版本。並記得如何上傳及推送至中央存放區。並建構及推送文件更新,以及傳送通知給使用者。嗯, 或許需要另一個指令碼...

  • 太慘了!硬碟故障,現在需要重新建立整個系統。您很聰明地將所有來源檔案都放在版本控制中,但下載的程式庫呢?請再次找出這些檔案,並確認版本與首次下載時相同。您的指令碼可能依賴安裝在特定位置的特定工具,您是否可以還原該環境,讓指令碼再次運作?您很久以前設定的環境變數,目的是讓編譯器正常運作,但後來就忘了這些變數,該怎麼辦?

  • 儘管遇到問題,您的專案仍相當成功,因此可以開始聘用更多工程師。現在您發現,不需要發生災害,先前的問題就會出現,因為每當有新開發人員加入團隊,您就必須經歷同樣痛苦的啟動程序。即使您盡力而為,每個人的系統仍會有些微差異。通常,在某人的機器上運作的項目,在其他人的機器上無法運作,而且每次都需要花費數小時偵錯工具路徑或程式庫版本,才能找出差異所在。

  • 您決定要將建構系統自動化。理論上,這很簡單,只要取得新電腦,並設定每晚使用 cron 執行建構指令碼即可。您仍須完成繁瑣的設定程序,但現在無法透過人腦偵測及解決小問題。現在,您每天早上上班時,都會看到昨晚的建構作業失敗,因為昨天有開發人員進行變更,但該變更在他們的系統上運作正常,在自動建構系統上卻無法運作。每次都是簡單的修正,但發生頻率太高,導致你每天都要花費大量時間尋找及套用這些簡單的修正。

  • 專案越大,建構速度就越慢。某天,您在等待建構完成時,悲傷地看著同事閒置的桌上型電腦 (他正在休假),希望有辦法充分利用所有浪費的運算能力。

您遇到了典型的規模問題。如果只有一位開發人員,且最多只會花一到兩週的時間處理幾百行程式碼 (這可能是剛畢業的初級開發人員目前為止的全部經驗),那麼編譯器就已足夠。指令碼或許能帶你走得更遠。但如果您需要協調多位開發人員及其機器,即使是完美的建構指令碼也不夠,因為很難考量這些機器之間的細微差異。此時,這種簡單的做法會失效,因此需要投資真正的建構系統。