代碼規范的自動化監管
英文原文:Implementing Automated Governance for Coding Standards
作者:Mark Figley 譯者:羅小平
多數大型開發組織都有一套自己的編碼和實踐規范。但是對這些團隊而言,光是將這些規范文檔化,并保證實時更新,就是一個巨大的挑戰。此外,在工作中長期、忠實地執行這些規范和標準,難度就更大。我們團隊在這些方面做了積極探索,在整個構建過程(build process)中實現了代碼規范的自動化監管。
積極主動、未雨綢繆是工作取得好成果的重要保證。即使在很成熟的組織中,建立了代碼復審流程,審查結果也能直接反饋給責任人,但如果復審是在事后進行,仍然存在很大風險。因為這個時候,錯誤已成現實,很可能已經進入測試和產品環境,從而造成實質性損失;而這時候再回頭修改,開發人員也有抵觸情緒,缺乏積極性。從我們的經驗看,構建過程必須自始至終處于受控之中,在所有的軟件開發過程中,對應的代碼審查工作都應該自動完成。只有這樣,錯誤代碼才能在第一時間消除,從而避免到最后階段采取回溯式審查方法所產生的成本高昂和開發人員抵觸等問題。不帶任何感情色彩的自動化系統可實時向開發人員反饋Web頁形式的報告,幫助他們解決可能存在的問題;而且通過反復提醒,也可以讓開發人員被動熟悉新的編程規范。
中心化的構建過程管理
為保證我們的上述策略真正落到實處,必須做好兩項工作:
- 構建過程必須是基于服務端的、中心化管理的。我們曾在Ant腳本基礎上自行開發了一個構建管理系統(Build Management System,BMS),因為那時候像AntHill、Maven等產品還沒有發展成熟。如果是現在,我肯定會選擇第三方的BMS,而不是自己從頭做起。自己開發,方便實現一些特殊的定制化需求,但現在很多第三方BMS都有功能集成能力。
- 必須樹立這樣的觀念:深度使用BMS,是團隊大幅提高代碼質量的唯一途徑。我這不是搞教條,在這個問題上,其實別無選擇。如果開發人員可以繞過監管系統,直接將Java類文件FTP傳送到服務器,那么我們正在這里討論的解決方案的有效性就大打折扣了。我們應該控制對服務器上相關目錄的訪問,只將寫入權限授予負責運行JVM過程(即我們的構建系統的宿主)的帳戶,這樣,開發人員必須通過BMS,才能將代碼傳遞到生產和測試環境。這樣一個過程,有連個顯而易見的好處:(1)保證在測試和生產環境中的源代碼控制;(2)確保在這些環境的所有代碼都通過了自動化的軟件審查。
工具化的軟件自動審查
我們使用的代碼自動審查工具是Parasoft的Jtest,當然還有很多工具可以完成類似功能。總的來說,Jtest是一個有效的管理工具,不過也存在一些問題。比如在使用之前,必須搭建一個基礎運行環境;另外,它并不是一個黑盒式的解決方案,這也是背離我們希望的。Jtest包括靜態分析和動態分析。其動態分析功能比較強大,不過這已超出了本文的討論范圍。
4年前,我們團隊因為數據庫連接未關閉問題焦頭爛額。資源未能在try/catch/finally塊中得到正確清理(大家是否感覺很熟悉?),因此引入了Jtest。在當時,Rod Johnson大仙(譯者注:Spring框架和《Expert One-on-One J2EE Development without EJB》的作者)還沒有下凡,沒有給我們帶來JdbcTemplate,因此很多公司都還在與此問題奮戰。而解決這類問題,恰是Jtest的強項。其運作原理是:分析Java類的結構和內容,檢查它們與既定規則的匹配程度。比如規則可能是這樣的:若在某個方法體中創建或從連接池中取得了數據庫連接,那么必須保證存在一個try/catch/finally塊,且在finally塊中關閉了連接,或將連接放回了連接池。4年前,我們就利用Jtest設立了這樣一個規則,將其嚴重程度定位一級,并在構建系統中設置:當Jtest錯誤出現時,構建過程自動暫停當前工作。這個系統工作得很好,數據庫連接問題再也沒有出現過。
現在,我們有了Rod和他的JdbcTemplate,但對于那些還沒有轉換到Spring的遺留Java應用來說,上述規則仍可發揮作用。此外,Jtest還可以強制執行很多其他結構性標準檢查工作。比如,我們團隊實施日志標準后,就引入了另一項規則,以杜絕代碼中再出現System.out.println語句的可能。上述這些功能,不過是Jtest的冰山一角。在Jtest魔盒中,規則多達數百項,你還可以根據自己需要創建新的規則。
但現在的一個問題是,Parasoft對服務端Jtest的支持不夠理想。該公司的主要產品是一個Eclipse插件,此插件負責在IDE內部對代碼執行靜態和動態分析。這不是我所想要的,我需要的是一個基于服務端的Jtest產品,服務端環境可以集成并調用它的功能。Parasoft認為我們討論的這種最終式的組織控制和監管,可以通過購買IDE插件(安裝到所有開發者的IDE),外加一個中心化的Parasoft報告服務器實現。但我們發現事實并非如此。Parasoft不能保證所有開發人員在將代碼簽入CVS前都會自覺執行靜態檢查。我們沒有辦法控制這類插件,沒有Jtest插件報告“停!在有一級錯誤前你不能簽入”這樣的控制點。因此,這種審查不宜放在客戶端執行,而必須有一個中心化的控制點,也就是一個中心化的BMS。我們需要的是服務端版本的Jtest,由我們自己完成對它的集成(雖然有點麻煩)。
當然,我得再次強調,Jtest不是唯一選擇。Adrian Colyer等人談到過利用AspectJ完成代碼強制檢查。在中心化的監管服務器上,這樣的功能很容易實現。我不能確定Jtest是否能滿足你的全部要求,不過它有免費的優勢。其他同類型產品以及eclipse插件一般能完成Jtest的不同部分功能。如果你想圖省事,可以選擇eclipse中的標準插件JDT,它支持從格式和句法兩個方面對源代碼做標準檢查。
實施監管的最佳實踐
軟件自動化監管策略遠比你選擇什么樣的技術構建解決方案更為重要。如下是我們多年來從實踐中總結的經驗教訓:
- 監管結構要簡單。我們只有1、2、3共三種等級規則。違反第一等級規則時,工作將暫停,項目將無法進入測試和生產階段,直道問題解決。第二等級主要是指一個預備階段。它告訴開發人員,在下一個6-12月內,此等級的問題會上升到第一等級,因此在此之前應該將這些問題解決掉。第三等級問題不具實質危害。這個等級只是建議解決某些問題,但在上升到其他等級前,這些問題不會對工作造成影響。
- 實施過程盡可能保守些。我在上面提到過,Jtest包括數百條規則,但在應用初期,我們只實施了兩個第一等級規則。原因很簡單:循序漸進,免得一下子出現太多問題,讓項目經理手忙腳亂、無所適從。
- 實施前做好壓力分析。公布新的第一等級規則前,你應該對問題出現的頻率、修改代碼所造成的時間和財務成本作到心中有數。這一點并不困難——你只需用新規則對現在項目做一次靜態分析,然后考察分析報告。由此可避免第一等級規則實施后,讓整個組織難以為繼,最后又將其降級為第二等級的情況出現。如果分析結果顯示壓力很高,那么可首先確定為第二等級,到以后合適時期再提升等級。實施嚴格的第一等級規則之前,應該反復多次考察,必須確保管理者理解它帶來的沖擊并支持這樣的決定;而一旦實施,就應該堅決執行。
- 充分溝通。和你的團隊就新規則及其價值、實施的原因充分交流溝通。在絕大多數情況下,他們一般都能支持你,但你也不應該讓他們無征兆“驚喜”。
盡管我們在實施過程中,還遇到了很多細節問題,但這樣一個主動的、自動化的軟件審查過程給我們的組織帶來了巨大利益。我們的軟件質量得到了提升,而且更重要的是,依靠這樣一個可信賴的系統,無需投入大量精力維護。人工維護過程的工作量非常浩繁。通過合理設計你的支持結構,的確可以在投入成本更低的前提下,給整個組織帶來更高的安全性。
作者簡介
Mark Figley:擁有8億美元資產的美聯保險公司(AIG United Guaranty)的架構組負責人。