阿里巴巴Java開發手冊評述|洞見

2021-03-02 ThoughtWorks洞見

註:本文基於阿里巴巴技術手冊的1.0.2版本編寫。

2016年底,阿里巴巴公開了其在內部使用的Java編程規範。隨後進行了幾次版本修訂,筆者當時看到的版本為v1.0.2版。下載地址可以在其官方社區——雲棲社區找到。

筆者作為一名有數年工作經驗的Java程式設計師,仔細研讀了這份手冊,覺得是一份不可多得的好材料。正如阿里巴巴在發布時所說,「阿里巴巴集團推出的《阿里巴巴Java開發手冊(正式版)》是公司近萬名開發同學集體智慧的結晶,以開發視角為中心,詳細列舉了如何開發更加高效、更加容錯、更加有協作性,力求知其然,更知其不然。結合正反例,讓Java開發者能夠提升協作效率、提高代碼質量。」 同時,阿里巴巴也期望這套Java統一規範標準將有助於提高行業編碼規範化水平,幫助行業人員提高開發質量和效率、大大降低代碼維護成本。

   

其實早在多年前,Google就已經把公司內部採用的所有語言的編碼規範(其稱為Style Guide)都開源在Github上。這份清單中包括了C++、Objective-C、Java、Python、R、Shell、HTML/CSS、JavaScript、AngularJS、Common Lisp、Vimscript等語言的編程規範。並且Google還發布了一個用於檢查樣式合規性的工具cpplint以及在Emacs中使用Google編程樣式的配置文件google-c-style.el。看來Google中Emacs粉比Vim粉要強勢的多。

Google為什麼要發布這樣的Style Guide呢?因為它認為幾乎所有的開源項目都需要有一組約定來規範如何編寫代碼。如果項目中的代碼都能保持一致的風格,那麼即使代碼再多也會很容易的被人理解。

(圖片來自:http://t.cn/R63jrWi)

Google的這份編程規範包含了很多方面,從」對變量使用camelCase命名法」到」絕不要使用全局變量」到」絕不允許例外「等。其Java編程規範包含7大部分,分別為介紹、源文件基本要求、源文件結構、格式化、命名、編程實踐和Javadoc。每一部分又細分為很多子條目。如果採取條規範的原因不是很容易理解,都會配有相應的示例或者引用文章。

由於Google的這份編程規範目前只有英文版本,所以在中國的程式設計師中只有少部分人知道它的存在。並且只有更少的團隊在真正的應用它,其中就包括我的團隊。我們團隊根據Google的Java style guide也演化出了自己的團隊版本,放置在團隊共享wiki上供大家隨時查閱。我們根據自身的項目特點豐富了"編程實踐"裡的內容,並且新加入一個章節來描述編寫Java代碼的一些原則,比如簡潔代碼、組合優於繼承、stream優於for循環等。

我想阿里巴巴發布的Java開發手冊之所以叫做"開發手冊",而不是像Google那樣叫做「Style Guide(樣式風格)」,是因為它不僅僅局限於style guide這一方面,而是以Java開發者為中心視角,劃分為編程規約、異常日誌規約、MYSQL規約、工程規約、安全規約五大塊,再根據內容特徵,細分成若干二級子目錄。根據約束力強弱和故障敏感性,規約依次分為強制、推薦、參考三大類。

該開發手冊中的每一條都值得了解。限於篇幅原因,這裡只列出」編程規約「中有感受的幾條來評述一下。

15.【參考】各層命名規約:

A) Service/DAO層方法命名規約

1) 獲取單個對象的方法用get做前綴。

2) 獲取多個對象的方法用list做前綴。

3) 獲取統計值的方法用count做前綴。

4) 插入的方法用save(推薦)或insert做前綴。

5) 刪除的方法用remove(推薦)或 delete 做前綴。

6) 修改的方法用update做前綴。

B) 領域模型命名規約

1) 數據對象:xxxDO,xxx即為數據表名。

2) 數據傳輸對象:xxxDTO,xxx為業務領域相關的名稱。

3) 展示對象:xxxVO,xxx一般為網頁名稱。

4) POJO是DO/DTO/BO/VO的統稱,禁止命名成xxxPOJO。

命名規約的第15條描述了在Service/DAO層對於資源的操作的命名規範。這一條的參考價值極大,因為我所有待過的團隊對於這一點都沒有明顯的約束,每個團隊都有五花八門的實現。如果能遵守這一點,那麼我們在操作資源時就會減少一些困擾。

2.【強制】long或者Long初始賦值時,必須使用大寫的L,不能是小寫的l,小寫容易跟數字1混淆,造成誤解。

說明:Long a = 2l; 寫的是數字的21,還是Long型的 2?

這是常量定義的第2條。從這一點可以看出阿里巴巴對代碼可讀性的細節扣的很嚴格。我也很贊同這一點。代碼只需編寫一次,而會被查看無數次,所以要力爭在第一次編寫的時候儘可能少的引入歧義。

1.【強制】大括號的使用約定。如果是大括號內為空,則簡潔地寫成{}即可,不需要換行;如果是非空代碼塊則:

1)左大括號前不換行。

2)左大括號後換行。

3)右大括號前換行。

4)右大括號後還有else等代碼則不換行;表示終止右大括號後必須換行。

格式規約的第1條終於終結了括號之爭。這一條需要強制遵守,那麼左大括號換行一派則被徹底排除在阿里巴巴之外。有人說不推薦左大括號換行,可以減少行數,增加單個屏幕可以顯示的代碼行數。而有的人反駁說現在屏幕已經足夠大,不換行則破壞了對稱之美。其實對於我來說兩種格式都有各自的好處,我都可以接受,只要團隊能夠堅持使用其中之一即可。

5.【強制】縮進採用4個空格,禁止使用tab字符。

說明:如果使用tab縮進,必須設置1個tab為4個空格。IDEA設置tab為4個空格時,請勿勾選Use tab character;而在eclipse中,必須勾選insert spaces for tabs。

正例:(涉及1-5點)

public static void main(String[] args) {
 // 縮進4個空格
 String say = "hello";
 // 運算符的左右必須有一個空格
 int flag = 0;
 // 關鍵詞if與括號之間必須有一個空格,括號內的f與左括號,0與右括號不需要空格
 if (flag == 0) {
   System.out.println(say);
 }
 // 左大括號前加空格且不換行;左大括號後換行
 if (flag == 1) {
   System.out.println("world");
   // 右大括號前換行,右大括號後有else,不用換行
 } else {
   System.out.println("ok");
   // 在右大括號後直接結束,則必須換行
 }
}

使用空格代替tab字符進行縮進已經成為了編程界的共識。其主要原因是不同的平臺甚至不同的編輯器下tab字符的長短是不一樣的。不過Google在其《java style guide》中規定縮進為2個空格,而阿里巴巴約定為4個空格。由於4個空格的縮進比2個空格的縮進長一倍,所以如果在代碼嵌套過深的情況下可能會很快超過單行最多字符數(阿里巴巴規定為120個)的限制。不過這個問題可以從另一個方面進行思考,如果由於縮進的原因導致單行字符數超標,這很可能是代碼設計上有壞味道而導致嵌套過深。所以最好從調整代碼結構的方面下手。

6.【強制】單行字符數限制不超過120個,超出需要換行,換行時遵循如下原則:

1)第二行相對第一行縮進4個空格,從第三行開始,不再繼續縮進,參考示例。

2)運算符與下文一起換行。

3)方法調用的點符號與下文一起換行。

4)在多個參數超長,逗號後進行換行。

5)在括號前不要換行,見反例。

正例:

StringBuffer sb = new StringBuffer();
//超過 120 個字符的情況下,換行縮進 4 個空格,並且方法前的點符號一起換行
sb.append("zi").append("xin")...
 .append("huang")...
 .append("huang")...
 .append("huang");

反例:

StringBuffer sb = new StringBuffer();
//超過 120 個字符的情況下,不要在括號前換行
sb.append("zi").append("xin")...append
("huang");
//參數很多的方法調用可能超過 120 個字符,不要在逗號前換行
method(args1, args2, args3, ...
, argsX);

關於換行,Google並沒有給出明確的要求,而阿里巴巴則給出了強制性的要求。Google特別提示可以通過一些重構手法來減少單行字符長度從而避免換行,這一點我頗為認同。

關於參數,很多方法調用超過120個字符需要換行,這暴露除了過長參數列的代碼壞味道,解決方式之一就是使用重構手法的Replace Parameter With Method的方式把一次方法調用化為多次方法調用,或者使用Introduce Parameter Object手法創造出參數對象並進行傳遞。

17.【推薦】循環體內,字符串的聯接方式,使用StringBuilder的append方法進行擴展。 反例:

String str = "start";
for (int i = 0; i < 100; i++) {
 str = str + "hello";
}

說明:反編譯出的字節碼文件顯示每次循環都會new出一個StringBuilder對象,然後進行append操作,最後通過toString方法返回String對象,造成內存資源浪費。

這是《Effective Java》以及其他文章中經常提及的優化方式,而且面試初級Java工程師時幾乎是一個必考點。其實不僅是在循環體內,所有需要進行多次字符串拼接的地方都應該使用StringBuilder對象。

20.【推薦】類成員與方法訪問控制從嚴:

1)如果不允許外部直接通過 new 來創建對象,那麼構造方法必須是 private。

2)工具類不允許有public或default構造方法。

3)類非static成員變量並且與子類共享,必須是protected。

4)類非static成員變量並且僅在本類使用,必須是private。

5)類static成員變量如果僅在本類使用,必須是private。

6)若是static成員變量,必須考慮是否為final。

7)類成員方法只供類內部調用,必須是private。

8)類成員方法只對繼承類公開,那麼限制為protected。

說明:要嚴控類、方法、參數、變量的訪問範圍。過寬泛的訪問範圍不利於模塊解耦。思考:如果是一個private的方法,想刪除就刪除,可是一個public的Service方法,或者一個public的成員變量,刪除一下,不得手心冒點汗嗎?變量像自己的小孩,儘量在自己的視線內,變量作用域太大,會無限制的到處跑,那麼你會擔心的。

這其實就是經典的原則『Principle of least privilege』 的體現。我們必須遵循這一原則,但不知為何阿里巴巴將其級別列為「推薦」。

7.【參考】方法中需要進行參數校驗的場景:

1)調用頻次低的方法。

2)執行時間開銷很大的方法,參數校驗時間幾乎可以忽略不計,但如果因為參數錯誤導致 中間執行回退,或者錯誤,那得不償失。

3)需要極高穩定性和可用性的方法。

4)對外提供的開放接口,不管是RPC/API/HTTP接口。

5)敏感權限入口。

8.【參考】方法中不需要參數校驗的場景:

1)極有可能被循環調用的方法,不建議對參數進行校驗。但在方法說明裡必須註明外部參 數檢查。

2)底層的方法調用頻度都比較高,一般不校驗。畢竟是像純淨水過濾的最後一道,參數錯 誤不太可能到底層才會暴露問題。一般DAO層與Service層都在同一個應用中,部署在同一臺伺服器中,所以DAO的參數校驗,可以省略。

3)被聲明成private只會被自己代碼所調用的方法,如果能夠確定調用方法的代碼傳入參數已經做過檢查或者肯定不會有問題,此時可以不校驗參數。

編寫代碼時,對參數進行校驗是不可避免的。詳細說又扯到「防禦式編程」和「契約式編程」的話題上。這兩項之所以列為參考,並沒有強迫大家遵守。

6.【推薦】與其「半吊子」英文來注釋,不如用中文注釋把問題說清楚。專有名詞與關鍵字保持英文原文即可。

反例:「TCP連接超時」解釋成「傳輸控制協議連接超時」,理解反而費腦筋。

看到這一條我已經笑出來了。這一條說的很好,注釋是用來闡述問題的,如果看了注釋還一頭霧水,那麼這樣的注釋不要也罷。使用中文沒什麼可丟人的,解決問題才是王道。

7. 【推薦】代碼修改的同時,注釋也要進行相應的修改,尤其是參數、返回值、異常、核心邏輯等的修改。

說明:代碼與注釋更新不同步,就像路網與導航軟體更新不同步一樣,如果導航軟體嚴重滯後, 就失去了導航的意義。

阿里巴巴對該條的說明非常到位。其實我們團隊在編寫代碼時默認是沒有任何注釋的,因為我們追求的是self-explanatory methods。即代碼本身已經就能說明它的用途。只有在很少的情況下需要添加注釋。

編程規約的第九部分都是很好的tips,值得去了解和學習。

除了編程規約之外,日誌規約、MySQL規約、工程規約和安全規約也都有極高的參考價值,這也是比Google的Java Style Guide出色的地方。這裡就不再評述了。

   

阿里巴巴公布這個Java開發手冊絕對是值得讚賞的事情。最後我也想給其提幾點建議:

1、建議使用公開wiki的方式發布該手冊,而不是採用pdf的方式。因為如果像google那樣是公開wiki方式的話,可以方便大家參與修正和改進,並且可以看到版本歷史。

2、該手冊並沒有明確的版權許可,只是在頁腳處加入了「禁止用於商業用途,違者必究」的字樣。Google的style guide的版權為CC-By 3.0 License,建議阿里巴巴能夠指明其版權。

3、手冊中的部分示例代碼並沒有遵守其列出的編程規約,有點打臉之嫌。比如以下示例代碼:

Iterator<String> it = a.iterator();
while(it.hasNext()){
 String temp = it.next();
 if(刪除元素的條件){
   it.remove();
 }
}

其while和if關鍵字與小括號之間並沒有空格,違反了該手冊中「3.【強制】if/for/while/switch/do等保留字與左右括號之間都必須加空格。」這一規則。

4、集合處理中可以多推薦一些Java8的集合操作方法。

5、有些名詞沒有過多解釋,比如很多人可能都不知道什麼叫一方庫、二方庫。

6、希望除了這份開發手冊以外,阿里巴巴也可以推出對應的checkstyle配置文件以及Intellij、Eclipse的配置文件。畢竟格式化這些事都可以交由IDE來解決,通過在構建時使用checkstyle插件也可以防止不合規的代碼遷入到倉庫,從源頭上保證代碼樣式的一致性。

最後,希望這份Java開發手冊可以持續改進,吸納百家之長,成為每個入門程式設計師必看的手冊。

- 相關閱讀 -

Spring Batch在大型企業中的最佳實踐|洞見

以敏捷的方式運作一所大學|洞見

點擊[閱讀原文]可到ThoughtWorks官網查看原文和後續文章內容&綠字部分。

本文版權屬ThoughtWorks公司所有,如需轉載請在後臺留言聯繫。

相關焦點

  • 優秀Java開發者必備的技術素養——阿里巴巴《Java開發手冊》
    《阿里巴巴Java開發手冊》,該版本將是阿里官方對外釋放的最後一個PDF版本,也是史上內容最全、修正最為徹底的一個版本,並且史無前例地增加了單元測試規約,絕對值得珍藏。小編費盡周折為大家找到了快速下載連結,喜歡的猿猿們趕緊收藏吧~終極版Java開發手冊看點《阿里巴巴Java開發手冊》系統性地從編程、資料庫、異常日誌、工程結構、安全、單元測試六大方面,總結出優秀Java開發者必備的技術素養。
  • 《阿里巴巴Java開發手冊》2018年完整資料下載!
    《阿里巴巴Java開發手冊》(以下簡稱《手冊》)是阿里內部Java工程師所遵循的開發規範,涵蓋編程規約、異常日誌、單元測試、安全規約、MySQL資料庫、工程規約、設計規約7大維度。《手冊》是近萬名阿里Java技術精英的經驗總結,經歷了多次大規模一線實戰檢驗及完善;是阿里回饋給Java社區的一份禮物,旨在提升團隊研發效能,幫助企業開發團隊在Java開發上更高效、容錯、有協作性,提高代碼質量,降低項目維護成本。
  • 《Java 開發手冊》的前世今生(附全部版本下載)
    《Java 開發手冊》始發於阿里巴巴內部規約,涵蓋編程規約、異常日誌、單元測試、安全規約等七大維度。從 2017 年上線至今整整四年,共發布了七個版本,在全球 Java 開發者共同努力下,這本手冊已經成為業界普遍遵循的開發規範,感謝大家一直和我們在碼出高效、碼出質量的路上並肩同行。本文將介紹每個版本手冊更新的亮點,文末可以下載所有版本的合集。
  • 「Java開發者的福音」泰山版《Java開發手冊》速覽!附下載地址.
    經過一年的修煉,《Java 開發手冊》泰山版於 4.22 正式發布。泰山版發布之後,我便立馬去下載簡單閱讀了一下新增加了內容。Guide 哥:我平時會經常拿出來看看,裡面的很多精華都是阿里工程師踩坑而得,學到就可以立馬用到,避免再犯同樣的錯誤。
  • 阿里官方Java代碼規範標準《阿里巴巴Java開發手冊 終極版 v1.3.0》
    終極版 v1.3.02017年開春之際,阿里誠意獻上重磅大禮:《阿里巴巴Java開發手冊》,首次公開阿里官方Java代碼規範標準。
  • JAVA開發公約
    碼出高效,碼出質量,是每個程式設計師都在孜孜不倦追求的目標,尤其現在都是在協同開發,公約的建立更是至關重要。
  • 為什麼阿里巴巴Java開發手冊中強制要求超大整數禁止使用Long類型返回?
    在閱讀《阿里巴巴Java開發手冊》時,發現有一條關於前後端超大整數返回的規約,具體內容如下:這個問題在之前和前端聯調的時候發生過,發現根據腳本 id 去審批的時候,狀態沒有變化,後來和前端溝通後,才知道這是 JavaScript 的一個坑,下面來復現下這個錯誤:錯誤演示
  • 《阿里巴巴Java開發規約》插件全球首發!
    經過247天的持續研發,阿里巴巴於10月14日在杭州雲棲大會上,正式發布眾所期待的《阿里巴巴Java開發規約》掃描插件!
  • 《阿里巴巴 DevOps 實踐手冊》,免費下載
    在實施DevOps之前,開發和運維團隊是兩個獨立的團隊,每個團隊都有自己的目標
  • 阿里技術團隊重磅開放 《Java 開發手冊》(附下載地址)!
    《阿里巴巴 Java 開發手冊》的願景是碼出高效,碼出質量。
  • 反對《阿里巴巴Android開發手冊》中NestedScrollView嵌套RecyclerView的用法
    個人始終覺得《阿里巴巴Android開發手冊》是一本好手冊,上面確實提供了很多Android開發的開發者注意不到的地方,個人也從中獲益匪淺,這片文章也只是針對其中的一點談了一些自己不一樣的理解。這也就是為什麼《阿里巴巴Android開發手冊》中禁止ScrollView嵌套ListView/GridView/ExpandableListView。
  • 阿里巴巴Java代碼規約插件p3c-pmd使用指南與實現解析
    2017年9月底,阿里巴巴集團發布了《阿里巴巴Java開發手冊》PDF終極版,2017年10月14日,在2017杭州雲棲大會上,Java代碼規約插件全球首發
  • 原創 | 為什麼阿里巴巴要求謹慎使用ArrayList中的subList方法
    在之前的一些文章中,我們介紹過一些關於使用集合類應該注意的事項,如《為什麼阿里巴巴禁止在 foreach 循環裡進行元素的 remove/add 操作》、《為什麼阿里巴巴建議集合初始化時,指定集合容量大小》等。關於集合類,《阿里巴巴Java開發手冊》中其實還有另外一個規定:
  • 阿里巴巴的26款超強Java開源項目!
    Spring Cloud Alibaba分布式應用服務開發的一站式解決方案 Spring Cloud Alibaba分布式應用服務開發的一站式解決方案 Spring Cloud AlibabaSpring Cloud Alibaba 致力於提供分布式應用服務開發的一站式解決方案。
  • Java基礎:開發環境如何搭建(新手必藏)
    1 前言在上一篇 Java編程學習指南 中我們了解了Java的前世今生,接下來介紹一下如何在Windows作業系統中搭建開發運行環境。
  • 《Java開發手冊》解讀:大整數傳輸為何禁用Long類型?
    阿里妹導讀:最新發布的《Java開發手冊(嵩山版)》增加了前後端規約,其中有一條:禁止服務端在超大整數下使用Long類型作為返回。
  • 【基礎回溯2】Java 基礎知識疑難點/易錯點
    BigDecimal 的用處《阿里巴巴Java開發手冊》中提到:浮點數之間的等值判斷,基本數據類型不能用==來比較,包裝數據類型不能用 equals 來判斷。《阿里巴巴Java開發手冊》對這部分內容也有提到如下圖所示。《阿里巴巴Java開發手冊》對這部分BigDecimal的描述1.3.5. 總結BigDecimal 主要用來操作(大)浮點數,BigInteger 主要用來操作大整數(超過 long 類型)。
  • Java 集合使用不當,Code Review 被 diss了!
    這篇文章我根據《阿里巴巴 Java 開發手冊》總結了關於集合使用常見的注意事項以及其具體原理。強烈建議小夥伴們多多閱讀幾遍,避免自己寫代碼的時候出現這些低級的問題。Java 開發手冊》的描述如下:在使用 java.util.stream.Collectors 類的 toMap() 方法轉為 Map 集合時,一定要注意當 value 為 null 時會拋 NPE 異常。
  • 為什麼阿里巴巴不建議 boolean 類型變量用 isXXX?
    private boolean hot;public boolean isHot() {        return hot;        }        5.包裝類型private Boolean hot;public Boolean getHot() {        return hot;        }阿里巴巴規範
  • 下載 | 新版Java開發手冊有哪些亮點?
    《Java 開發手冊(嵩山版)》特別增加了前後端規約,並修復了一些原來存在的一些問題,接下來讓我們先品嘗一些嵩山版帶來的新的滋味吧。此外為了更好地幫助大家理解運用,特別綜合過往的規約和新增修訂的內容給大家帶來了一套測試題,還有機會獲得機械鍵盤和社區周邊!點擊「閱讀原文」,下載嵩山版。