我在本文中要談的不是編碼的技術實現,我所關注的是關於編碼的風格的問題。我在編寫了e速的編碼規范之後,產生了要寫一些關於程序編碼風格的念頭;因此,就有了以下的文章,這些僅僅是本人的想法,可能在文章中還有一些未盡如人意的地方,所以肯請大家能夠給與諒解。
很多人在談到編碼的藝術時,總會說我的程序怎麼怎麼的厲害,功能多麼的強大,好像什麼事情都能完成一樣;但是去運行他的程序,bug不斷;連他自己都不知道錯在了什麼地方。打開他的程序一看,代碼寫的凌亂不堪;命名上不規范,為了偷懶和簡便有些命名干脆就用一個字母或者其他的簡單符號代替,甚至於有些代碼連他自己也搞不清是干什麼了,更不要說怎樣讓別人去修改了….本人編碼也快4個年頭了,像上述的例子遇見過不少,整個程序改動起來實在是頭疼。
的確,一件好的藝術品不在於其功能是多麼的完善,而在於別人欣賞起來是否有它內在的美和是否很容易就把它從雜貨堆裡一眼就能辨認出來;畢竟它是藝術品而非日用品。我們寫程序也是同樣,如果程序中的格式很隨意,例如對數組做循環,一會兒采用下標變量從下到上的方式,一會兒又用從上到下的方式;對字符串一會兒用s t r c p y做復制,一會兒又用f o r循環做復制;等等。這些變化就會使人很難看清實際上到底是怎麼回事了。
寫好一個程序,當然需要使它符合語法規則、修正其中的錯誤和使它運行得足夠快,但是實際應該做的遠比這多得多。程序不僅需要給計算機讀,也要給程序員讀。一個寫得好的程序比那些寫得差的程序更容易讀、更容易修改。經過了如何寫好程序的訓練,生產的代碼更可能是正確的。
注釋:注釋是幫助程序讀者的一種手段。但是,如果在注釋中只說明代碼本身已經講明的事情,或者與代碼矛盾,或是以精心編排的形式干擾讀者,那麼它們就是幫了倒忙。最好的注釋是簡潔地點明程序的突出特征,或是提供一種概觀,幫助別人理解程序。在標注注釋的同時,應該注意下面的問題:
不要大談明顯的東西。注釋不要去說明明白白的事,比如i + +能夠將i值加1等等。注釋應該提供那些不能一下子從代碼中看到的東西,或者把那些散布在許多代碼裡的信息收集到一起。當某些難以捉摸的事情出現時,注釋可以幫助澄清情況。如果操作本身非常明了,重復談論它們就是畫蛇添足了;給函數和全局數據加注釋。注釋當然可以有價值。對於函數、全局變量、常數定義、結構和類的域等,以及任何其他加上簡短說明就能夠幫助理解的內容,我們都應該為之提供注釋。全局變量常被分散使用在整個程序中的各個地方,寫一個注釋可以幫人記住它的意義,也可以作為參考。放在每個函數前面的注釋可以成為幫人讀懂程序的台階。如果函數代碼不太長,在這裡寫一行注釋就足夠了。有些代碼原本非常復雜,可能是因為算法本身很復雜,或者是因為數據結構非常復雜。在這些情況下,用一段注釋指明有關文獻對讀者也很有幫助。此外,說明做出某種決定的理由也很有價值。
職業程序員也常被要求注釋他們的所有代碼。但是,應該看到,盲目遵守這些規則的結果卻可能是丟掉了注釋的真谛。注釋是一種工具,它的作用就是幫助讀者理解程序中的某些部分,而這些部分的意義不容易通過代碼本身直接看到。我們應該盡可能地把代碼寫得容易理解。在這方面你做得越好,需要寫的注釋就越少。好的代碼需要的注釋遠遠少於差的代碼。
編碼的風格:全局變量應該采用具有描述意義的名字,局部變量用短名字。函數采用動作性的名字。給神秘的數起個名字。現實中存在許多命名約定或者本地習慣。常見的比如:指針采用以p結尾的變量名,例如n o d e p;全局變量用大寫開頭的變量名,例如G l o b a l;常量用完全由大寫字母拼寫的變量名,如C O N S T A N T S等。命名約定能使自己的代碼更容易理解,對別人寫的代碼也是一樣。這些約定也使人在寫代碼時更容易決定事物的命名。對於長的程序,選擇那些好的、具有說明性的、系統化的名字就更加重要。
保持一致性。要准確。以縮行形式顯示程序結構。使用表達式的自然形式。利用括號排除歧義。分解復雜的表達式。要清晰。當心副作用。使用一致的縮行和加括號風格。為了一致性,使用習慣用法。用else-if 處理多路選擇。避免使用函數宏。給宏的體和參數都加上括號。這些都是很瑣碎的事情,但卻又是非常有價值的,就像保持書桌整潔能使你容易找到東西一樣。與你的書桌不同的是,你的程序代碼很可能還會被別人使用。
用縮行顯示程序的結構。采用一種一致的縮行風格,是使程序呈現出結構清晰的最省力的方法。
用加括號的方式排除二義性。括號表示分組,即使有時並不必要,加了括號也可能把意圖表示得更清楚。在混合使用互相無關的運算符時,多寫幾個括號是個好主意。C語言以及與之相關的語言存在很險惡的優先級問題,在這裡很容易犯錯誤。例如,由於邏輯運算符的約束力比賦值運算符強,在大部分混合使用它們的表達式中,括號都是必需的。
利用語言去計算對象的大小。不要大談明顯的東西。給函數和全局數據加注釋。不要注釋不好的代碼,應該重寫。不要與代碼矛盾。澄清情況,不要添亂。
界面的風格:隱蔽實現的細節。不要在用戶背後搞小動作。在各處都用同樣方式做同樣的事。釋放資源與分配資源應該在同一層次進行。在低層檢查錯誤,在高層處理。只把異常用在異常的情況。
寫良好的代碼更容易閱讀和理解,幾乎可以保證其中的錯誤更少。進一步說,它們通常比那些馬馬虎虎地堆起來的、沒有仔細推敲過的代碼更短小。在這個拼命要把代碼送出門、去趕上最後期限的時代,人們很容易把風格丟在一旁,讓將來去管它們吧。但是,這很可能是一個代價非常昂貴的決定。上面的一些陳述性的言語充分的說明了,如果對好風格問題重視不夠,程序中哪些方面可能出毛病。草率的代碼是很壞的代碼,它不僅難看、難讀,而且經常崩潰。好風格應該成為一種習慣。如果你在開始寫代碼時就關心風格問題,如果你花時間去審視和改進它,你將會逐漸養成一種好的編程習慣。一旦這種習慣變成自動的東西,你的潛意識就會幫你照料許多細節問題,甚至你在工作壓力下寫出的代碼也會更好。