前段時期我負責部門內部主幹開發落地相關事宜,這個過程中,也真真切切的體會到了多人開發過程中,面對特性分支管理中,大家遇到的一些困擾,尤其面對敏捷迭代的開發方式,合併衝突,集成測試,代碼重用等方面,都與高效兩個字背離。當然,我在推進主幹開發過程中,也遇到了一些問題和坎坷,在這裡,集中的做一次分享。 ...
前段時期我負責部門內部主幹開發落地相關事宜,這個過程中,也真真切切的體會到了多人開發過程中,面對特性分支管理中,大家遇到的一些困擾,尤其面對敏捷迭代的開發方式,合併衝突,集成測試,代碼重用等方面,都與高效兩個字背離。當然,我在推進主幹開發過程中,也遇到了一些問題和坎坷,在這裡,集中的做一次分享。
1. 概述
主幹開發,是指開發人員直接向主幹(習慣上主幹分支通常為:trunk 或 master)提交 / 推送代碼。通常,開發團隊的成員 1 天至少 1 次地將代碼提交到主幹分支。在到達發佈條件時,從主幹拉出發佈分支(通常為 release),用於發佈。若發現缺陷,直接在主幹上修複,並根據需要 cherry pick 到對應版本的發佈分支。
優點:
-
分支模型簡單高效,開發人員易於掌握不容易出現錯誤操作
-
避免了分支合併、衝突解決的困擾
-
隨時擁有可發佈的版本
-
有利於持續集成和持續交付
缺點:
-
基礎架構要求高:合入到主幹的代碼若質量不過關將直接阻塞整個團隊的開發工作,因此需要高效的持續集成平臺進行把關;
-
自動化測試要求高:需有完備單元測試代碼,確保在代碼合入主幹前能在獲得快速和可靠的質量反饋;
-
最好有代碼評審:若代碼質量要求高,需要配套代碼評審(CR)機制,在代碼提交到主幹時,觸發 CR,通過 Peer Review 後才能正式合入;
-
最好有特性開關:主幹開發頻發合入主幹的情況下,特性拆分得很小,可能是半成品特性,需要配套特性開關(Feature Toggle),只有當特性整體開發完才通過灰度發佈等手段逐步打開;
適用環境:
-
對迭代速度要求高,希望需求快速交付上線
-
基礎架構強,持續集成工具高效;
-
團隊成員習慣 TDD(測試驅動開發),代碼自動化測試覆蓋率高(至少增量代碼的自動化測試覆蓋率高);
2. 整體架構
2.1 衡量主幹開發的效果
可以通過執行以下操作來衡量主幹開發的效果。
測試的因素 | 衡量的指標 | 目標 |
---|---|---|
應用代碼庫中的活躍分支數。 | 衡量應用代碼庫版本控制系統中的活躍分支數,讓所有團隊都能看到此數字。然後跟蹤目標狀態的增量式進度。 | 不超過三個活躍分支。 |
代碼凍結期。 | 衡量團隊的代碼凍結數及凍結時長。這些衡量指標還可以對合併衝突、代碼凍結、穩定等方面所耗費的時間進行分類。 | 無人提交代碼時,沒有代碼會被凍結。 |
將分支合併到主幹的頻率。 | 衡量合併的每個分支的二進位(是/否)值,或者衡量每天合併的分支的百分比。 | 每天至少合併一次。 |
查看審批代碼更改所需的時間。 | 如果您非同步執行代碼審核,請衡量審批更改請求所需的平均時間,並特別關註所需時間大大超過平均值的請求。 | 設法使代碼審核成為在開發過程中執行的同步活動。 |
2.2 常見誤區
如需全面採用主幹開發,需要避免以下常見障礙:
-
繁瑣的代碼審核流程。許多組織的代碼審核流程都較為繁瑣,需要多次審批才能將更改合併到主幹中。如果代碼審核很費力並且需要數小時或數天才能完成,開發者會避免小批量工作,改為進行大批量更改。因為大批量代碼審核十分複雜,因此審核人員的審核時間會延長,進而造成惡性迴圈。
-
這樣的結果是開發者避免使用合併請求,從而導致合併請求經常受到冷落。由於很難通過檢查來推導大規模更改對系統的影響,因此審核人員很可能會忽略缺陷,主幹開發的優勢也就減弱了。
-
非同步執行代碼審核。如果您的團隊實行結對編程,那麼該代碼已由第二個人審核。如果需要進一步審核,則應該同步執行:開發者準備提交代碼時,應立即讓團隊中的其他人員審核代碼。開發者不應該要求進行非同步審核,例如向工具提交請求,然後在等待審核時啟動新任務。合併延遲時間越長,就越有可能發生合併衝突和相關問題。如果執行同步審核,需要團隊同意優先審核彼此的代碼而不是處理其他工作。
-
在提交代碼之前未運行單元測試或者自動化測試。為了確保主幹保持工作狀態,在提交前對代碼更改運行測試非常重要。此操作可以在開發者工作站完成,許多工具也提供針對本地更改遠程運行測試,然後在通過測試後自動提交更改的功能。如果開發者知道自己無需大量繁雜流程即可將代碼提交到主幹,那麼就會小批量更改代碼,這些更改易於理解、審核、測試,並且可以更快地遷移到生產環境。
2.3 改進主幹開發的Tip
-
小批量開發。主幹開發最重要的推動因素之一就是團隊學習如何小批量開發。這需要為開發團隊提供培訓和組織支持。
-
執行同步代碼審核。如前所述,轉換為同步代碼審核或至少確保開發者優先進行代碼審核,有助於確保所做的更改不必等待數小時甚至數天即可合併到主幹中。
-
執行全面的單元測試和自動化測試。確保您擁有全面而實用的自動化單元測試套件,併在每次提交之前運行這些測試工具。
-
快速構建。構建和測試過程應在幾分鐘內執行。目標是將測試環境的jdos部署串聯到整個CI的自動化流水線之中
2.4 主幹開發流程說明
如圖所示,研發小伙伴基於master分支開發,當每次merge時,都會觸發流水線驗證過程。在流水線驗證中:
1.EOS代碼掃描,該掃描會掃描代碼中不規範的情況,按照代碼規約不同,會有不同的級別,包括 WARNING, MAJOR, CRITICAL, BLOCKER四種級別,基於不同級別可以設置攔截規則,如果代碼不符合設定的攔截規則,將不予merge。
2.代碼評審會觸發代碼評審邀請,可以根據設定,邀請組內研發,leader,或者測試人員參與代碼評審,通過設定規則,如果代碼評審通過,才允許merge。
3.現在自動進行maven打包和單元測試工作,如果單元測試不通過,將不予merge。
4.流水線會自動將單元測試通過的jar包發佈到測試的JOS分組進行部署,部署完成後自動調取線上自動化測試流程,只有所有介面通過自動化測試,才允許merge。
3. 落地方案
3.1 單元測試
應用架構: 基於spring boot junit 編寫單元測試。
我們可以將測試按照模塊劃分,放在不同的目錄之下,可以分為集成測試和單元測試。這樣做的原因是,當我們的項目邊的越來越大的時候,寫的測試會越來越多,當所有測試都放在一個目錄下的時候,跑一次集成測試時間會很長。具體目錄如下:
主開發目錄 | 測試開發目錄 | 測試模塊 | 描述 | 測試父類命名 |
---|---|---|---|---|
src/ | test/ | init | 初始化測試模塊 | InitTestBase |
unit | service單元測試模塊 | UnitTestBase | ||
jpa | 持久化層測試模塊 | JPATestBase | ||
mvc | controller層測試 | MvcTestBase |
所有測試模塊集成對應的父類,然後類名必須以對應模塊+Test結尾,例如:ShipperStatisticUnitTest
- 引入單元測試依賴 spring-boot-starter-test
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
2. 引入 surefile 插件
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<skip>false</skip>
<includes>
<include>**/unit/*Test.java</include>
</includes>
</configuration>
</plugin>
3. 配置測試配置文件路徑
<resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<!--①-->
<excludes>
<exclude>application*.properties</exclude>
</excludes>
</testResource>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
<includes>
<include>application.properties</include>
<include>important.properties</include>
<include>application-${activatedProperties}.properties</include>
</includes>
</testResource>
</testResources>
3.2 JaCoCo代碼覆蓋率掃描
該處可以先串聯到流水線中,但不做門禁設置,等後期確定標準後,再打開門禁設置。
3.3 EOS靜態代碼掃描
在主幹開發模式中,因為EOS靜態代碼掃描,配置代碼合併門禁,確保代碼編碼規範。配置如下圖所示例子:
3.4 代碼線上評審
代碼評審通過Coding內置的評審規則實現,規則設定如下:
1.評審分支為master分支,併在push時創建代碼評審,並阻塞代碼直接合入目標分支。
2.評審人需要達到兩人及以上通過後,才能觸發隨後的操作。
3.不允許自評。
4.不允許特定成員跳過自動化檢查。
3.5 特性開關
遇到此情況,一般是多版本同時開發的情況
此處跟業務強相關,需要具體問題具體分析。不過保證如下幾個原則:
-
代碼開發儘量保證高內聚低耦合,保證類的封閉性,同時可以用常用設計模式,保證功能的業務代碼解耦,有利於特性區分。
-
個別情況,可以引入ducc配置中心,實現特性開關。
3.6 流水線配置
在行雲流水線中,主要包括如下幾個節點:
其中有一個配置上有一個小坑就是下載代碼。為什麼這麼說呢?
因為我們流水線的觸發條件是跟coding上的代碼評審配合使用,當主幹分支發生merge請求時,這個時候會觸發流水線,但拉取的代碼並不能直接填寫主幹分支名稱(如:master), 原因是當前的commit快照並沒有合併到master上,而是處於等待狀態,只有當流水線通過後才會真正合併到主幹分支,這是如果下載代碼裡拉取的主幹分支就是不包含當前提交內容的快照,並不能滿足我們的訴求。
那麼,我們該如何配置呢?
好在Webhook中會帶一些系統內置全局參數,其中globalParams.user.WEBHOOK_ATTR_COMMIT_ID,代表的就是當前提交請求所包含的 commit快照,所以,我們只需要配置這個全局參數即可,如圖所示:
配合如上配置,我們在觸發設置中,只需要設置MR created/Updated事件即可。如下圖所示:
4. 總結
於許多開發者而言,主幹開發是一項重大變革,您很可能會遇到一些阻礙。許多開發者根本無法想像如何採用這種方式工作。一項好的做法是找到曾採用這種方式工作的開發者,讓他們指導其他開發者。讓一些團隊轉為採用主幹開發方式工作也很重要。實現此目標的一種方法是將大量具有主幹開發經驗的開發者召集到一起,這樣至少有一個團隊遵循主幹開發做法。然後,如果您確信遵循此做法的團隊發揮預期的作用,則可以將其他團隊轉換為這種風格。
當然主幹開發也不是銀彈,他也會有一些自己的弊端,比如在處理需求變更,或者同時多版本並行開發時,也需要建立多個臨時分支支持,想做到純粹的主幹開發,也是過於理想化的結果。
作者:京東物流 趙勇萍
來源:京東雲開發者社區