為什麼要建構系統?

回報問題 查看原始碼 Nightly · 8.0 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

本頁面將說明建構系統的定義、功能、使用建構系統的原因,以及為何在組織開始擴大規模時,編譯器和建構指令碼並非最佳選擇。這項工具適用於不熟悉建構系統的開發人員。

什麼是建構系統?

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

我可以直接使用編譯器嗎?

您可能不會立即意識到需要建構系統。大多數工程師在學習程式碼時不會使用建構系統:大多數人會直接從指令列叫用 gccjavac 等工具,或是在整合式開發環境 (IDE) 中叫用等效工具。只要所有原始碼都在同一個目錄中,以下指令就能正常運作:

javac *.java

這會指示 Java 編譯器將目前目錄中的每個 Java 來源檔案轉換為二進位類別檔案。在最簡單的情況下,您只需執行這項操作即可。

不過,一旦程式碼擴充,就會開始出現複雜性。javac 夠聰明,可以查看目前目錄的子目錄,找出要匯入的程式碼。但它無法找出儲存在檔案系統其他部分的程式碼 (可能是多個專案共用的程式庫)。它也只知道如何建構 Java 程式碼。大型系統通常包含以各種程式設計語言編寫的不同部分,且這些部分之間有依附元件網絡,這表示沒有任何單一語言的編譯器可以建構整個系統。

一旦您開始處理多種語言或多個編譯單位的程式碼,建構程式碼就不再是單一步驟的程序。您現在必須評估程式碼的依附項目,並依正確順序建構這些部分,可能會為每個部分使用不同的工具組合。如果任何依附元件發生變更,您必須重複這個程序,避免依附過時的二進位檔。即使是規模適中的程式碼庫,這個程序也會很快變得乏味且容易出錯。

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

殼層指令碼呢?

假設您的興趣專案一開始相當簡單,您可以只使用編譯器建構專案,但開始遇到先前所述的部分問題。也許您仍認為自己不需要建構系統,而且可以使用一些簡單的 Shell 指令碼,以正確順序建構項目,自動執行繁瑣的部分。這麼做雖然有一段時間有幫助,但很快就會開始遇到更多問題:

  • 這會變得乏味。隨著系統越來越複雜,您開始花費幾乎與實際程式碼相同的時間來處理建構指令碼。因為有越來越多駭客會層層堆疊,因此殼層指令碼的偵錯作業相當耗時。

  • 速度較慢。為確保您不會不小心依附過時的程式庫,請在每次執行建構指令碼時,依序建構每個依附元件。您考慮新增一些邏輯來偵測需要重建的部分,但這對指令碼來說似乎相當複雜且容易出錯。或者,您可以考慮指定每次需要重建哪些部分,但這麼做就會回到原點。

  • 好消息:現在是發布更新的最佳時機!建議您找出所有需要傳遞至 jar 指令的引數,以便進行最終建構作業。並記得如何上傳並推送至中央存放區。並建立及推送文件更新,以及向使用者發出通知。嗯,或許需要另一個指令碼才能呼叫...

  • 太慘了!硬碟發生故障,因此您必須重新建立整個系統。您很聰明,將所有來源檔案都保留在版本控制中,但下載的程式庫呢?你可以再次找到這些檔案,並確認這些檔案與你首次下載的版本相同嗎?你的指令碼可能會依賴在特定位置安裝特定工具,請問你能否還原相同環境,讓指令碼再次運作?您很久以前設定的所有環境變數,是否都會讓編譯器正常運作,但您卻忘記了?

  • 儘管有問題,但您的專案已成功到足以開始招募更多工程師。您現在應該已經瞭解,前述問題並非災難,只是每次有新開發人員加入團隊時,您都必須經歷相同的啟動程序。即使您盡力調整,每個人的系統仍會有些微差異。在某人機器上運作的程式,往往無法在其他人機器上運作,而且每次都需要花上好幾個小時來偵錯工具路徑或程式庫版本,才能找出差異所在。

  • 您決定需要自動化建構系統。理論上,這就像取得新電腦,並設定讓電腦每天晚上使用 cron 執行建構指令碼一樣簡單。您還是需要經歷痛苦的設定程序,但現在您無法利用人腦偵測及解決小問題。如今,每天早上上班時,您會發現昨晚的建構作業失敗,因為昨天開發人員所做的變更在他們的系統上可行,但在自動建構系統中卻無法運作。每次都是簡單的修正方式,但發生的頻率太高,導致您每天都花費大量時間找出並套用這些簡單的修正方式。

  • 隨著專案規模擴大,建構作業的速度也會越來越慢。某天,在等待建構作業完成時,您無意間看到同事 (他正在度假) 的電腦閒置,於是心想如果有辦法能善用所有浪費的運算效能就好了。

您遇到了典型的規模問題。對於單一開發人員而言,最多一週內處理幾百行程式碼 (這可能是剛畢業的初級開發人員至今的全部經驗),您只需要編譯器即可。指令碼可能會讓您更深入瞭解。不過,一旦需要協調多位開發人員和他們的機器,即使是完美的建構指令碼也不足以應付,因為很難考量這些機器之間的細微差異。此時,這個簡單的方法就會失效,您必須投資於實際的建構系統。