看了neora的大作
寫給我的團隊
,頗受啟發,在這里我借花獻佛,也寫一些短文給團隊的新老成員做些總結。照搬的地方neora老大表罵我
?
<!----><!----> 各位尊敬的同事
你們好!我知道大家都很忙,忙的連寫注釋和文檔的時間都沒有,更不要說做總結了。所以我就寫一些短文,幫助大家總結一下。正如大家所知道的,我們的團隊每天所面對的問題有很多——需求、測試、編碼、變更、架構 …… ,好吧,就讓我們從編碼開始吧。
為什么要編碼?
軟件就是把人們的需要轉化為計算機可以執行的程序。
這一點毫無疑問,但是這就是我們編碼的目的嗎?我們都知道,計算機其實很笨,它只能認識 0 和 1 這兩個數字,無論多么復雜的程序都是由這兩個最簡單的數字構成。這正如哥德巴赫猜想,作為最復雜的數學證明題,要求解決的卻是最簡單的 1+1 問題。也就是說,最直接的編程就是向計算機輸入 0 或者 1 ,為什么我們不這樣呢?
原因當然很簡單,因為 0 和 1 組成的機器語言實在是太難以理解和記憶了。于是前輩們就發明了匯編語言,匯編語言用單詞 代替了機器語言,它能夠讓人們更加容易理解代碼和程序。可是前輩們又發現匯編語言還是太晦澀難懂,幾百行代碼已經讓人云山霧罩,遇到幾萬行的大型程序,那 簡直就是天書了。所以先行者們又發明了高級語言,高級語言用接近自然語言的方式來編寫程序,就象自然語言一樣,它(們)成為了程序員闡明觀點交流思想的通 用工具。
所以,我們編寫代碼的目的就是為了交流和溝通,而這,也正是計算機語言存在的意義。
考慮別人
既 然編寫代碼的目的是為了溝通,那么作為一個程序員有什么理由去寫那些只有自己才能夠看懂的代碼呢。如果吧這個作為一個問題問大家,恐怕沒有一個人會這樣回 答:“編寫只有自己能看懂的代碼,讓別人去猜吧!”。因為大家都希望合作,都愿意與其他人溝通,這不僅僅是工作的需要也是人類的基本需要之一。
可是,并不是每一個程序員都懂得溝通的藝術。幾年前,我認識了一個很有天分的程序員,他的編程能力讓人吃驚。但是,當他把一個命名為“ tj ”的函數交給我的時候,我只有無語了——“統計?”“添加?”,反復猜測不得要領之后,我只好讓他重寫這個函數。這樣的例子還有很多,幾乎每一個新手都出現過這樣問題,即使他們對所使用的編程語言掌握的無比純熟。
那么怎樣才能編寫一份能夠閱讀并易于理解的代碼呢?下面我給出一些建議,其中的一些已經作為我們團隊《編程規范》的一部分而被大家了解了,而另一些則不然。
<!----><!----><!----> ● ???? <!----> 時刻考慮你所編寫的每一行代碼、代碼中的每一個單詞都會在將來某個時候被你的伙伴們閱讀、測試和維護。這是一個原則,也是一個前提,是每一個程序員所必須具備的基本素質。在一個團隊中,編寫可以閱讀和維護的代碼是團隊合作的前提條件。
<!----><!----><!----> <!----> ●? ? <!----> 必須認真的慎重的為你的變量、函數(方法)、類命名。要起一個科學合理的名字,因為名字是理解代碼的重要依據。同時,一旦代碼發布,其依賴者、繼承者都要永遠維持這種命名。想像一下,如果你和你的同事不得不使用類似“ tj ”這樣的名字,而又不能改變現狀(會影響其他使用者),那該是一件多么痛苦的事情。
<!----><!----><!----> ● 為你的代碼編寫注釋。注釋是代碼的重要組成部分,同時也是別人理解你代碼的重要依據,無論任務多么繁重,時間多么緊張,都應該象對待代碼一樣對待你的注釋。哦,還有,最重要的是維護你的代碼的同時要維護注釋,就像下面一條所說的:
<!----><!----><!----> ●? 請確保注釋是有效的。無效的,甚至是錯誤的注釋還不如不寫注釋,這是顯而易見的。注釋應該言簡意賅,不要用注釋重復你的代碼,也不要用注釋闡述代碼中顯而易見的邏輯。請原諒我的啰嗦——在維護代碼的同時不要忘記維護注釋。
<!----><!----><!----> <!----> ● ? <!----> 空行、空格也是代碼。空行是一個邏輯段起止的標志,它和編程者的思路是一致的。另外,適當的使用空行和空格可以使你的代碼更加清晰。
<!----><!----><!----> <!----> ● ? <!----> 不要耍小聰明。只要有可能,請盡量使用平實的 思路來規劃你的代碼。我們都知道,閱讀別人的代碼往往比自己編寫同樣功能的代碼要困難,因為閱讀代碼的過程就是讀懂對方思想的過程。困難的原因之一是作者 的水平比讀者要高——這當然是讀者所歡迎的;但是,也可能是因為作者使用了晦澀難懂的思路和技巧,這些技巧五花八門無法列舉,下面是常見的幾種情況:
<!---->
1)
???????
<!---->
過度的使用了設計模式。
這是設計模式初學者經常犯的錯誤,設計模式是面向對象思想的精華,但是對于經驗較少的程序員來說,設計模式是抽象的和復雜的,過多的使用設計模式,會使得代碼結構復雜難以理解。
<!---->
2)
???????
<!---->
拼湊結果。
例如,某個復雜的函數返回的值總是比預期結果少
1
,有些程序員會采用
+1
的方式使結果正確。這類做法往往使得代碼邏輯混亂莫名其妙,更為嚴重的是,類似的方法很冗余導致程序中隱藏著錯誤。
<!---->
3)
???????
<!---->
過度封裝。
經常遇到的一種情況就是對第三方類庫的進一步封裝,這必須在有經驗的設計者的指導下進行,因為類似的需求往往出現在各種架構級別的模塊中。對第三方類庫的不合理封裝會導致使用著對類庫的使用產生異議,出現錯誤的用法等。
<!---->
4)
???????
<!---->
拒絕使用成熟的第三方類庫。
許多初級設計人員,往往喜歡自己編寫框架級別的代碼,例如,在
JavaEE
開發中自行設計
MVC
框架。這類做法在多數情況下都是錯誤的,因為成熟的產品比比皆是,這些產品都有廣泛的用戶群、詳盡的文檔、活躍的社區和大量的成熟案例。普通開發人員極少能夠自行編寫同樣水準的代碼,而且,即便寫出來了誰又能夠保證其他開發人員會使用并且喜歡使用呢。
<!---->
5)
???????
<!---->
冒然采用新的技術。
程序員是思維活躍敢于嘗試創新的人群,他們往往樂于使用新的技術和新的產品。但是,在使用這些產品之前請仔細考慮:“你了解它嗎
?
”。冒然在團隊中應用新技術是一種非常不負責任的行為,學習曲線、隱藏
BUG
、適用范圍等等會成為應用新技術的障礙,嚴重的情況下一個類似的決策會導致整個項目的失敗。
?
消除重復
如果說軟件目的就是將需求轉換為程序,那么軟件的本質就是復用。復用是一個非常寬泛概念,微軟將 Windows 操作系統刻錄成光盤出售,用戶買到的都是同樣的程序,這就是復用;我們使用 163 或者 google 的 Email 服務,訪問同樣的 Web 網站,這,也是復用。一個程序、一個 URL 、一個架構、一個類、一個方法都可以成為復用的對象。這里,我們只討論代碼的復用。
<!----><!----><!---->
●
僅在需要的時候使用接口。
接口為我們的應用提供很好的“可替換性”,簡單的說,使用者僅依賴接口,而不必考慮接口 是如何實現的,這樣,一旦發生變化只需要重新實現接口,而依賴于接口的代碼不必改動。顯然,接口是非常強大的,它使得我們的代碼具有擴展性,但是,是否所 有的模塊都需要這種擴展性呢?實踐證明,
80%
左右的模塊不需要替換實現類,這些模塊即使發生了變化也往往是局部的,不會影響其他模塊。而對它們的修改和維護的工作量要遠遠小于重新實現它們的接口。這類模塊,是不需要接口的。那么什么時候使用接口呢,下面列出幾種常見的情況:
<!---->
1)
?
<!---->
兩個并行開發的模塊(或類、子系統),互相存在依賴關系。
例如,
A
模塊依賴
B
模塊的某些功能,因為是并行開發的,所以
B
模塊可能還沒有完成,這個時候,需要
B
模塊提供接口以供
A
模塊使用。
A
模塊開發的時候,可以先使用一個
B
模塊接口的“模擬實現”,等到
B
模塊完成,再替換為真實的實現。
<!---->
2)
?
<!---->
對于結構復雜的或提供公共服務的模塊。
有時候,需要提供一些公共的服務為整個系統使用。例如,在
Java
中直接使用
JDBC
操作數據庫往往比較繁瑣,這個使用需要提供一個通用的
JDBC
封裝,將重復繁瑣的
JDBC
操作提取到抽象類或者工具類中。但是,
JDBC
操作中并非所有的代碼都是重復的和可預見的,此時應該將這些非重復的和不可預見的代碼抽象為接口,工具類依賴接口編程,工具類的使用者來根據自身情況實現這些接口。這其實是一個策略模式的應用,在實際開發中是很常見的。
<!---->
3)
?
<!---->
當模塊的可變性是可以預見的時候。
如果開發人員預見到:“這個模塊將來一定會發生某種變化”,那么此時可以使用接口。這種 情況下,接口的粒度一定要細,僅僅包含變化的功能即可。例如,一組結構相同的數據,需要我們對其中一些特殊的數據進行處理,而原始數據中并沒有提供某種規 律來辨別哪些數據是特殊的,此時,我們只好通過硬編碼(
Hard Code
)來處理這些特殊數據(例如,通過名稱來判斷)。這顯然是代碼中的壞味道,解決的辦法就是提供一個用于判別特殊性的接口,然后用
Hard Code
的部分來實現接口,當客戶方提供了數據的規律的時候,重新實現一個就可以了。
<!----> 4) ? <!----> 在某些大型項目中,不同的模塊可能需要不同的團隊甚至不同公司進行開發。這個時候需要使用接口來規范雙方之間的通信。
?
<!----><!----><!----> <!---->
●
用抽象類實現公用的代碼。
面向對象的原則告訴我們,聚合復用應該優先于繼承復用。但是,當你確定某些類
從本質上講是同一個類別
的時候,就應該考慮將這些類的公共部分提取到抽象類中,以實現代碼的復用。經過這種處理的子類比原來要精簡很多,甚至比使用了聚合復用還要精簡。
<!----><!----><!----> <!----> ● 在復雜的模塊中使用設計模式。
<!----><!----><!----> <!---->
●
適量的使用條件分支判斷。
大量的條件分支判斷會導致代碼冗長、結構松散、邏輯混亂,這類代碼往往沒有可閱讀性和可維護性。但是,并非
if-else
就不能使用的了,只要遵循下面的原則,
if-else
仍然可以使用:
<!----> 1) ????? <!----> 一組條件分支只判斷一類條件。多種條件混合在一組分支中只能說明編程者的思維混亂。
<!----> 2) ????? <!----> 分支要盡可能少,不要超過 8 個。
<!----> 3) ????? <!----> 每個分支的代碼在 3 行以內。
<!----> 4) ????? <!----> 每個分支都有注釋。
<!----> 5) ????? <!----> 最后一個分支用于判斷缺省情況。
<!----> 6) ????? <!----> 如果上述 5 條不能同時滿足,請休息片刻,然后重構你的代碼。
<!----><!----><!---->
●
不要
Copy-Paste
你的代碼。
當你
Copy-Paste
代碼的時候,說明代碼中存在重復,重復的代碼往往導致代碼難以維護和閱讀。一旦那些保存在剪切板中的代碼中存在錯誤,編寫者甚至不知道到哪里修改這些錯誤。每當你
Copy-Paste
代碼的時候,請停下來,考慮將這些代碼提取為方法、類或者組件。
源代碼就是文檔
我們為什么寫設計文檔呢?設計文檔可以說明你的代碼,闡明設計思路,文檔是我們溝通的重要工具,它可以使軟件具有可持續發展性。這里我只想說說詳細設計文檔。 幾年 前,我一直有一些疑問,什么是概要設計和詳細設計?怎樣才算“概要”?怎樣才算“詳細”?詳細到什么程度才算合格?
現在我已經明白了,所謂概要設計就是架構設計,架構就是將一個軟件中功能性的東西剔除之后剩下的部分。這一部分是軟件的結構,它說明了軟件中最為重要的特性和這些特性的實現方式。
那么詳細設計呢?我曾經看到過的詳細設計可以細致到偽代碼,程序員可以不必動腦筋,直接將偽代碼翻譯為 Java 或者 C# 代碼即可。我對這樣的設計人員致以無比的敬意,因為他(們)不但可以為數量遠超他們的程序員寫代碼,更為神奇的是,這些代碼可以在沒有調試過的情況下正常運行。但是,我想今生我都無法達到這個水平了。而且即使我達到了這個水平,我還要為這些設計文檔的維護 尤其是文檔與代碼之間的同步 付出無比艱辛的勞動,與其這樣,我不如:
<!----><!----><!---->?<!----><!---->
<!---->
●
???????
<!---->
簡單設計。
Kent Beck
在《解析極限編程——擁抱變化》中為簡單設計制定了
4
個評價標準,依次為(最重要的排在最前面):通過所有測試;體現所有意圖;避免重復;類 或者方法數量最少。這其中包含的核心意義就是不要為了考慮程序的可擴展性,把目前不需要的功能加入到軟件中來。不要為了遵循某種規范而編寫大量無用的甚至 是起到反作用的文檔,將精力轉移到代碼上來。依附在良好架構上的優質代碼,比任何文檔的作用都明顯。
<!---->
●
???????
<!---->
單元測試的文檔作用。
測試方面我將另行撰文闡述,這里所說的是單元測試的文檔作用。任何一個學習計算機編程的人都知道,
10
行文字說明不如一行代碼演示,這體現了“例子”的重要性。單元測試對于維護者而言就是“例子”,當維護者難以理解你的代碼,當使用者不知如何使用你寫的
API
,當你自己不知道修改代碼會造成哪些影響的時候,單元測試可以為你說明一切。所以,請每 一個程序員都要認真的編寫測試代碼,力求測試代碼能夠反映全部的意圖,此時,單元測試就是文檔!它不但能夠說明代碼的使用、功能,而且天然的與代碼同步, 更重要的是,它可以使你放心的維護你的代碼。
<!---->
●
???????
<!---->
現代編程語言對于文檔的支持。
在
Java
、
C#
、
Ruby
等新興的編程語言中,可以將代碼注釋當作文檔使用。例如
Java
為文檔提供了很多支持——使用
HTML
標簽、使用
@
標記等,結合
Javadoc
命令就可以生成
HTML
格式的文檔。相比傳統的
Word
文檔,注釋作為文檔的優勢是顯而易見的:
<!----> 1) ? <!----> 天然的與代碼同步,省去了很多同步的成本。
<!----> 2) ? <!----> 連接特性使得文檔更容易閱讀。
<!----> 3) ? <!----> 更加規范的文檔格式。
<!---->
●
???????
<!---->
源碼之前了無秘密。
當測試、注釋、文檔都失去作用的時候,不要忘記,我們還有邏輯,還有代碼!代碼之前了無秘密。優質的代碼是說明應用程序的最根本的方式,是程序員溝通的通用語言。
所以,請認真的編寫每一行代碼!
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
