1. 程式人生 > >《程式碼整潔之道》讀書筆記

《程式碼整潔之道》讀書筆記

  最初我喜歡這本書可能是因為非技術方面的原因,這本書中有很多我喜歡的插圖。這本書的第一章的第一句話是這樣說的:讀這本書通常有兩個原因:1. 你是一名程式設計師。2. 你想成為更好的程式設計師。我們需要更好的程式設計師。    這本書的每一章都可以總結出一句話,其實每章開始的插圖就是這句話的濃縮。      本書的第一章是關於什麼是整潔程式碼的討論,引用了Bjarne Stroustrup(C++之父)、Grady Booch(UML的創始人之一)等人當然也Bob大叔(本書的作者Robert Martin)自己對整潔程式碼的理解。順便說一下,上面那張圖上的程式碼應該是保齡球計分程式(不知道大家看清楚了沒有,哈哈)。

    不管是現實世界還是軟體專案中,命名都是一件讓人頭疼的事情,給小孩起過名字的就知道,你希望把你對孩子的期望包含在這個名字中,你又希望這個名字讀起來要好聽,至少不至於將來成為別人的笑柄(比如龐光大、魏升京這樣的名字),可能你還要考慮族譜班輩的排列等等。軟體專案中的命名情況會更加複雜,簡單的說命名的原則是"見名知意",當然你還需要用各種方式防範命名衝突的問題,不同的程式語言也有自己不成文的像契約一樣的命名規則和方式(例如匈牙利命名法),這些可能都是需要考慮的事情。我個人並不喜歡匈牙利命名法,加上一個型別字首的感覺就是永遠和這個東西繫結到一起了,就如同用C語言的malloc函式分配記憶體建立一個能放100000個元素的陣列,你願意用下面哪種寫法呢?記住:好的名字相當於為程式碼寫了一段有用的註釋。

    int* myArray = NULL;
    /* 寫法1 */
    myArray = malloc(100000 * sizeof(int));
    /* 寫法2 */
    myArray = malloc(100000 * sizeof *myArray);

    第三章講的是函式,說了這麼一句話:"Function should do one thing. They should do it well. They should do it only. "(函式只應該做一件事情,把一件事情做好,而且只由它來做這一件事情),聽起來很簡單的一句話但是要踐行這條原則卻並不容易,所以我們的程式碼中才會有很多的壞味道(請參考《重構:改善既有程式碼的設計》一書的第三章)。事實上,上升一個層次,我們在設計類的時候也應該如此,這是面向物件設計原則中說的單一職責原則(SRP),當我們的程式碼中出現了冗長的方法或者巨大的類的時候,我們就應該依據職責來對其進行拆分,這樣程式的結構才會趨於合理,最終達到"高內聚"的目標。當然,這一章裡面還提到很多理念,包括:Command Query Separation(一個方法要麼執行某種命令,要麼返回查詢資料)、DRY(不要重複自己)、Prefer Exceptions to Returning Error Codes(異常優於返回錯誤碼)等。

    第四章講的是註釋,有一句話我很喜歡,說的是:"Comments Do Not Make Up for Bad Code."(註釋不是對劣質程式碼的補救)。事實上好的程式碼即便沒有註釋也擁有良好的可讀性,但恰當的註釋會讓程式碼變得更可讀、可維護性更高。

    第五章講的是程式碼風格。現代IDE(整合開發環境)幾乎都有程式碼格式化程式碼的功能,你只需要設定好你使用的程式碼風格就可以了,其實不只是IDE,很多高階的文字編輯工具也能夠按照指定的風格格式化你的程式碼。用什麼樣的程式碼風格不是關鍵,關鍵是整個專案組的成員應當使用相同的程式碼風格,讓多個人編寫的程式碼看起來像一個人書寫的。我個在程式碼中使用的括號風格是1TBS(One True Bracing Style,也叫做K&R風格,這種風格是Kernighan和Ritchie兩位老師在"The C Programming Language"一書中使用的程式碼風格),當然Allman風格(FreeBSD系統的作者之一使用的程式碼風格)也是很好的選擇。

    第六章討論的是物件和資料結構,讀完之後的感覺是雖然我們天天都嚷著吼著要面向物件程式設計,但是很多時候我們都使用了類的退化結構,包括我們開發時經常使用的失血模型和貧血模型(事務指令碼模式)都和麵向物件的設計理念相違背。我得承認在讀這一章的時候我可能沒有抓住作者的觀點。

    第七章對錯誤處理(異常)的講解非常精彩的,整潔的程式碼中對錯誤的處理應當是被分離的關注點(不要跟正常的業務邏輯混雜在一起),而面向物件中的異常機制就是一種在不打亂原有業務邏輯的前提下處理掉程式在執行時發生的不正常狀況的手段。這章有兩個觀點我特別欣賞,一是"Use Unchecked Exceptions"(非受檢異常允許你在適當的地方處理異常,而適當的地方就是異常影響程式碼執行邏輯的地方,不管做哪種型別的應用,都應該儘可能向用戶隱藏異常的發生,除非發生了不可挽救的狀況,這才是符合最小驚訝原則的設計);二是"Don’t Return Null"(如果一個方法在出狀況的時候返回null,那麼呼叫者都要通過頻繁的檢查返回值來判定是否出錯,一旦忘了這件事情就有可能出錯,既然null是一種異常狀況,那麼用丟擲異常的方式來代替返回null明顯是更好的做法)。

    第八章的內容對實際開發有重要的指導意義,因為我們的專案中不可避免的要使用第三方工具,因此我們需要將這些東西整潔的納入到我們的系統中,這時就需要考慮系統邊界的問題。有的時候我們會千辛萬苦的發現系統中的一些bug是來源於第三方工具的,當然我們基本上沒有時間去重頭學習和研究第三方工具或者自己寫程式碼來實現第三方工具的功能,但是我們至少應該先對第三方工具進行測試。我在以前的專案中,即使用Apache提供的那些著名的第三方工具,我的做法也是先寫測試程式碼對這些工具的可用性和有效性進行證實,當然有的時候可能是過於謹慎了,但這種習慣和做法本身是很好的。在這種場景下,介面卡模式是非常好的設計,它不僅能將不相容的介面改寫成相容的介面,還能夠對通過對第三方工具重新封裝來避免邊界的變化對系統的影響。

    第九章的內容是單元測試。Bob大叔是TDD(測試驅動開發)的倡導者,這一章講的是如何編寫整潔的測試,Bob大叔的答案是FIRST規則(Fast、Independent、Repeatable、Self-Validating、Timely)。

    第十章介紹類的設計,最重要的還是SRP(單一職責原則)。

    第十一章是關於系統設計的內容,開篇引用了微軟首席技術官Ray Ozzie的一句話:"Complexity kills. It sucks the life out of developers, it makes products difficult to plan, build and test."(複雜要人命,它消磨開發者的生命,讓產品難於規劃、構建和測試)。這章對於希望瞭解面向切面程式設計的開發者是極好的,包括了對依賴注入、代理模式以及AOP的探討。

    第十二章探討了系統的迭代式演進。

    第十三章對併發程式設計的討論非常經常,很多開發者都畏懼併發程式設計,也有的開發者迷信多執行緒可以解決所有的併發問題,如果你是這兩類人之一,本章會教給你真正的併發程式設計。這一章的內容我重新整理了一篇文章,已經發布在CSDN的部落格上,名為《關於Java併發程式設計的總結和思考》

    第十四章是一個精彩的案例用來講解對程式碼的持續改進,你可以自己好好閱讀一次。第十五章到第十七章說的都是重構,相當精彩。如果你還沒有來得及讀《重構:改善既有程式碼的設計》一書,你可以先讀讀這幾張中探討的程式碼的壞味道及其改進方案。