生活随笔
收集整理的這篇文章主要介紹了
【整洁之道】如何写出更整洁的代码(上)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?
如何寫出更整潔的代碼
?
?
代碼整潔之道不是銀彈,不會立竿見影的帶來收益。
沒有任何犀利的武功招式,只有一些我個人異常推崇的代碼整潔之道的內功心法。它不會直接有效的提高你寫代碼的能力與速度,但是對于程序員的整個職業生涯必然會帶來意想不到的好處。
如果你還是一個在校學生,或者是剛工作沒多久的“菜鳥”,那么很有必要接觸一些這方面的知識的。很顯然,它會幫助你更快的適應企業級開發的要求。
?
1. 為什么需要代碼更整潔?
在考慮代碼整潔的時候,我們需要明確的一個前提是,這里不討論代碼的對錯。
關于什么是整潔的代碼,可能千人千面,但是關于為什么要寫出整潔的代碼是要達成共識的。
如果今天需要出去約會,不管是男生女生一定會將自己梳妝打扮一番吧。如果是周末自己一個人宅在家里呢?可能很多人都是不修邊幅的。這體現了人際交往中很重要的一點:當需要與別人接觸時,會注重自己的儀容。不管咱們的顏值高低,怎么都還是得捯飭一番不是?對于代碼而言,我們應該抱有一樣的要求。如果只是自己寫的好玩的“用后即丟“的代碼,讓它邋遢點其實也沒什么影響。但是如果是在公司與其他人一起開發維護的代碼庫呢?別人會看我們寫的代碼,我們也需要看別人寫的代碼。這樣咱們是不是應該也要把自己的代碼好好打扮一下,畢竟代碼就是咱么的面子啊!
?
想必,對于每一個看過幾本編程方面書籍的人,都看過這么兩個說法:
1) 代碼是寫給人看的。
2) 開發的大部分時間都是在看代碼。
?
我們可能在看別人的代碼的時候,會在心里情不自禁的飆幾句WTF,以宣泄自己對別人難以理解的代碼的煩躁之情。但與此同時,別人也可能在心里F著咱們的代碼。有感于此,是不是覺得自己應該寫出更整潔、更易讀的代碼?讓別人對自己的代碼”無F可說“。
?
我們需要追求整潔的代碼,但是代碼需要整潔的什么程度呢?抱歉,好像這是一個現階段還沒有被量化的問題。在我看來,是需要找到一個平衡點。對于那些之后再也不會用到的代碼,當然就不用花費大力氣去追求極致的整潔。而對于那些日常中需要用到的代碼,我想讓它們再怎么整潔也不為過。
?
2. 怎么寫出整潔的代碼?
以下將是來自于《代碼整潔之道》的方法論。
?
2.1 命名
需要被命名的有:變量、函數、參數、類、包等。
名副其實。選擇體現本意的名稱能讓人更容易理解和修改代碼。都知道類名用名詞性的詞,函數名用動詞性的詞。除了這個最基本的要求之外,名字應該能體現領域概念。使用表意更準確的詞匯,而不要用模棱兩可的詞匯增加代碼模糊度。避免誤導。應避免使用與本意相悖的詞。不要使用不同之處較小的名稱。如?InformationToSet, InformationToSend?,這樣會增加區分它們的時間成本。此外,在使用IDE的快捷補全功能時,可能會使用相似但錯誤的變量名。如果有兩個類型為?String?的變量,一個為?XYZControlllerForEffcientHandlingOfStrings?另一個為?XYZControllerForEffectientStorageOfStrings?,在使用補全功能時,一不小心就可能使用錯誤的變量名而導致錯誤。以同樣的方式拼寫同樣的概念。也就是說,同一個概念如果前后使用不一樣的名字,就會產生誤導的反效果。最應該避免的是使用小寫字母l和大寫字母O作為變量名,它們與數字1和0極難區分。做有意義的區分。不要使用數字系列的命名來區分。對于如下方法簽名 /*該方法簽名需要注釋的幫助來能理解參數 a1, a2 分別表示什么意思*/public static void copyChars(char[] a1, char[] a2);/*方法簽名“自說明”參數的含義*/public static void copyChars(char[] source, char[] destination);
說明一個好的名字,對整個方法可讀性的提供。
只要體現有意義的區分,廢話都是冗余的。對于?getActiveAccount();getActiveAccounts();?這兩個函數很難通過名字就明白它們之間的區別。使用讀得出來的名字。受制于“poor”的英文詞匯,一般很少涉及這點。但毫無疑問,如果在與別人交流代碼的時候,能夠順暢的讀出每個變量、函數名,無疑會使得整個交流更加的高效集中。使用可搜索的名字。使用單字母名稱和數字常量的問題在于,當需要全局搜索某個名字的時候,會出現很多的重復。就好像,如果你在一個文件中全局搜索字母"e",一般會出現很多結果(某個單詞中間包含的字母也會被搜索到),這樣會模糊我們的搜索結果。長名稱勝于短名稱。單字母名稱僅用于短方法中的本地變量。名稱長短應該與其作用域大小相對應。避免使用編碼。不要把類型或作用域信息編碼進名稱里。每個概念對應一個詞。避免將多個單詞用于同一個目的。給每個抽象概念選擇一個詞,并從一而終。例如,在DAO層中查詢數據庫時,很多時候會出現?get, query?等表示查詢的詞,對于這種情況項目組內應該要保持統一。別用雙關語。避免將同一個單詞用于不同的目的。代碼作者應該盡力寫出易于理解的代碼。使用解決方案領域名稱。使用在編程領域里大家都認同并接受的概念。比如,當使用訪問者模式時,在名稱中加上?Visitor?會給熟悉設計模式的更多的信息。使用問題領域的名稱。也就是在名字中使用業務領域的概念來命名。這些概念都是從你的項目正在解決的問題中提煉出來的。在你的日常開發交流中會使用到的概念。添加有意義的語境,不要添加沒有意義的語境。 取名字最難的地方在于需要良好的描技巧和共有的文化背景。一般而言,很難一下就給所有的變量、函數取一個簡單直接、表意準確的名字,所以更應該的是不斷的重構改善它們。隨著對業務知識理解的不斷加深,我們會發現以前起的名字不那么貼切,這個時候應該果斷的對其進行修改。
?
大概就是像給自己家小孩起名字一樣的態度對待每個出現在代碼中的名字。
?
2.2 函數
?
函數是業務邏輯的載體。大部分時候,我們都是在函數中進進出出、上上下下、左左右右。這里涉及到了函數之間的跳轉、函數內的導航。對于函數的編寫,同樣有著一些應該遵守的最佳實踐。
?
短小。函數的第一個規則就是要短小。短小才精悍,濃縮的都是精華。函數短小的好處:對于大部分大腦不是特別發達的人,10個10行的函數可能比一個100行的函數理解起來更容易。如果給每個“小函數”能起一個具有說明性的名字,那么整個流程讀下來會更清晰,而且可以增加代碼自解釋的作用。我曾經重構過一個接近1000行的函數,那絕對是噩夢。短小的函數便于在電腦屏中完整的顯示出來,不需要上下去滾動屏幕。只做一件事。函數應該做好一件事,做好這件事,只做這件事。這個原則(單一職責原則)表述起來很簡單,但實際執行過程中卻困難重重。難點就在于怎么去區分“事”。你覺得“吃飯”是一件事嗎?是的,它可以只是一件事。但是如果你要在更低的層次去細分,你還可以將“吃飯”拆分成“拿碗 -> 打飯 -> 吃飯 -> 洗碗”這些過程。當然,這個例子比較牽強,但還是可以說明問題的。按不同的粒度可以劃分出不同的結果。那到底應該將一件事“細分到多細”呢?需要找到一個平衡。當我們將一件事劃分的越細、粒度越小,那么它的靈活性就越高,復雜度也越高。反之,則靈活性降低、易用性提高。比如,“棉花”就有較高的靈活性,我們可以用它來制作“棉被、被套、布匹”等,相應的它的復雜度也較高,大部分非專業技能人士應該都不可能將一堆“棉花”加工成一塊“布匹”。與“棉花”相比,“布匹”的層次高一些,高層次也導致了它靈活性的降低,“棉花”可以加工成“棉被”,而“布匹”則不應加工成“棉被”了,也就說“布匹”的可能性相比“棉花”更少。此外,從“布匹”加工成一件“衣服”的復雜度比起從“棉花”到一件“衣服”的復雜度有了極大的降低。每個函數一個抽象層級。讓代碼擁有自頂向下的閱讀順序,讓每個函數后面跟著位于下一抽象層級的函數。也就是說,將類中的函數按照抽象層次的順序放置在文件中,這樣的好處在于可以順暢的從上到下的閱讀整個類。函數的順序應該像小說一樣被精心安排。函數中混雜不同抽象層級,往往讓人迷惑。如果和一群你的“領導”(抽象層級高)的人一起吃飯,你會“不自在”。如果和一群你的“下屬”(抽象層級低)的人一起吃飯,你會咋樣呢?哪個領導來表達一下此種情況的心情::-)switch語句。有需要的時候可以利用多態來優化?switch?語句。使用描述性的名稱。與之前在命名中介紹的一樣,我們需要使用具有描述性的名字。不要害怕長名稱。使用描述性的名稱能幫助理清模塊的設計思路,并幫助改進它。命名的方式要保持一致。函數越短小、功能越集中,就越便于取名字。在函數名字中存在 ?and ?時一般體現來了該函數的職責不單一。函數參數。函數參數越少越好。從測試角度來看,參數越多,就越難寫出能確保各種參數組合正常運行的測試用例。輸出參數比輸入參數難以理解。習慣認為信息通過輸入參數傳入函數,通過返回值從函數中輸出。不太希望信息通過輸入參數傳出。輸出參數,就是將一個對象通過參數形式傳入一個函數,然后在函數中對該對象的值進行處理,在該函數外部可以通過該對象的引用使用函數處理后的值,達到函數輸出的效果。標識參數丑陋不堪。不要向函數中傳入布爾值。無副作用。分割指令與詢問。函數要么做什么事,要么回答什么事。函數應該修改某對象的狀態(指令),或是返回該對象有關的信息(詢問),兩者都干常會導致混亂。使用異常替代返回錯誤碼。使用Java的異常系統來處理錯誤,而不是通過自定義的錯誤碼來處理各種異常的情況。??try / catch?代碼塊搞亂了代碼結構,把錯誤流程和正常流程混為一談。最好把 ?try??和 ?catch??代碼塊的主體部分抽離出來,形成函數。使用錯誤碼容易形成依賴磁鐵 dependency magnet,依賴磁鐵類會被很多類導入和使用。當這個類修改時,所有其他依賴它的類都需要重新編譯和部署。別重復自己DRY。重復是軟件中一切邪惡的根源。許多原則與實踐都是為了控制與消除重復。存在不同層次的消除重復。可以將一段語句塊提取為一個函數來消除重復,可以將一些函數提取到父類來消除重復,可以將一個模塊提取為公共服務來消除重復,就像開源屆流行的說法:不要重復制造車輪。?
借助于高級開發工具的幫助,我們可以方便的在函數、類之間跳轉,可以方便在函數中添加任意的參數,但是如果拋開工具的輔助,那么曾經沒有在意的“細節”就會形成難以清除的“污垢”,讓人難受。當然,我們完全沒有必要拋棄高級的開發工具,但是如果能在日常工作中就注意并保持代碼中的每一個細微之處的整潔,難道不是一件很有“工匠精神”的事情嗎?
大師級程序員把系統當作故事來講,而不是當作程序來寫。
?
2.3 注釋
?
注釋就是函數、類的一種輔助說明,就是怕別人不懂自己寫的代碼的意圖,就加上一段說明性的文字。我經歷過兩個極端:一個是完全不寫注釋,另一個是每個函數、類都需要寫上注釋。
我個人更認同的觀點是:如果我們擅長于用語言來表達意圖,那么就不需要注釋。
關于注釋特別要注意的一點是:當代碼在變動的時候,注釋并不總是跟著變動的。這樣會導致注釋常常會與它所描述的代碼不同步,并越來越不準確,甚至可能會起誤導的作用。
?
注釋不能美化糟糕的代碼。少量而準確是注釋比大量而毫無意義的注釋更有用。大量無用的注釋會打亂閱讀代碼時的思路,也會增加滾動屏幕的成本。用代碼來闡述。盡量使用代碼來闡述它的意圖。這需要給函數、參數起恰當的名字,函數層次清晰、邏輯明確。好注釋。法律信息。根據公司要求而定。提供信息的注釋。對意圖的解釋。注釋可以提供某個決定背后的故事。闡釋。注釋可以解釋某些難懂的參數或返回值的意義。警示。TODO注釋。TODO大多都是程序員的自我安慰、自欺欺人。放大。可以用來放大某種不合理之物的重要性。公共API中的Javadoc壞注釋。大多數注釋都屬于此列。喃喃自語。如果決定寫注釋,那就花點時間確保寫出最好的注釋。多余的注釋。典型的就是對Bean類中的每個參數都寫上注釋,比如?name, length?等可以通過名字就判斷意義的字段。誤導性的注釋。這個最可怕。循規蹈矩式的注釋。很多IDE都會自動生成函數的注釋,其中可能會包含?@param, @return?等信息的說明,大多數時候可能就是放了一個IDE生成的模板在那里,并沒有任何實質性的內容。日志式注釋。在每次修改時,在模塊開始處添加一條注釋,注明此次的修改變動。這個工作應該是Git等版本控制系統該做的事。廢話注釋。毫無意義的注釋。能用函數或變量時就別用注釋。體現了要使名稱更具表達性,能表達它自身的意圖。位置標記。#######################################之類的。括號后面的注釋。通過注釋來表明這個括號與哪個括號是一對的。歸屬與署名。同樣應該是代碼控制系統應該做的事。注釋掉的代碼。非本地信息。信息過多。不明確的聯系。?
注釋應該起著輔助的作用,而不應該“喧賓奪主”。好的注釋在于提供有用信息、或者方便程序員獲取有用信息。而壞的信息在于冗余,甚至是錯誤,一般它們對提高對系統的認識不會提供任何幫助,反而會分散注意力。
?
2.4 格式
?
好的團隊,應該有一份屬于團隊的編碼規范。這里面需要定義代碼的格式問題,目的是為了保證團隊的人輸出的代碼就像是一個人寫的。這樣的好處,1)在于減少團隊間相互適應不同格式的成本,2)在于提高團隊對外輸出的影響力。
代碼的格式關乎溝通。下面是一些格式的最佳實踐:
垂直格式。向報紙學習。源文件的頂部應該給出高層次概念和算法,細節應該往下逐次展開。概念間垂直方向上的區隔。每個空白行都應該是一條線索,標識出新的獨立概念。垂直方向上的靠近。相互靠近的代碼應該是緊密相關的代碼。垂直距離。變量聲明。應該盡可能的靠近其使用的位置。實體變量。應該在類的頂部聲明。相關函數。調用者應該盡可能的放在被調用者的上面。概念相關。概念間的相關性越強,彼此之間的距離就應該越短。水平格式。水平方向上的區隔與靠近。在操作符周圍加上空格字符,可以達到強調的目的。不在函數名和左圓括號之間家空格。函數參數之間用空格隔開。縮進。縮進有助于理清代碼的層次結構。 // 風格1 if (condition) {statement;}// 風格2if (condition){statement;}
關于下面的兩個?if?語句塊,你是哪種風格?我是風格1,曾經被人當面說風格1怎么怎么不好,應該使用風格2,什么什么的!氣氛一度十分尷尬。
其實,這也沒什么大驚小怪的,每個程序員都會有自己喜歡的風格。但是,在團隊中,那就應該形成一致的團隊風格。
3. 總結
上面介紹了關于命名、函數、注釋、格式相關的一些概念性知識點,代碼整潔之道不是銀彈,它只是幫助我們做好代碼層面的小事。如果能夠堅持下去,那今天的付出可能就是一只蝴蝶開始扇動了翅膀,可能在未來的某一天帶來意想不到的巨大收貨。拋開這些功利主義的想法,純粹的想要成為一個有著“工匠精神”的程序員也是一件很牛逼的事吧!
轉載于:https://www.cnblogs.com/liujiong/p/7471515.html
總結
以上是生活随笔為你收集整理的【整洁之道】如何写出更整洁的代码(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。