代碼榮辱觀-以運用風格爲榮,以隨意編碼爲恥

原文轉載於:https://blog.csdn.net/xiexiaojing/article/details/92870040

編寫代碼的八榮八恥

1. 產品命名:以簡單有趣爲榮,以平庸難記爲恥。

2. 單個函數:以短小精悍爲榮,以冗長費神爲恥。

3. 代碼維護:以持續重構爲榮,以停滯不前爲恥。

4. 編程風格:以運用風格爲榮,以隨意編碼爲恥。

5. 程序設計:以開關上線爲榮,以自信編碼爲恥。

6. 接口定義:以用戶易用爲榮,以複雜歧義爲恥。

7. 斷言分支:以實時報警爲榮,以忽略分支爲恥。

8. 監控報警:以定時調整爲榮,以放棄維護爲恥。

5Why分析

(一)

Q: 誰需要學習編寫代碼的八榮八恥?

A: 項目中的開發人員、項目經理、架構師

(二)

Q: 爲什麼學習編寫代碼的八榮八恥?

A: 可以作爲實際代碼編寫和review(複查)的指導規範

(三)

Q: 什麼人什麼時候需要review代碼?

A:

對開發人員來說,需要在時間允許的條件下定期的review自己和別人的代碼,加深對項目的整體理解。對自己的成長做總結。如果過了一段時間,還看到自己之前的代碼,覺得寫的很好的話,就需要質疑自己的成長,更努力的學習了。

對於項目經理和架構師來說,鼓勵所有上線的功能都每週抽出時間來做個組內review。或者定期抽取一些模塊做review。鼓勵大家重構代碼。在review過程中,作爲領導者需要對大家有輸出,對代碼怎麼寫是更好的有一些理論基礎。這時候就需要使用編寫代碼的八榮八恥作爲review的指導規範。

(四)

Q: 怎麼用作review的指導規範?

A: 八榮八恥中不但介紹了每個條目的意義,而且有通俗易懂的代碼實例便於和實際中的代碼在頭腦中做對比。文中明確的指出了哪些寫法是鼓勵的、哪些是不鼓勵的,是基於什麼理由不鼓勵這樣做。

(五)

Q: 編寫代碼的八榮八恥對於高可用有什麼意義?

A: 我利用美團的內部運維平臺對自己參與過的項目可用性做過統計。將影響可用性的case(具體事件)分成:開發因素和設計因素。開發因素包括系統bug、開發不規範、上線不規範、監控報警不及時(影響可用性的恢復時長)等由於具體開發者在設計階段覆蓋不到的階段發生的。設計因素包括機器故障、網絡中斷、異常流量、中間件故障等可以通過設計做容災的。結果95%以上的可用性問題都是開發因素造成的。編寫代碼的八榮八恥是對避免開發因素產生可用性問題的指導規範。

 

編程風格:以運用風格爲榮,以隨意編碼爲恥

引子

在工作中,經常發現有些程序員用面向對象的語言寫出了面向過程的代碼而自己並沒有感覺到:

前面提到有個java軟件工程師,叫Margaret。她對工作有三個要求:錢多、有趣、離家近。HR想針對這些要求和她具體溝通,問她最低標準是什麼。每一項最低要求回覆一個星級。
      

星級
    

錢多
    

有趣
    

離家近


    

1
    

年薪10萬
    

出差+旅遊佔工時1%
    

40公里

☆☆
    

2
    

年薪20萬
    

出差+旅遊佔工時10%
    

20公里

☆☆☆
    

3
    

年薪50萬
    

出差+旅遊佔工時20%
    

10公里

☆☆☆☆
    

4
    

年薪100萬
    

出差+旅遊佔工時50%
    

2公里

☆☆☆☆☆
    

5
    

年薪500萬
    

出差+旅遊佔工時80%
    

1公里

Margaret在外地,所以用了一個常用的數據交換格式json給HR回覆如下:

{"moreMoney”:4,"moreFun”:2,"closerToHome”:3}

拿到這個回覆時面向過程的解析方式是這樣寫的:

    Map json = (HashMap) JSONUtils.parse("{\"moreMoney\":4,\"moreFun\":2,\"closerToHome\":3}");    
        
    int moreMoney = (int)json.get("moreMoney");    
    int moreFun = (int)json.get("moreFun");    
    int closerToHome = (int)json.get("closerToHome");

接收方將接收到的數據轉成了json,代碼裏一堆get完成了功能。爲什麼說這是面向過程的呢?map是一種數據結構,沒有直接的業務意義。功能實現了,表達的意義卻不清晰。

這段代碼更好的一個實現方式是將接收的數據結構定義成一個對象,在java裏可以使用jackson等工具直接將json轉成有業務含義的對象。

    ObjectMapper objectMapper = new ObjectMapper();    
        
    Requirement requirement = objectMapper.readValue("{\"moreMoney\":4,\"moreFun\":2,\"closerToHome\":3}",JavaSoftwareEngineerMargaretRequirement.class);

這樣做,HR拿到的requirement不是一列列數字,需要自己對覈對每一項都是什麼意思。而是一個有完整語義的對象,利於理解。而以這種思路來進行編寫的代碼我經常稱他們叫面向對象風格的代碼。

WHY

來看一段寫赤壁山旅行的文章:

今天有幸登上赤壁山,看到這山上的景物,不禁想起了當前戰場上廝殺的場面。想起當年要不是周瑜運氣好,大冬天颳起了東風,恐怕吳國就被曹操滅了。

再來看唐代詩人杜牧經過赤壁山這個著名的古戰場,有感於三國時代的英雄成敗而寫下的《赤壁》:

折戟沉沙鐵未銷,自將磨洗認前朝。

東風不與周郎便,銅雀春深鎖二喬。

前兩句意思是在沙子底下找到一隻斷戟,磨洗之後發現“made in 赤壁”。讀者讀了這兩句不禁會聯想起當前戰場上廝殺的場面吧。

後兩句意思是要不是周瑜運氣好,大冬天颳起了東風。那孫權的老婆大喬和周瑜的老婆小喬這兩位絕世美女都要被曹操這個色老頭關進銅雀臺了。因爲曹操久仰大小喬的美貌,提前爲二人修築銅雀臺,作爲打敗吳國的戰利品。

杜牧隻字未提戰場和如果沒有東風的運氣,將會亡國的下場。但是讀者卻能心領神會,印象深刻。這是因爲杜牧採用了以小見大的風格手法。

代碼與代碼的區別如同文章與文章的區別。能否讓讀者以更短的時間、更輕鬆的讀懂?代碼是給人整體感還是噁心感?這些都決定了代碼的可維護性。而它和系統可用性、穩定性的最直接關係在工作中非常常見:“爺爺的!這是誰寫的代碼這麼爛?忍不了了,老子不幹了。”而這個代碼的作者之所以離職也是因爲忍受不了自己的爛代碼。頻繁的人員更替,新接手人員要有學習的成本。成本就包括要踩坑來加深對系統的理解。

HOW

除了開頭提到的面向對象的風格,編寫java代碼時下面三種風格也很常見。

1.fluent風格

fluent風格的代碼常以Builder結尾。比如StringBuilder就是典型的fluent風格。定義一個人的對象,這個對象使用fluent風格代碼這麼寫:

    public class Person {    
        private String name;    
        private int armCount=2;//胳膊數默認爲2    
        private int legCount=2;//腿數默認爲2    
        
        public static Person builder() {    
            return new Person.Builder();    
        }    
        
        public Person setName(String name) {    
            this.name = name;    
            return this;    
        }    
        
        public Person armCount(int armCount) {    
            this.armCount = armCount;    
            return this;    
        }    
        
        public void legCount(int legCount) {    
            this.legCount = legCount;    
        }    
    }

如上,就是每次給對象賦屬性的時候同時返回對象本身。這樣調用的時候:

Person.builder().name("Jane").armCount(2).legCount(2);

這樣寫的好處是比每個屬性都用一句set簡潔。在屬性多的時候,用構造函數。調用時容易表達不清楚屬性的含義。方法名起到了解釋的作用。現在流行的做法是代碼即註釋,註釋不用在每個方法都寫。這時候能表達自身意義的代碼就更加重要。注意:我們也可以保留setXXX、getXXX的命名規範,因爲jackson等序列化反序列化的組件會根據set、get方法對參數賦值,上面的明明風格在序列化時會有問題。

當然,這個類也可以直接用lombok註解得到。

    @Data    
    @Buildr    
    public class Person {    
        private String name;    
        private int armCount=2;//胳膊數默認爲2    
        private int legCount=2;//腿數默認爲2    
    }

2.lambda函數式編程風格

lambda函數式編程比傳統的命令式編程更加簡潔。比如:現在有一羣人。

    List<Person> personList = Lists.newArrayList();    
        
    personList.add(Person.builder().name("Jane"));    
    personList.add(Person.builder().name("Joe").armCount(1));    
    personList.add(Person.builder().name("Stark").legCount(1));

要找出所有的殘疾人:

    List<Person> disabledPersonList = Lists.newArrayList();    
    for(Person person : personList) {    
        if(person.legCount()!=2 || person.armCount()!=2) {    
            disabledPersonList.add(person);    
        }    
    }

或者使用lambda函數式編程:

List<Person> disabledPersonList = personList.stream().filter(person -> person.legCount()!=2 || person.armCount()!=2).collect(Collectors.toList());

3.設計模式風格

1995年,GoF(Gang of Four,四人幫)合作出版了《設計模式:可複用面向對象軟件的基礎》一書,共收錄了23中設計模式,人稱“GoF設計模式”。這23種設計模式的本質是面向對象設計原則的實際運用,是一種最佳實踐。

在各種java源碼中,經常看到以設計模式命名的類名和方法名。在我們日常編碼中,設計模式也非常實用。設計模式風格的例子請參考:平時代碼中用不到設計模式?Are you kidding me?

總結

寫有技術追求的代碼

 

相關閱讀

編寫代碼的「八榮八恥」- 以用戶易用爲榮,以複雜歧義爲恥

編寫代碼的「八榮八恥」- 以開關上線爲榮,以自信編碼爲恥

編寫代碼的「八榮八恥」(上篇)
關於作者

一線開發十二年,有日本東京和美國硅谷研發經驗。有百餘項技術發明專利,目前任美團點評技術專家。有自己的技術公衆號「編程一生」。如果您在閱讀文章時有什麼疑問或者發現文章的錯誤,歡迎在公衆號裏給我留言。


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章