持續交付探索與實踐(三):指標度量體系搭建

g發表於2022-03-18

一、前言

前面兩篇分別介紹了我們是如何通過建立視覺化的交付流水線來使得整體交付過程更加緊密順暢,以及如何通過各類自動化手段來提升整體的交付效率;這就好比汽車生產流水線的引入和機械化升級分別帶來了前兩輪汽車生產效率的革命性提升。而汽車生產效率的第三輪革命性提升可以說是由豐田公司提出的“精益製造”所引發的,其強調的理念是實時監控生產品質,以便及早發現問題加以改進。管理學之父彼得-德魯克也說過——“無法度量,就無法改進”,度量能幫助我們更深刻的認知研發效能,設定改進方向,並衡量改進後的效果。所以,想要持續的提升效能,最首要的任務就是建立度量效能的能力,以便更好的識別交付過程中的質效瓶頸。本文主要介紹下我們在交付質量及交付效率兩方面的度量實踐

持續交付流水線

二、指標度量體系搭建

2.1、質量度量

程式碼質量在研發過程中是一個很重要的因素,更好的程式碼質量能產生更少的 BUG,也能降低程式碼的維護成本使開發人員更不容易犯錯,從而使產品的質量得到提升。那麼,如何定義程式碼質量,如何測量並視覺化的展現就成了我們探索的方向。我們的程式碼質量監控體系從無到有,從基礎檢測到系統性評測大致經歷瞭如下 3 個階段。

1)第一階段:質量標準確定

這一階段我們主要目標是快速建立程式碼規範及對應的自動化檢測手段,所以我們更多的是考慮高價效比的方案,比如引入第三方檢測工具。SonarQube 是一款目前比較流行的工具,採用 B/S 架構,通過外掛的形式可以支援 Java、C、C++、JavaScript 等二十多種程式語言,同時也可以整合不同的檢測工具和規則,比如 pmd-cpd、findbugs、P3C 規範等,能較方便的實現基本的程式碼質量檢測與管理。所以最終我們將 SonarQube 作為了主要的檢測工具,通過與各業務線研發負責人梳理並調整對應的規則配置,形成了各業務線基礎的檢查規則。

而 Sonar 作為一款大而全的工具,對於部分特定的語言來說,規則的完備性和全面性肯定沒有專門針對該語言的單一工具更好。對於特定語言的規則我們後續又逐漸引入了一些針對性更強的檢測工具,比如 360的火線,該工具在安全漏洞、記憶體洩露風險方面的檢查相比 sonar 會更加完善。

另外,對於業務特性比較強的一些規則,市面上的這些工具就無法很好的支援了,針對這種規則我們主要是基於正則和語法樹解析的方式來實現自定義的檢查規則。最終形成的檢測工具集如下:

程式碼掃描工具

2)第二階段:度量指標設計

上述規範落地執行一段時間之後,我們部門內的嚴重等級以上的規範性問題基本做到了清零,但是還是會存在各種各樣的痛點,比如:簡單的規範性掃描和 code review 只能解決程式碼風格及少部分業務邏輯問題,很難發現重複率、複雜度、用例失敗等方面的問題;某個專案針對部分模組進行了重構、增加了許多 case,整體程式碼質量是變好還是變壞了?這個變化如何評估,如何量化?

針對上述問題,我們希望進一步優化程式碼質量評測體系,達成以下 2 點要求:

  • 多維度、全方位評測:提供多維度的程式碼檢測方式和評測手段,而不僅僅已程式碼違規數來作為唯一衡量標準
  • 可量化、視覺化:能數值化、視覺化的展現程式碼質量,能方便直觀的看到程式碼所存在的問題及整體質量變化趨勢

《Sonar code quality testing essential》一書中從編碼規範、潛在 BUG、文件和註釋、重複程式碼、複雜度、測試覆蓋率、設計與架構 7 個維度定義了程式碼的內在質量。為了更精細合理的度量程式碼質量,我們選取了3個與程式碼內在質量強相關的維度納入我們的評測體系:

  • 程式碼規範性得分:程式碼規範性是指否遵循了編碼規範及最佳實踐;我們主要通過Sonar、ESLint 等第三方工具及我們自研的工具對程式碼進行掃描,根據最終發現的問題數量結合權重係數,綜合計算出一個程式碼規範性得分

這裡額外提一下權重係數,它跟問題的嚴重等級,專案的規模大小都有關係;問題的嚴重等級好理解,不同等級的問題扣分不同;專案規模大小可以理解為問題密度:因為我們認為一個10萬行程式碼的專案出現10個嚴重問題,和一個1千行程式碼的專案出現10個嚴重問題,這兩者的質量情況是不一樣的

  • 程式碼重複率得分:重複率顧名思義就是重複程式碼的比例了。重複率較高的程式碼,一來增加程式碼體積、二來可能會出現程式碼漏改導致問題。我們通過統計專案程式碼的整體重複比例,然後按照一定的標準計算得到程式碼重複率得分
  • 程式碼複雜度:較低複雜度的程式碼能提高可讀性、降低維護成本,避免一些不可控的問題出現。我們通過統計專案的整體複雜度,結合程式碼總行數,得到千行程式碼複雜度,然後按照一定的標準計算得到程式碼複雜度得分

最終,我們將以上3個維度的得分綜合加權,得到一個100分制的分數,我們內部稱之為“程式碼健康度”。然後結合程式碼健康度這個指標,在日常工作中去評測我們的程式碼質量,並推動相應的質量改進。

程式碼健康度演算法

3)第三階段:優化改進推動

都說規範易定,落地難。尤其是在產品快速迭代的情況下,僅僅是為了滿足正常的業務交付大家就已經開足馬力了,提升程式碼質量這種看不到顯著短期收益的事情大家往往容易忽略。那我們是如何真正落地這個程式碼健康度指標,並推動大家在研發過程中去及時改進的呢?我們主要做了下面兩件事情

1、提高認可度

我們做的第一件事情,就是不斷優化和完善健康度演算法,使得該資料更加貼近大家的主觀認知。也就是說當大家都認為一段程式碼比較爛的時候,其健康度評分也應該是比較低的,反之亦然;只有這樣才能一定程度上的節省人工code review的成本,讓大家願意參考和使用這個指標。在這方面我們主要做了以下3點:

  • 權重優化:比如嚴重問題應該扣多少分?次要問題又應該扣多少分;不同的專案規模對這個權重係數的影響應該是多大?程式碼的重複率和複雜度多少算是優秀?等等...所有的這些權重係數,我們都跟研發團隊一起,結合具體的業務場景進行了多輪的調整和優化,並非是一蹴而就的
  • 演算法調整:比如複雜度我們最初使用的是圈複雜度,它用來描述一段程式碼的“可測性”很好,但是卻很難得出程式碼的“可維護性”方面的結果,而且對於一些特定的場景的評判會不太客觀,所以我們最終替換為了更準確的認知複雜度(詳情大家可以參考這篇文章:淺析程式碼圈複雜度及認知複雜度
  • 查漏補缺:這一點主要是指我們會針對日常code review過程中所發現的問題,不斷地補充和完善我們的程式碼檢測規則池;同時也會結合實際的業務情況對一些配置類、thrift自動生成的程式碼進行過濾,以使得評測範圍更加的精準

2、促進執行力

在大家逐漸認可了這個指標之後,我們加下來要做的就是如何更有效的推動大家進行改進了,我們主要採取了兩類實踐。

① 建立質量大盤dashboard:針對存量程式碼或者說技術債務,我們通過定期掃描來監控部門內所有專案的整體質量情況。另外,我們也通過打通內部的服務治理系統並結合各維度的資料統計進行了程式碼質量的視覺化呈現,讓大家能夠很直觀的看到部門、模組、小組、人員等維度的程式碼質量情況,方便大家進行橫向比較,讓程式碼質量好的同事和小組起到一個帶頭示範的效應;同時平臺上也支援大家進行階段性的健康度目標設定(類似OKR一樣),並通過將現狀與目標的差異顯性化的展示出來,讓大家更有目標感和使命感。

程式碼健康度大盤

② 增加流程中的質量門禁:在解決歷史債務的同時,我們也希望能在研發流程中對增量程式碼進行控制,以避免一邊在解決歷史問題,一邊又不斷新增問題的情況出現。所以我們最終結合gitlab api獲取每個需求分支對應的差異程式碼,計算出增量程式碼的健康度,並在研發流程中設定相應的檢查門禁來進行管控(增量程式碼健康度若<80則會阻斷流程)

流程中的質量門禁

最終,我們與研發團隊共同配合,基於這套可量化、視覺化的程式碼質量評測體系,在嚴格管控增量程式碼質量的同時,又不斷推動解決存量的技術債務;在近幾年實現了部門核心專案程式碼健康度的逐年上升,對最終產品質量的提升起到了正向促進作用。

 

2.2、效率度量

前文我們提到了,只要有人工參與的環節就或多或少會存在效率方面的損耗。為了更好的分析研發過程中存在的效率瓶頸,我們結合自研的交付流水線對研發流程中各個節點進行了埋點統計,實現了對各個階段、各個環節的效率資料統計和監控;同時也搭建了相應的視覺化指標平臺,方便及時發現和分析效能問題。

研發效能dashboard

然而,不同公司的業務形態、組織架構不同,對應的研發流程也不盡相同,很難說有一套銀彈能夠解決所有的效能問題。下面我就舉幾個案例,來說明下我們在效率優化方面所做的改進,希望能起到拋磚引玉,引發大家思考的這麼一個作用。

1)流程改進案例

不同於普通的業務需求,hotfix類的需求一般都是針對線上問題,需要緊急修復上線的,如果還走原來那一套研發-測試-整合-灰度-釋出的流程,就顯得有點繁瑣了,滿足不了快速上線的要求。針對這種場景,我們這邊的玩法是建立綠色通道,就是儘可能的精簡整個交付流程,僅僅保留必要的自動化驗證環節(程式碼掃描、單元測試)以及最終上線前的負責人稽核確認環節。研發團隊可以根據實際情況來選擇是走普通通道還是綠色通道,以此來做質量和效率方面的取捨和平衡。

pipeline綠色通道

除了上面提到的這種大刀闊斧的流程精簡之外,我們也是做了不少比較細的優化改進的,比如我們原先的發版審批流程如下圖所示:

研發流程優化

普通需求的審批流程這樣設定是沒什麼問題的,但是對於一些技術需求,開發負責人和產品負責人可能是同一個人,原先這個審批順序就相當於把一個人的審批動作強行給分隔開了,會造成無謂的過程等待。最終我們通過調整審批順序優化了這個問題。雖然這個改動點比較小,對於單次審批過程來說,其提升的效率是有限的。但是基數大了之後,對於團隊整體的效能提升還是很可觀的。

2)技術改進案例

除了流程方面的優化,也有一些改進是通過技術手段完成的。隨著產品的迭代、功能不斷增多,對應的自動化用例數量也隨之不斷增加,我們發現用例執行的耗時越來越長逐漸到了不可忍受的地步。為了解決這個問題,我們主要做了以下幾個方面的優化,最終實現了用例執行耗時的大幅下降:

  • 首先,是採用併發執行機制,用硬體換時間。
  • 其次,是重跑機制的優化。當檢測到沒有程式碼變更時,對於重新構建的場景我們會只執行上一次出錯的用例而非全量用例,從而節省不必要的耗時。
  • 最後,就是整體執行策略的調整。在研發流程中我們只會執行服務相關的核心用例,而將全量用例的執行留到夜間閒時去執行,以追求質量和效率上的平衡。

三、度量策略建議

借鑑業界的一些優秀實踐經驗,在效能度量和改進的落地實踐過程中我們也逐漸摸索到了一些套路,我覺得有以下幾點值得跟大家分享和探討一下:

1、指標要有目標引導性

指標的定義一定是需要有目標引導性的,不能是虛榮性的指標。舉個例子:接入程式碼健康度檢測的專案數就是虛榮性指標;而特定專案或者整體大盤的程式碼健康度變化趨勢就是一個目標引導性的指標。

2、指標需要有全域性視角

很多時候我們往往關注於優化某個具體的點,而忽略了全域性。就好比前面我們之前提到的組織之間的穀倉困局。所以指標的度量不光要考慮單個節點(比如程式碼掃描時長、單元用例執行時長),也要考慮流程之間的流轉耗時、環節之間的等待耗時等。

3、指標並非越多越好

不建議在沒有任何改進目標的前提下去進行大規模的度量,因為度量本身也是需要成本的。就好比我們去醫院看病,醫生一定是先詢問症狀,而不是一上來就讓我們做一套全身檢查。比較理想的做法是先對整個研發過程進行深度的分析,發現對應的改進點之後,再針對性的設計度量策略並採取相應的優化措施,最後再通過度量資料去驗證改進的效果。從而形成發現問題-分析問題-改進問題的這樣一個閉環。

4、指標計算需要有可靠輸入

度量指標的計算因子要有可靠的資訊輸入,不能依賴人工填寫。比如開發完成時間,就不能靠開發人員去手填,而是應該由提測前的最後一步自動化構建去自動生成。

5、不建議直接作為KPI

任何指標都無可避免的存在一定的片面性,如果強行把某些指標作為KPI往往會導致執行落地過程中變形。如果覺得這個指標比較重要,更推薦的做法是採取一定的措施,讓大家更有目標感和使命感(類似上面提到的質量看板),以此來推動改進。

效能度量指標

四、結語

以上就是我們在指標度量體系搭建方面所進行的一些探索和實踐,至此,這個持續交付系列的文章也算是接近尾聲了。寫這些內容主要目的是為了對自己的工作能有個階段性的總結,想通過輸出來倒逼自己輸入,畢竟心裡明白一件事情和把一件事情講明白還是有點差別的。當然了,如果大家能覺得這些內容其中的某一個小點有一定的參考或借鑑的價值,那也算是我的額外收穫了。

其實目前我們這套持續交付體系還存在著不少優化空間,隨著未來業務的發展,仍然不斷會有新的困難和挑戰,在效能改進方面我們依然需要不斷的探索。爭取後面再抽空整理一篇整體的回顧和總結,來闡述下我們系統的整體架構、過程中碰到的一些典型問題和決策、以及對於未來優化改進的一些思考。

相關閱讀:

持續交付探索與實踐(一):交付流水線的設計

持續交付探索與實踐(二):自動化工具鏈建設

相關文章