description |
---|
對敏捷開發團隊而言,持續整合與版本控制同樣重要,開發團隊如果有效實現持續整合,會比沒有使用它的團隊,更快交付出正確的軟體實作。 |
軟體專案管理的聖經,由 Frederick P. Brooks 撰寫的《人月神話:軟體專案管理之道》一書,在第十六章「沒有銀彈(No Silver Bullet)」論述中強調,由於軟體的複雜性本質,並沒有任何一項技術或管理方法,可以保證生產力、可靠與簡潔性獲得重大突破的改善。
這個論點在 1986 年被提出,直到三十多年後的今日,許多技術、工具與管理方法不斷地推進,但軟體工程仍是一項腦力與勞力密集的工作型態。
事實上,你的開發團隊並不會因為開始使用某種工具或管理方法,就能讓眼前遇到的所有問題迎刃而解。但是隨著時代的演進、經驗的積累,技術、工具和管理方法不斷地進步,能讓軟體開發團隊進行更有效率、更大規模地協作,如同建築從三合院到萬丈高樓的演進。
如果想要更加瞭解持續整合的意義,可以先認識管理學必修的「精實生產(Lean Production)」,它又稱為豐田式生產管理(Toyota Production System,簡稱 TPS)。
維基百科對豐田生產方式的定義:
豐田式生產主要目標,是杜絕負荷過重(muri)、不平準(mura)和一切的浪費(muda)。TPS 把浪費歸納成七種:
- 等待的浪費;
- 搬運的浪費;
- 不良品的浪費;
- 動作的浪費;
- 加工的浪費;
- 庫存的浪費;
- 製造過多(早)的浪費。
TPS 背後的理念就是「杜絕浪費」,包括在製造業難以避免的庫存堆積。基本原則是「豐田模式」(The Toyota Way),概述如下:
- 正確的流程方能產生正確結果
- 發展員工與事業夥伴,以為組織創造價值
- 持續解決根本問題是組織型學習的驅動力
從製造業的角度來看,只要能避免不必要的浪費與重工,相對來說,效率就會變得更快更好;我們把 TPS 歸納的七種浪費,改從軟體開發的角度來看:
- 等待的浪費,搬運的浪費: 程式開發週期除寫程式外,建構(build)、測試(test)與部署(deploy)都是必要的流程,需要透過自動化建置來杜絕各環節的浪費。
- 不良品的浪費: 可以預期的是,程式錯誤(bug)只會一再地發生,不可能完全避免;但是若能夠在每個環節多進行測試與確認,則可以確保每個小動作能被正常執行,特別是在每次程式的修改後,應立即進行完整的測試,盡可能減少錯誤的產生。
- 動作的浪費,加工的浪費: 不斷被重覆的動作,就是一種浪費;每個人的時間和精力有限,能夠透過程式來取代人力介入的流程,就應該及早被自動化。
- 庫存的浪費: 很幸運地,軟體通常沒有庫存壓力;但是隨著程式碼增長,無法被測試的程式碼一旦堆積過多,就會帶來可怕的除錯夢靨。
- 製造過多(早)的浪費: 非必要或事先考慮過多的功能需求,除開發過程已浪費不少時間,寫出來的程式也增加維護成本。
所有在製造業所會發生的問題,大部份軟體開發也會有同樣的問題,我們可以借鏡其精神,與豐田式生產相互輝映,發展出敏捷式開發(Agile Development)。
敏捷軟體開發(Agile development)是一種以人為核心、迭代、循序漸進的開發方法。實行敏捷軟體開發流程的過程,並非選擇某種方法論、規範和工具,而是讓團隊的每位成員都能意識到:更有效率的溝通協作是美好的目標,更好的工作效率對自己有好處,團隊也能提升到更好的層次。
持續整合是「敏捷軟體開發」重要的一個環節,就跟豐田式生產一樣,敏捷軟體開發也致力於杜絕所有可能的浪費。
維基百科對敏捷軟體開發的定義:
敏捷軟體開發(英語:Agile Software Development),又稱敏捷開發,是一種從 1990 年代開始逐漸引起廣泛關注的一些新型軟體開發方法,是一種應對快速變化的需求的一種軟體開發能力。它們的具體名稱、理念、過程、術語都不盡相同,相對於「非敏捷」,更強調程式設計師團隊與業務專家之間的緊密協作、面對面的溝通(認為比書面的文檔更有效)、頻繁交付新的軟體版本、緊湊而自我組織型的團隊、能夠很好地適應需求變化的代碼編寫和團隊組織方法,也更注重軟體開發中人的作用。
藉著親自並協助他人進行軟體開發,我們正致力於發掘更優良的軟體開發方法。透過這樣的努力,我們已建立以下價值觀:
- 個人與互動 重於 流程與工具
- 可用的軟體 重於 詳盡的文件
- 與客戶合作 重於 合約協商
- 回應變化 重於 遵循計劃
也就是說,雖然右側項目有其價值,但我們更重視左側項目。
出處:敏捷軟體開發宣言
- 版本控制
- 自動化建置
- 團隊共識
原始碼管理 SCM(Source Code Management)是團隊多人協作的基礎,不論使用 Git、SVN 或其他版本控制工具,只要與專案有關的所有內容,包括程式碼、測試程式、資料庫初始化腳本、建置流程、設定檔、虛擬化環境配置與部署腳本,這些資料都必須提交到 Repository 保存。除了完整保存開發演進過程的每個版本,開發團隊也必須依循一套工作流程(Workflow),例如 Git Flow 或 GitHub Flow 等。
軟體建置(build)的流程愈來愈繁瑣,所幸大多開發平台皆發展出完善的建置工具,例如:
- Java 的 Ant、Maven 與 Gradle
- C/C++ 的 CMake 或 Autotools
- Node.js 的 Grunt 或 Gulp
為能夠實現自動化建置,專案必須能夠在終端機下,僅使用 Command-line 或 Build Script,就能完成所有建置流程。過去有些開發環境相當程度地,依賴圖形化介面的整合開發環境,例如 Visual Studio 或 DELPHI 等,但是由於自動化建置與持續整合的大勢所趨,近年來許多開發平台都能提供完善的建置方法,例如微軟近期推行的 .NET Core,除了使用 Visual Studio 的圖形化介面建置專案,也能使用 .NET Core CLI 以指令方式操作。
dotnet restore # 還原專案的相依性和工具
dotnet build # 建置專案和其所有相依性
dotnet run # 執行原始程式碼
dotnet test # 用來執行單元測試的 .NET 測試驅動程式
dotnet publish # 將應用程式與其相依性封裝至資料夾中,以部署至主機系統
.NET Core CLI 提供的指令包括建置、執行、測試與發布等,對於持續整合的實現相當容易。
然而,即使工具再強大、理想再美好,敏捷開發與持續整合的推行,最終還是由團隊中的成員「每個人」共同決定成敗。持續整合不是一種工具,而是一種開發流程的實踐,其精神在於:開發團隊共同約定並遵守一些準則,例如:
- 每次對於程式進行的小幅修改,都必須提交 Commit 並撰寫清楚的備註。
- 主要的程式邏輯都能被自動化測試,需要撰寫單元測試或整合測試。
- 如果某次修改造成程式無法完成自動化建置與測試程序,必須優先被修復處理。
持續整合的先行條件,就是專案必須規劃良好的測試機制,將規格(Spec)清楚定義成為可被自動執行的測試流程。
有清楚的規格可以用來檢驗系統的功能,在上線後每次_異常狀況_發生時,就能將遇到的問題,制定成新加入的規格,用更多的測試代碼來確保系統品質,讓除錯的成果能被累積、保存在規格之中,如此一來就能累積成為系統品質的後盾。
搭配可以自動化執行的測試規格,就能利用 Jenkins 定時產生測試報告,讓專案相關人員隨時注意專案的健康指數,及早發現問題並儘早治療。
進行自動化建置與測試的時間點,可能發生在每個 Code Commit 之後,也可能由人為控制觸發;無論如何,要搭配 Jenkins 做到持續整合,建議至少要進行每日及每週的建置任務。
程式開發是一連串的協同合作過程,因此人為疏失無法根絕;但是建立良好的開發流程,就能讓問題儘早被發現並加以修復。測試是開發流程中重要的環節,讓系統功能得到良好的驗證機制,確保開發能量能夠被累積,並加以重複利用,隨著專案的成長,偵錯的能量也會同步增長。
我們提倡在專案中實踐 TDD(測試驅動開發),只要專案有先做好規格的定義與自動化測試流程,導入「持續整合」就是水到渠成。搭配 Jenkins CI 讓專案定時、頻繁地做健康檢查,專案上線或每次更新後,就不用再太過於提心吊膽。只有開發流程令人安心,才能更專注於系統功能的完善,能夠實踐 TDD + Jenkins CI 流程的開發團隊,雖然一開始會比別人辛苦,但不久之後就會得到更多的幸福,就像隨時有個盡責的管家在一旁照料大小事。
持續整合流程從豐田式生產而來,其所提倡的核心目標是「剛剛好、不浪費」,讓流程更加透明化。有了 Jenkins 的幫忙,專案因此更有 “ 心 跳 脈 動 ” ,平時就要做好專案健康管理,否則到瀕死邊緣時,就需要徹底搶救才能回復心跳!