字數總計:0 個 | 閱讀時長:0 分鐘 |閱讀次數:

9.1 起源與定義

  • Chrysler Comprehensive Compensation System(C3),是一個用戶數達 87000 名的綜合人事與工資系統
  • 1994 年開始開發,預計 1999 年上線,1996 年 Kent Beck 被邀請來挽救這個項目,並採用新的開發方式(極限編程方法)
    • 遇到的問題:要把系統的不同部分整合起來,並且讓系統運作,常常需要 1~2 週的時間
    • 極限編程:提高整合頻率,每次合併的東西較少,減少整合需要的時間,整合過程中的問題較好排解(Debug)
    • 方式:開發人員撰寫 shell 腳本,這個腳本定期去訪問儲存庫,只要發現有新的程式碼被提交,就將程式碼自動拉取到建構主機進行編譯
  • 但是最後上線的版本僅能支撐 10000 人使用,2000 年系統被捨棄

9.1.1 原始定義

  • 每日構建(daily build)、每晚構建(nightly build)
    • 每天定時自動執行一次軟體構建工作,將版本控制系統最新版本的程式碼在建構環境(沒有安裝集成開發環境的乾淨機器)下進行編譯、鏈結、打包的過程
    • 有助於確保開發人員明確了解前一天編寫的程式在整合的過程中是否發生問題,幫助開發團隊確定新的程式碼變更是否破壞原有功能
    • 「持續集成是一種軟體開發實踐,團隊成員頻繁地將他們的工作成果集成再一起(通常每人每天至少提交一次,這樣每天就會有多次集成);每次提交後,自動觸發一次包含自動化驗證的構建任務,以便能儘早發現集成問題」 —— Martin Fowler(2006)

9.1.2 一次集成過程

  1. 開發人員提交程式碼到儲存庫
  2. 建構主機定期輪詢程式碼儲存庫
  3. 有新的程式碼,下載到建置環境
  4. 根據建置腳本,執行建置
  5. 建置完成後上傳結果

截圖 2022-06-04 下午6.04.46.png

9.2 六步提交法

  1. 開發人員 check out 最新建置成功的程式碼
  2. 修改程式碼實作需求
  3. 第一次個人建置(Build):建置自己開發的東西(確保自己開發的東西沒問題)
  4. 第二次個人建置:從主幹中下載最新建置成功的程式碼(如果這段期間有其他人更新),並且進行建置(自己開發的東西+這段期間其他人的東西)
    • 確保要上去主線的程式碼是沒問題的
  5. 提交程式碼
  6. 第三次建置:如果程式碼通過自動化測試、靜態程式碼檢測,則將該程式碼並回主線,如果失敗則進行修復

截圖 2022-06-04 下午6.08.26.png

9.2.1 四個關鍵點

  1. 六步提交法中的三次驗證有什麼作用
    • 三次驗證的腳本必須一樣
    • 第一次驗證:確認開發者撰寫的內容是否正確,內容為自己
    • 第二次驗證:確認與最新版合併後系統是否正常,內容為自己+他人
    • 第三次驗證:在乾淨受控的環境中執行與第二次驗證一樣的腳本,確保開發人員提交完整且無程式品質問題,內容為儲存庫最新版本
      • 如果第二次驗證有過,第三次驗證沒過,代表 1.自己這次程式碼提交不完整 2.自己的建置環境跟團隊有差 3.團隊成員有提交新代碼,但是自己沒發現
  2. 個人驗證(第一次驗證、第二次驗證)一定要做兩次嗎?
    • 第二次驗證目標是驗證自己改的程式碼跟其他人提交的程式碼合併再一起,也符合預期
    • 如果第一次有過,第二次沒過,代表其他人提交的內容影響到這次的開發內容
    • 信心爆棚的工程師可以跳過個人第一次驗證,直接做第二次驗證即可
  3. 如何確保在提交前執行個人建置
    • 在代碼合併到主線時,強制進行第二次個人驗證
  4. 每次建置應該包含哪些品質檢驗內容
    • 單元測試、程式碼靜態掃描(白箱)、程式碼規範檢查(code style)
    • 建置驗證測試(build verification test)
      • 建置結束產生的二進制內容是否包含正確的內容 ex.配置文件的完整性
      • 這個建置結果是否能夠正常安裝並且啟動運行
      • 運行後最基本的功能是否可以使用 ex.登入
    • 針對接手舊案(大量遺留代碼的儲存庫),使用程式碼靜態掃描可能會出現一堆錯誤,該怎麼處理?以下提供兩種解法
      • 減少規範,關注重點:提取最重要的程式碼規範,早期只關注嚴重類型的問題,以後在逐步增加程式碼規範
      • 執行「童子軍營地」原則:遺留代碼多,且系統已經上線一段時間,且最近不會動到那邊的程式碼,則暫時不去修(當作沒看到),有動到那部份的程式碼,則考慮進行修復,做到每次提交時,沒有新增問題,最好問題可以逐步減少

9.2.2 同步異步模式

  • 主要的差異是在程式碼提交到主線時(六步提交法的第五步),後續開發人員的行為差異
  • 同步:開發人員需要等到建置完成後,確保通過才進行下一個開發任務
  • 異步:提交後就可以開始下一個開發任務
  • Kent Beck 不建議採用異步,因為可能存在浪費,ex.當開發人員已經在做下一個任務時,被通知上一個驗證沒過,需要調整,開發人員需要回想當初做了什麼

9.2.3 自查表

  • 可以從以下六個面向來檢查是否自己已經符合持續整合的最佳狀態
  • 主線開發,頻繁提交:開發分之生命週期不超過三天
  • 每次提交都是一個完整的任務
  • 讓提交的建置都可以在 10 分鐘內完成:尤其使用同步模式(參考 9.2.2)
  • 提交建置失敗後應禁止團隊成員提交新的程式碼,也不允許其他人 check out 該程式碼
    • 當團隊成員提交代碼引起建置失敗,說明系統整體品質可能存在問題,因此整個團隊不應該繼續提交新的程式碼,而是集中火力解決這個問題
  • 立即在十分鐘內修復已失敗的提交建置,否則該主線分支退回上一個提交點
    • 因為問題被修復之前,這個分支上的內容無法上到 release,導致其他人就算提交內容,這個分支的內容還是不能用
    • 為了讓其他人的內容可以持續提交,出問題的原開發有足夠的時間進行思考與修復,捨棄這個有問題的提交
  • 自動化建置驗證通過後,對軟體品質有較大的信心
    • 反例情境:團隊並不覺得使用持續整合有什麼用處,因為他們有很多自動化測試案例,但是隨著系統功能增加,新增的測試案例卻很少,而且現有的測試案例測試失敗後,如果該問題太難修復,就刪除這個測試案例(解決提出問題的人,就是解決問題 😀)

9.3 速度與品質權衡

9.3.1 分級建置

  • 隨著系統功能擴展,自動化測試的數量會越來越多,超果我們可以忍受的建置時間(10 分鐘)
  • 可以將自動化測試拆成兩個部分,將運行速度較快,重點驗證項目放入提交建置裡面,運行較慢、不常驗證失敗的測試案例,放在次級建置驗證的內容
  • 次級構建失敗,應該立即發出通知,並且立即修復,在修復之前不得提交新程式碼

9.3.2 多人同時提交的建置

  • 如果目前次級建置(每次可能需要執行 30 分鐘以上)進行中,新提交的程式碼就不執行次級建置,只做主要構建
  • 直到次級建置完成後,新提交的程式碼(合併到儲存庫),才會觸發下一次的次級建置,中間的次級建置全部被省略
    • 1.節省建置資源 2.同時進行如果前者壞了,後者執行的內容全沒意義

截圖 2022-06-04 下午7.05.02.png

9.3.3 雲端建置的威力

  • 編譯過程主要分為預編譯、編譯、鏈結
  • 可以透過雲端叢集的概念同步執行,減少整體建置時間的為「編譯」,各機器完成編譯後,再交由一台主機做整合的鏈結

截圖 2022-06-04 下午7.08.12.png

9.4 在團隊中實施持續整合實作

9.4.1 實作五步法

  1. 建置腳本化,搭建持續整合框架
    • 選擇一款持續整合工作,目前比較夯的是 Jenkins
    • 在該持續整合工具上建立一個建置任務,可以從你的儲存庫拉取程式碼
    • 寫一個腳本文件,可以自動完成系統的編譯、建置、打包
    • 修改持續整合工作上的任務(第二步),讓他可以調用第三步的腳本
    • 向儲存庫提交一次程式碼,驗證持續整合工作可以發現新代碼並拉取正確的程式碼版本,運行指定的腳本
  2. 添加已有的自動化驗證集合
    • 增加自動化測試案例
    • 加入程式碼規範掃描
      • SonarQube、Android Lite、CCCC、cppcheck、Clang、Pclint
  3. 選擇利於持續整合的分支策略
    • 如果分支過多,則不利於團隊持續整合的效果
  4. 建立六步提交法
  5. 持續優化
    • 初期整個機制運作正常,但隨著系統功能增加,整個過程出現了問題
    • ex.測試案例本身的程式碼品質不良,導致隨機的測試失敗
    • 優化編譯打包的時間
    • 調整程式碼分支策略
    • 自動化測試案例的分級(ex.哪些應該放在次級構建)
    • 優化程式碼規範掃描(ex.調整規則)
    • 生成數據報告,方便團隊了解目前的程式碼品質狀態
  6. 工程師改變習慣,並提升技能
    • 要求工程師主動提早整合,非推遲整合(不要一大包才提 PR,一個 PR 不要包含多個任務)
    • 學習持續整合的工具如何使用

截圖 2022-06-04 下午7.30.39.png

9.4.2 分支策略與部署流水線

  • 主線開發,主線發布:開發團隊只要架設一個持續整合服務,關注主線的程式碼變更即可
  • 主線開發,分支發布:當新增分支時,需要加增這個分支的部署流水線
  • 分支開發,主線發布:(只有一個儲存庫,但是有多個系統)每個分支都需要有部署流水線,當有人併入主線觸發主線部署流水線,當分支不需要時,同時可以砍掉其部署流水線
  • 多建置集成:系統來自於多個儲存庫,個別建置完觸發產品部署流水線

截圖 2022-06-04 下午7.31.29.png

截圖 2022-06-04 下午7.31.48.png

截圖 2022-06-04 下午7.32.04.png

9.5 常見執行問題

  1. 團隊原有工作習慣,例如
    • 開發人員在自己的開發任務完成之前不希望與別人的程式碼進行整合
    • 測試人員希望在整批的開發完成後再進行集中測試
    • 對於程式碼靜態掃描問題視而不見,1.團隊對於掃描規範沒有大家都認同 2.問題太多沒時間修
    • 自動化測試案例不夠,導致採用人工測試,必須開發完才有辦法整批測試,無法在每次提交時就進行測試
  2. 技術研發管理缺乏導致,例如
    • 開發、測試和維運環境沒有分離或分離不徹底,多人共用測試環境
    • 各類測試環境的準備工作很複雜

9.6 小結

  • 主線開發,高頻提交代碼
  • 每次提交都是完整有意義的任務
  • 提交建置階段在十分鐘內完成
  • 提交建置失敗後,立即修復,其他人不得在修復前提交代碼
  • 應該在十分鐘內修復失敗,否則放棄這次的提交
  • 自動化建置成功後,團隊對於系統品質比較有信心