書本列出了一些撰寫code使得code更有可讀性的例子,其實如果從RUP的角度出發,有些事情會自然發生,就好比學過OOP很容易在設計DB就會自動符合一階正規劃(每個entity需要包含primary key),而不用再正規劃
packing information into names (讓變數名稱包含資訊)
choose specific words(使用明確的字)
使用有明確的動詞跟名詞,比方使用fetchPage()或者downloadPage()取代getPage()
動詞上可以更明確一些,作者列出了若干個例子
- send=>deliver, dispatch, announce, distribute, route
- find=>search, extract, locate, recover
- start=>launch, create, begin, open
- make=>create, set up, build, generate, compose, add, new
avoid generic names like tmp and retval(避免太過泛稱的名詞)
避免太泛稱的名詞,比方tmp跟retval。loop裡面常用的i, j, k等等index,如果可以,也建議給予適當的名稱
prefer concrete names over abstract names(避免太過抽象的名稱)
儘量讓變數名稱貼合他使用的場合,比方run_locally表示local test的flag就不太合適,不如使用use_local_database
attaching extra information to a name(增加額外有意義的資訊)
讓名稱包含其他有意義的資訊,比方說string id與string hex_id,後者表明了id由hex組成
又或者包含單位,如int time與int time_seconds,後者表明了時間以秒為單位
又或者html與html_utf8,後者表明了encoding的方式
how long should a name be?(名稱會太長嗎?)
作者認為在有工具的幫助下,打long name不是問題;另外如果有效範圍很短的變數使用簡單的名稱也是可以的,如map m;
use name formatting to convey meaning
格式化變數的清晰程度,利用底線、破折號以及大小寫( _ , - , CapitalsAnd)來區分名稱
names that can’t be misconstrued (正確的建構變數名稱)
example: filter()
filter("year >=200")是include?還是exclude?本身名稱就具備模糊空間,不好
example: clip(text, length)
是剪下length長度的文字呢?還是將文字刪除為最長長度length?如果是後者應該使用Trancate(text,length)比較好
prefer min and max for (inclusive) limits(適當的範圍選擇)
prefer first and last for inclusive ranges
prefer begin and end for inclusive/exclusive ranges
作者建議使用數學上,首尾包含[1,100]表示1~100,儘量不要使用[1,100)表示1~99,然則STL的begin(), end()則是[1,100)
naming booleans(為boolean變數命名)
bool read_passwd不是一個好表示法,因為不知道是否是表示已經讀取或者未讀取,使用如disable_passwd或者use_ssl會是一個比較好的名詞
matching expectations of users(使用者非預期中的成本)
例如getMean()其實隱含了計算成本,可是使用者卻不知道,使用computeMean()或許會更好,或者STL中的size()會隨著容器中元素個數改變,有時會在回圈中引發錯誤
example: evaluating multiple name candidates
aesthetics (美學)
why do aesthetics matter?(為何美學重要?)
readable code的排版是重要的,一個格式很糟糕的code很難讀
rearrange line breaks to be consistent and compact (重新分配換行以及保持註解簡潔跟一致)
直接看圖,上者是好的,下者是不好的
use methods to clean up irregularity (將不規則的不分用方法加以包裹)
將複雜且不規則的方法加以包裹,使動作看起來一致
use column alignment when helpful (行對齊是有幫助的)
直接看圖
pick a meaningful order, and use it consistently (保持有意義的次序)
保持對齊,比方assign屬性的時候
organize declarations into blocks (組織適當宣告)
將相似或者功能相近的宣告集中成一個block
break code into “paragraphs” (將code分段)
將一串code依照功能分段落,並且加上適當的註解
personal style versus consistency (個人風格或者一致)
風格要一致比較重要
knowing what to comment (知道哪些東西該註解)
what not to comment (怎樣的註解不該寫)
不要寫出dummy的資訊,例如這是一個"汽車類別"這樣的註解。也不要直接註解重複註解變數名稱,註解不該用來修飾不好的變數或者方法的名稱,遇到這種狀況,請直接改掉他
recording your thoughts (記錄你的想法)
將思路寫下,也可以記錄你的修改過程,常數(constant)往往也是需要解釋為何這樣設計的
put yourself in the reader’s shoes (多替他人想想)
不要在註解內寫下問句,將可能遇到的問題寫下來。使用高階或者宏觀的方式寫下的註解也有助於新手了結程式碼
final thoughts—getting over writer’s block (克服寫作恐懼)
有些人認為寫好的註解很花時間,對症下藥就是~趕緊寫註解,然後只要避免重複的註解。過程: 想到就寫=>以後重讀(需要改進嗎?) =>改進
making comments precise and compact (保持註解正確跟簡潔)
keep comments compact (保持註解簡潔)
avoid ambiguous pronouns (避免有疑慮的名詞)
polish sloppy sentences (避免註解過度肥大)
describe function behavior precisely (正確描述function的行為)
例如CountLines(),應該寫明是使用\n當計算單位?還是\n\r當計算單位?還是?
use input/output examples that illustrate corner cases (良好的舉例,顯示輸入輸出該注意的事項)
state the intent of your code (解釋你的意圖)
解釋你的意圖,不是解釋code的運作方式,code的運作應該是code本身顯示的
“named function parameter” comments (定義呼叫參數的意義)
當使用Connect(10,false),並無法得知參數的意義
在python可以寫
Connect(timeout = 10, use_encryption = False)
在C++則可以用
Connect(/* timeout_ms = */ 10, /* use_encryption = */ false);
use information-dense words (使用簡潔且資訊含量豐富的字眼)
=======================個人感想=======================
這個話題可能是永遠的話題,好比說,大家都知道註解很重要,但是絕大多數pogrammer的不寫註解。大多的人知道測試很重要,但是他們寧願相信自己的腦袋跟錯誤處理函數。大多人知道好的readable code風格很重要,但是pogrammer會持續使用自己特有的風格
然則這個沒有絕對的對錯,不過理解那些事情該做,才能夠適當的"客製化",好比現實專案大多不依照軟體工程來執行,但是理解軟體工程絕對對專案執行有幫助。好比如果專案很小,可以將需求使用拍照的方式記錄下來就好,不用在寫複雜的格式。在寫code上面也是一樣,有人推崇的方式,是code應該跟註解一樣,每一個function call本身就應該包含它的意義,不應該再添加太多的註解
此外,很多方法已經被研發出來,但是相對應的工具還不是那麼方便,最有名以及全面的工具應該是version control跟refactoring工具,version control不管是cvs, svn or git都是一個良好的工具,比自行壓縮,然後在檔案名稱上面附加上日期好很多,refactoring則是一種瑣碎的過程,如果IDE沒有配合的工具,我想光rename variable/method這件事情就很容易引入更多的bug
最後要表達的是,生產力以及品質之間有關連,但卻又是分開的。有些人會覺得很詭異,舉例來說,使用OOP或者Design Pattern可以提升生產力嗎?答案是否定的,工程是不會因為OOP或者Design Pattern產生新的功能出來,也就是對於用戶,使用lisp(not OOP)或者C++(OOP)是沒有分別的,但是正確使用兩者則可以提升開發品質,間接的會影響生產力,更容易維護的code是有幫助的,但幫助不是增加新功能
在換句話說,可以分為對內需求以及對外需求,對內(專案團隊),如何專案管理、如何測試、如何提升可維護性是很重要。但是對外(客戶),則是團隊交付了多少功能以及花費還有時間才是他們所期待的。這兩者不直接相關,但是兩者又互相影響