汽車軟件敏捷開發(fā)和分支管理
?經(jīng)過十多年的發(fā)展,敏捷軟件開發(fā)已經(jīng)從一種前衛(wèi)的開發(fā)方式轉(zhuǎn)變成為在各大軟件公司中被廣泛應(yīng)用的主流技術(shù),變成了互聯(lián)網(wǎng)行業(yè)的一種潮流。隨著軟件定義汽車等概念的興起,軟件在一輛汽車中的價值正在不斷增加。電動化、網(wǎng)聯(lián)化、智能化、共享化的背后都需要強(qiáng)大的軟件能力作為支撐,而軟件能力不僅體現(xiàn)在構(gòu)建出高質(zhì)量的軟件產(chǎn)品上,同時還體現(xiàn)在軟件產(chǎn)品的快速迭代以滿足快速變化的市場需求的能力之上。這樣的變化無疑給汽車軟件開發(fā)帶來了新的挑戰(zhàn),同時也帶來了巨大的機(jī)遇。新玩家紛紛入場,期望在軟件和用戶體驗上贏得市場,而傳統(tǒng)的汽車制造商則正重新審視組織架構(gòu)、人才、流程、職責(zé)等方方面面以期適應(yīng)新的變化,成為軟件驅(qū)動的公司。
持續(xù)集成/持續(xù)發(fā)布(Continuous Integration andContinuous Delivery)是敏捷軟件開發(fā)中的核心過程,本文將從持續(xù)集成/持續(xù)發(fā)布角度探討汽車軟件開發(fā)過程中的代碼管理和發(fā)布流程。
01 傳統(tǒng)汽車軟件的開發(fā)流程
傳統(tǒng)汽車軟件開發(fā)大量依賴于供應(yīng)商,汽車制造商提出需求,由供應(yīng)商負(fù)責(zé)軟件編寫和實現(xiàn)。在過去十幾年的時間里,汽車電子器件的數(shù)量增長迅速,車內(nèi)電子控制單元(ECU)從十幾個增長到了上百個,帶來的是軟件復(fù)雜度的快速增加。除了汽車功能繁多所帶來的軟件復(fù)雜度,汽車電子類產(chǎn)品在軟硬上往往對設(shè)備的高可靠性、穩(wěn)定性有著嚴(yán)格的要求。這些要求在消費電子類,甚至是醫(yī)療電子類和工業(yè)控制類產(chǎn)品上是沒有的。因此,為了滿足功能安全等要求,汽車的軟硬件往往需要做額外設(shè)計。面對這樣的復(fù)雜系統(tǒng),汽車行業(yè)制定了許多標(biāo)準(zhǔn)及方法論以規(guī)范開發(fā)過程,而在軟件開發(fā)過程中,最有名的是ASPICE(Automotive Software Process Improvement and CapabilitydEtermination)。
Automotive SPICE簡稱ASPICE,是ISO/IEC 15504(SPICE)國際標(biāo)準(zhǔn)在車用領(lǐng)域下的修改版本。其目的是為了評估汽車產(chǎn)業(yè)中,電子控制器供應(yīng)商開發(fā)的流程。
ASPICE 建立在 V 模型之上,它需要與每個開發(fā)階段相對應(yīng)的測試階段。這是一個嚴(yán)格的模型,需要嚴(yán)格評估以確保持續(xù)的評估和發(fā)展。下圖是ASPICE中定義的典型開發(fā)流程:
From: https://www.automotivespice.com
V 模型的左側(cè)包括需求分析、系統(tǒng)設(shè)計、架構(gòu)設(shè)計、模塊設(shè)計、編碼;
V 模型的右側(cè)包括單元測試、集成測試、系統(tǒng)測試、驗收測試。
從上面可以看出,V模型是一種類似于瀑布式的開發(fā)模型,開發(fā)模型是線性的,制造商只有等到整個過程的末期才能見到開發(fā)成果。盡管在實際過程中,可以進(jìn)一步分解成更小的任務(wù)進(jìn)行驗證,但階段的劃分依然比較固定,階段之間會要求大量的文檔。
02 敏捷開發(fā)的理念
傳統(tǒng)裝載在汽車上的軟件往往一旦賣出,就不會再變更,升級需要去線下4S店完成。在這樣的情況下,基于V模型進(jìn)行軟件開發(fā)有利于需求和過程管理,明確范圍和進(jìn)度。不過,這樣的情況正在發(fā)生變化,一方面,消費者對新技術(shù)越來越感興趣,特別是與用戶有直接交互的信息娛樂系統(tǒng)或者是智能駕駛功能,用戶希望功能不斷完善,獲取新的技術(shù)不用換一臺新車;另一方面,隨著車內(nèi)固件升級(FOTA)和應(yīng)用軟件升級(SOTA)技術(shù)的成熟,汽車制造商已經(jīng)有可能在遠(yuǎn)程完成軟件的更新。軟件和硬件的開發(fā)過程正在逐步解耦,軟件需要實現(xiàn)小步快跑,不斷迭代。這個時候,汽車軟件的新老從業(yè)者們開始思考如何改變,是否能在汽車行業(yè)中應(yīng)用敏捷開發(fā)的理念或者是將敏捷開發(fā)與傳統(tǒng)的開發(fā)模型進(jìn)行結(jié)合。目標(biāo)是獲得效率和質(zhì)量的平衡。
與傳統(tǒng)計劃驅(qū)動的開發(fā)相比,敏捷開發(fā)有兩個核心理念:
1. 自適應(yīng)而不是預(yù)測;
2. 以人為本而不是流程為導(dǎo)向的。
計劃驅(qū)動的工程期望在開發(fā)之前提出一個預(yù)測計劃。該計劃列出了整個項目的人員、資源和進(jìn)度。軟件設(shè)計也是預(yù)先完成的,預(yù)計實現(xiàn)與此設(shè)計一致。成功的衡量標(biāo)準(zhǔn)是這個計劃的遵循程度。
敏捷計劃是用來幫助控制變更的基線。敏捷團(tuán)隊的計劃與傳統(tǒng)團(tuán)隊一樣仔細(xì),但計劃會不斷修改以反映在項目中學(xué)到的東西。成功取決于軟件提供的價值。
計劃驅(qū)動的工程尋求一種結(jié)構(gòu)以將個體差異減少到最低。這樣的工業(yè)流程更具可預(yù)測性,在人員轉(zhuǎn)移時能夠更好地應(yīng)對,并且更容易定義技能。
敏捷工程將軟件開發(fā)視為人類活動,其中涉及的人員以及他們?nèi)绾螀f(xié)作是成功背后的主要驅(qū)動力。
03 持續(xù)集成
在敏捷開發(fā)的理念之下,持續(xù)集成和持續(xù)交付(CI/CD)軟件產(chǎn)品(有的制造商也同樣在探索硬件產(chǎn)品敏捷開發(fā)的可能性)。持續(xù)集成和持續(xù)交付的重要特點是自動化、不斷構(gòu)建,下圖是敏捷開發(fā)的主要過程:
(From:https://faun.pub/most-popular-ci-cd-pipelines-and-tools-ccfdce429867)
持續(xù)集成和持續(xù)交付需要快速完成計劃、編碼、測試、發(fā)布的循環(huán),持續(xù)集成和持續(xù)交付并不是畫成“圓”的V模型,自動化的測試和自動化的發(fā)布是不可或缺的組成部分。而這一過程應(yīng)用于每一次提交,意味著每一次代碼的提交、合并都會經(jīng)過自動化測試,成為一個新的發(fā)布版本。為了保障效率,可在提交合并和版本發(fā)布時,進(jìn)行不同程度的測試。重要的是持續(xù)獲得版本,為進(jìn)一步驗證和最終交付給用戶提供有力支持。
為了完成快速發(fā)布,CI/CD本身也成為了一個復(fù)雜的軟件產(chǎn)品,需要專業(yè)的軟件團(tuán)隊進(jìn)行維護(hù),編寫大量代碼以實現(xiàn)各個任務(wù)的調(diào)度,集成多個工具鏈以提高整個過程的效率。而這也是汽車制造商實現(xiàn)敏捷軟件開發(fā)轉(zhuǎn)型的一個挑戰(zhàn)。在過渡期間,往往會因為工具鏈的不成熟而影響產(chǎn)品的開發(fā)效率,甚至于忽略必要的自動化測試和反饋,使產(chǎn)品的質(zhì)量出現(xiàn)問題。
04 代碼分支模型
持續(xù)集成和持續(xù)交付的落地過程中,需要考量不少因素,包括但不限于工具鏈的選擇、流程的制定、服務(wù)器的搭建等等,而代碼分支模型的選擇是持續(xù)集成團(tuán)隊和軟件開發(fā)團(tuán)隊需要在早期進(jìn)行定義并共同遵守的一項規(guī)范,下面將對持續(xù)集成過程中代碼分支模型的選擇進(jìn)行探討。
分支模型是軟件開發(fā)團(tuán)隊通過Git 等版本控制系統(tǒng)編寫、合并和交付代碼時采用的策略。好的分支模型增強(qiáng)了軟件交付過程中的協(xié)作、效率和準(zhǔn)確性。它定義了團(tuán)隊如何使用分支來實現(xiàn)并開發(fā)。
良好的分支模型往往可以達(dá)到以下目標(biāo):
1. 對持續(xù)集成的良好支持。
2. 確保高頻率的集成。
3. 減少合并沖突和處理沖突的成本(在開發(fā)過程中,處理大量合并沖突是開發(fā)人員非常頭痛的問題,并且很容易發(fā)生錯誤)。
比較常見的分支模型有:Git-flow、GitHub Flow、GitLab Flow和Trunk-based development。
使用Trunk-baseddevelopment是持續(xù)集成中常見的選擇,下面簡單介紹一下各個分支模型的特點。
Trunk-based development
Trunk-based development (TBD) 是基于主干開發(fā)的一種分支模型,所有開發(fā)人員每天都將他們的更改直接集成到共享主干(trunk或master)中。理想情況下,主干始終處于可發(fā)布狀態(tài)。
下圖說明了 TBD 的基本流程:
(From:https://trunkbaseddevelopment.com/#scaled-trunk-based-development)
基于主干開發(fā)的典型策略如下:
1. 開發(fā)基于主干,沒有長期存在的功能分支(feature branch)。如果需要功能分支,它應(yīng)該是本地的或短期的,并在幾天內(nèi)合并到主干;
2. 主干應(yīng)保持健康且可發(fā)布的狀態(tài);
3. 發(fā)布分支(release branch)從主干中“即時”檢出(checkout)(例如發(fā)布前 2 周)并在發(fā)布之前凍結(jié)(例如發(fā)布前 1 周);
4. 修復(fù)應(yīng)該首先上傳到主干,然后cherry-pick到發(fā)布分支(這有助于確保主干中包含所有修復(fù)并避免回退)。
TBD非常適合持續(xù)集成,持續(xù)集成的流程可以在主干上運行,對每次提交進(jìn)行驗證,在代碼成功合并后進(jìn)一步生成交付物。發(fā)布分支是為了更好管控產(chǎn)品的質(zhì)量。因為實際過程中,盡管主干經(jīng)過驗證,但缺少凍結(jié)過程,新的提交容易造成意想不到的問題,發(fā)布分支的存在有效控制了這一影響。在發(fā)布分支檢出后,同樣可以與主干一起進(jìn)行持續(xù)集成和交付。
使用TBD的主要挑戰(zhàn)是當(dāng)有體量較大的新特性需要開發(fā)時,高頻集成會相對較難,開發(fā)人員需要額外的工作(如使用標(biāo)志位等方式),避免不完整的功能在產(chǎn)品中運行。
Git Flow
Git Flow模型背后的主要思想是將工作隔離到不同類型的分支(main, develop, feature, release, hotfix)。主干分支和開發(fā)分支都是長期存在的。下圖是Git Flow的典型流程:
(From:https://docs.gitlab.com/ee/topics/gitlab_flow.html#git-flow-and-its-problems)
雖然Git Flow使開發(fā)、修復(fù)、發(fā)布分支很清晰,但很難在采用Git Flow的工程項目上進(jìn)行持續(xù)集成,main和develop分支都是長期存在的,且隨著時間的增加,兩者可能會有越來越大的差異,難以形成自動化的集成交付閉環(huán)。
GitHub Flow
GitHub Flow 對Git Flow進(jìn)行了改進(jìn)。開發(fā)人員使用功能分支(feature branch)并定期將其功能分支推送到主干。發(fā)布通常是直接從主干完成的。每個開發(fā)人員都會創(chuàng)建一個新分支,即功能分支。功能分支在功能完成后合并到主干。
GitHub Flow對持續(xù)集成提供良好支持,但功能分支可能會存在較長的時間,從而影響軟件集成的頻度。
另外,GitHub Flow的概念中并沒有發(fā)布分支,發(fā)布直接從主干進(jìn)行,會對軟件的質(zhì)量的管控帶來更大的挑戰(zhàn)。
GitLab Flow
GitLab Flow在GitHub Flow的基礎(chǔ)上增加了發(fā)布分支(release branch),對持續(xù)集成有良好的支持,也可以對需要發(fā)布的產(chǎn)品提前進(jìn)行凍結(jié)以便對質(zhì)量進(jìn)行更好的管控。它和TBD的主要區(qū)別是在模型的理念上,TBD更加鼓勵高頻率的代碼合并和集成。?