讀《編寫可讀代碼的藝術》

《編寫可讀代碼的藝術》是與Clean Code相似的書,提供改善“丑陋”代碼的技巧。本書193頁,共16章內容。


圖書封面

本書分為四個部分:

  • 表面層次的改進-命名/注釋以及審美
  • 簡化循環(huán)和邏輯
  • 重新組織代碼
  • 精選話題

關鍵思想:代碼應當易于理解

可讀性基本定律:代碼的寫法應當使別人理解他所需的時間最小化。

1 表面層次的改進

包括好的名字,好的注釋,還有好的格式

1.1 把信息裝進名字里

1.1.1 選擇專業(yè)的詞

反例: 函數名 GetPage(url)
正例: FetchPage()、DownloadPage()
反例: class BinaryTree的方法Size() VS
正例:Hight() NumberNodes(),MemoryBytes()
反例: class Thread的方法Stop()
正例: Kill() Pause(),Resume()

1.1.2 避免泛泛的名字

關鍵思想:清新和準確比裝可愛好
迭代器變量,應該有明確指向

選擇更有表現力的詞

避免tmp和retcode泛泛的名字
retcode建議:retcode沒有包含更新信息。描述該變量的值的名字代替它。

retcode改為sum_squares

tmp建議:tmp這個名字只應用于短期存在且臨時性為其主要存在因素的變量。
tmp改為user_info

如果需要使用tmp,也需要指明tmp_file,或者tmp_data.
迭代器變量,應該有明確指向
i,j,k改為clubls_i/ci,members_i/mi,users_i/ui

1.1.3 用具體的名字代替抽象的名字

名字更具體而不是抽象

反例: 函數ServerCanStart:檢測服務是否可以監(jiān)聽某個端口
正例: CanListenOnPort()
DISALLOW_COPY_AND_ASSIGN更好

1.1.4 給名字附帶更多的信息

1、一個變量名就是一個小小的注釋
反例:string id ; //example:"0x128a232b"
正例:string hex_id;
2、變量名帶單位

帶單位的值

3、附帶額外信息
附帶額外信息

1.1.5 決定名字的長度

名字隱含約束就是不能太長。

  • 1、在小的作用域可以使用短名字。
  • 2、輸入長名字不再是問題?!緝戎醚a全功能】
  • 3、首字母縮寫詞和縮寫
    經驗原則:團隊新成員可以理解這個名字含義。
  • 4、丟掉沒用的詞
    反例 :ConvertToString()
    正例: ToString()

1.1.6 利用名字的格式表達含義

利用下劃線,大小寫或者連字符可以裝載更多含義。 在google的C++代碼規(guī)范中:

  • kMaxOpenFiles表示常量,MAX_OPEN_FILES表示宏
  • state是局部變量,state_是成員變量

1.1.7 小結

    1. 使用專業(yè)的單詞
    1. 避免空泛的名字
    1. 使用具體的名字描述細致的事物
    1. 給名字帶上重要的細節(jié)
    1. 給作用域更大的名字采用更長的名字
    1. 有目的使用大小寫和下劃線

1.2 不起誤解的名字

關鍵思想:要多問自己幾遍,“這個名字會被別人誤解成其他含義嗎?“要仔細審視這個名字

反例: Filter("years <= 2010") 挑出還是減掉?
反例: Clip(text,length)是截斷到,還是去掉?
正例:使用min和max表示極限
正例:使用first和last表示包含的范圍
正例:使用begin和end表示包含/排除的范圍

布爾型命名
正例:加上is,should,has,can,use變得含義更明確
正例:避免使用反義名詞:bool disable_ssl=false;

1.3 審美

布局的三個原則:

  1. 使用一致的布局,讓讀者很快習慣這種風格。
  2. 讓相似代碼看上去相似。
  3. 相關的代碼分組,形成代碼塊。
審美
  • 1、使用【從審美角度】讓人愉悅的代碼更容易
  • 2、安排換行是節(jié)奏保持一致和緊湊
  • 3、用方法規(guī)整不一致的東西
    反例

    正例
  • 4、在需要時,使用列對齊
    使用列對齊
  • 5、選擇有意義的順序,并保持一致
  • 6、把申明按照塊組織起來
  • 7、把代碼分成段落
  • 8、一致性比”正確“風格更重要

1.4 注釋

關鍵思想:注釋的目的就是盡量幫讀者和作者了解一樣多

注釋

1、什么不需要注釋

  • 不要為那些可以從代碼快速推斷的事實寫注釋
  • 不要為了注釋而注釋
  • 不要為不好的名字加注釋,應該把名字改好

2、記錄你的思想

  • 加入“導演評論”
  • 為代碼的瑕疵做注釋(//TODO:)


    流行的標注
  • 給常量加注釋
    常量本身不需要解釋,記錄決定這個常量取值的想法,便于后續(xù)優(yōu)化。
    3、站在讀者的角度
  • 意料之中的提問
  • 公布可能的陷阱
  • 全局性的注釋
    高級別的注釋信息,包括文件,類,模塊如何組織工作的。
  • 用注釋來總結代碼塊,防止迷失細節(jié)

1.5 寫出言簡意駭的注釋

言簡意駭

關鍵思想:注釋應該有很高的信息/空間率

  • 1、讓注釋保持緊湊
    反例

    正例
  • 2、避免使用不明確的代詞(it,this)
  • 3、潤色粗糙的句子
  • 4、精確描述函數的行為
    反例

    正例
  • 5、用輸入/輸出的例子來說明情況
  • 6、申明代碼的意圖
    【4,5,6用單元測試代替注釋更妥】
  • 7、具名函數參數的注釋
    使用嵌入式的注釋,例如Function(/arg=/...)來解釋函數的參數。
  • 8、采用信息量高的詞,使得注釋簡潔

2 簡化循環(huán)和邏輯

2.1 把控制流變得易懂

關鍵思想:把條件,循環(huán)以及其它對控制流的改變做的越“自然”越好。運用一種方式使得讀者不用停下來重讀你的代碼

  • 1、條件語句中參數順序
    if(length<=10) 還是 if(10>=length)?
    while(bytes_expected < bytes_recieved) 還是 while(bytes_expected > bytes_recieved) ?
    指導原則【和語言的語法一直】
比較的左側 比較的右側
被詢問的表達式,它的值傾向于不斷變化 用來作比較的表達式,它的值傾向于常量

if(object == null) 還是 if(null == object)?

  • 2、if/else語句塊的順序
    if條件選擇標準:
    先處理正邏輯而不是負邏輯
    先處理簡單的
    先處理有趣或者可疑的

  • 3、三目運算符
    關鍵思想:相對于追求代碼最小行,一個更好的方式就是最小化人們理解他所需的時間
    建議:默認情況下都if/else, 三目表達式只在最簡單的情況下使用。

  • 4、避免do/while循環(huán)
    使用while/for,而不是for/while, 把條件【危險】放到首先看到地方。

    提前告警

  • 5、從函數中提前返回
    使用衛(wèi)語句,提前返回?!締纬隹凇?/p>

  • 6、臭名昭著的goto

  • 7、最小化嵌套
    思維棧-可能導致理解困難。
    通過提前返回減少嵌套
    減少循環(huán)內的嵌套

2.2 拆分超長的表達式

1、解釋變量
引入變量來解釋子表達式。
2、最小化嵌套
用一個變量來代替一段代碼。
3、使用德摩根定理

分別取反,轉換與或

4、濫用短路原理
濫用短路

5、使用德摩根定理
6、復雜表達式,提取函數,提前返回

2.3 變量和可讀性

1、減少變量
沒有價值的變量
減少中間結果
減少控制變量

2、變小變量的作用域
讓你的變量對盡量少的代碼行可見
C++ if的作用域

差異?

3、只寫一次的變量更好
操作一個變量的地方越多,越難確定他的值。

3 重新組織代碼


3.1 抽取不相干的子問題

抽取不相干的子問題,建議:積極地發(fā)現并抽取不相干的子邏輯。
我們指:

  • 看到某個函數或者代碼塊,問自己:這個代碼的高層次目標是什么?
  • 對于每一行代碼,問:他是直接為了目標而工作嗎?這段代碼高層次的目標是什么?
  • 如果足夠的行數在解決不相干的子問題,抽取代碼到獨立的函數中。
  • 抽取純工具代碼
  • 其他多用途的代碼
  • 創(chuàng)建大量通用代碼
  • 項目專有代碼
  • 簡化已有接口
  • 按需重塑接口
  • 避免過猶不及
    小結:把一般代碼和專有代碼分離。

3.2 一次只做一件事

整理碎片
  • 1、任務可以很小
  • 2、從對象中抽取值

3.3 把想法變成代碼

愛因斯坦:如果你不能把一件事情解釋給你祖母聽的話說明你還沒有真正理解他

  • 1、像對著同事一樣,用自然語言描述代碼要做什么。
  • 2、注意描述中所用的關鍵詞和短語。
  • 3、寫出與描述匹配的代碼

3.4 少寫代碼

關鍵思想:最好讀的代碼就是沒有代碼。

  • 1別費神不需要的功能【過度設計】
  • 2質疑和拆分需求 【故事拆分】
  • 3保持小代碼庫
    利用工具減少重復代碼,并刪除無用代碼
代碼庫大小和維護難度
  • 4、熟悉你周邊的庫
    中肯建議:每隔一段時間,花15分鐘來閱讀標準庫的所有函數/模塊/類型的名字。

冒險、興奮-絕地武士追求的并不是這些。--尤達大師

4 精選話題

4.1 測試與可讀性

  • 1、使閱讀易于閱讀和理解
    測試應該具備可讀性,以便其他程序員可以舒服的改變和增加用例。
    對使用者隱去不重要的細節(jié),以便重要的細節(jié)更突出。
  • 2、創(chuàng)建最小的測試申明
    測試都可以提煉成:對于這樣的輸入/情形,期望這樣的行為/輸出.【BDD的描述更好】
  • 3、實現定制的“微語言”(DSL)
  • 4、讓錯誤消息具備可讀性
  • 5、 手工打造錯誤消息
  • 6、 測試函數命名
    規(guī)則:Test_<Function>_<Situation>
  • 7、TDD
    易測試產生更好的代碼。
可測試性差的代碼帶來的設計問題

可測試性好的代碼帶來優(yōu)秀設計
  • 8、走的太遠
    主要有:
    為了可測試,犧牲可讀性
    著迷100%可測試性
    測試成為開發(fā)的阻礙

4.2 設計并改進

通過一個例子來說明:演進式改進的過程。

小結

本書2018讀的第一本書,大概花了10個多小時。本書在代碼可讀性的命名,布局,注釋,循環(huán)控制,抽取函數,表達式,可測試性方面都有很不錯的建議,值得內部分享和學習。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容