?
1.什么樣的代碼是可讀性好的代碼?
“讓人閱讀你的代碼戈钢,就像閱讀文章一樣流暢,就像閱讀散文詩(shī)一樣優(yōu)美是尔!”——這就是好代碼殉了!
把代碼當(dāng)作一篇優(yōu)美的散文詩(shī)來(lái)寫(xiě)!用這樣的標(biāo)準(zhǔn)來(lái)要求自己拟枚,一定會(huì)寫(xiě)出好代碼薪铜,一定會(huì)成為一個(gè)優(yōu)秀的程序員。
代碼不僅是寫(xiě)給機(jī)器編譯的恩溅,更是寫(xiě)給人看的隔箍!
代碼不僅是代碼,更是文檔脚乡!
2.理清思路再動(dòng)手——先寫(xiě)注釋鞍恢,再寫(xiě)代碼
清晰的思路是編程行動(dòng)的良好指南∶拷眩花點(diǎn)時(shí)間思考一下帮掉,不要一接到任務(wù)就動(dòng)手編代碼,從而陷入技術(shù)細(xì)節(jié)不可自拔窒典。
2.1 我的編程步驟
(1)在一個(gè)空的函數(shù)體內(nèi)用注釋寫(xiě)出自己的思路蟆炊,如:
//功能說(shuō)明:XXX
private void MyMainFunction()
{
//第1步,XXX
//第2步瀑志,XXX
MySubFunction ();//實(shí)現(xiàn)XXX
//第3步涩搓,XXX
}
//功能說(shuō)明:XXX
private void MySubFunction()
{
//先空著
return 0;
}
(2)理清思路后,在空白處填寫(xiě)自己的代碼劈猪。
如果某個(gè)步驟中實(shí)現(xiàn)起來(lái)感覺(jué)有點(diǎn)麻煩昧甘,那就先放一個(gè)空的子函數(shù),為這個(gè)子函數(shù)建一個(gè)空的函數(shù)體——保證編譯始終通過(guò)战得,稍后再填充這個(gè)空函數(shù)體充边。這種方法不影響你的整體思路,避免陷入編程細(xì)節(jié),同時(shí)又讓“大事化小浇冰,小事化了”贬媒。
(3)編完主函數(shù)后,填充空的子函數(shù)體肘习。
其實(shí)是對(duì)(1)(2)的迭代际乘。通過(guò)主函數(shù)的運(yùn)行效果,可以實(shí)時(shí)檢測(cè)子函數(shù)編寫(xiě)的正確與否漂佩。我們編寫(xiě)的子函數(shù)都即時(shí)被應(yīng)用場(chǎng)景所調(diào)用脖含,也就是即時(shí)的被測(cè)試,這不也是測(cè)試驅(qū)動(dòng)的思想嗎投蝉?事實(shí)證明器赞,這樣得到的函數(shù),比預(yù)先設(shè)計(jì)的函數(shù)更有用墓拜。
這樣港柜,只要思路清晰正確,編程就不會(huì)走太大彎路咳榜。
2.2 注釋?xiě)?yīng)先于代碼存在
注釋?xiě)?yīng)先于代碼存在夏醉,而不是編寫(xiě)完代碼之后去補(bǔ)注釋。因?yàn)槿斯逃械膽卸栌亢帉?xiě)完代碼之后都不情愿再去主動(dòng)加注釋畔柔,這使得代碼的可讀性變差。
另外臣樱,利用空白或空白行合理分隔代碼靶擦,也是一種良好的注釋。就像好的文章印刷雇毫,段落間距要大一點(diǎn)是一樣的玄捕。文章中也要留白!
C#代碼中可使用region合理分隔代碼棚放,同時(shí)在region中加入注釋枚粘。特別是,一定要把私有函數(shù)聚集到region中折疊起來(lái)飘蚯,不要與公有函數(shù)(或事件函數(shù))交叉馍迄,因?yàn)槲覀冮喿x代碼往往是從公有函數(shù)(或事件函數(shù))入手的。這可以隱藏細(xì)節(jié)局骤,使代碼看起來(lái)更整潔攀圈。
3.給變量起個(gè)好名字!
合理的變量命名是代碼可讀的基礎(chǔ)峦甩。好的命名赘来,不僅僅是使得代碼易讀,它代表了你對(duì)業(yè)務(wù)領(lǐng)域的理解,對(duì)程序邏輯的認(rèn)知撕捍,對(duì)項(xiàng)目框架的把握。所以泣洞,好的程序員很多時(shí)候糾結(jié)的不是技術(shù)實(shí)現(xiàn)問(wèn)題忧风,而是如何為變量起一個(gè)好名字,使得代碼讀起來(lái)流暢球凰,能讓更多的人理解狮腿!
遵循一些成熟的命名規(guī)范,給變量起個(gè)好名字的事會(huì)容易一些呕诉。接下來(lái)缘厢,我們探討一下常見(jiàn)的命名規(guī)范問(wèn)題。
(1)常見(jiàn)的大小寫(xiě)命名法
PascalCasing(大寫(xiě)開(kāi)頭):用于名字空間甩挫、類型贴硫、成員等的命名伊者,舉例:FileStream英遭。
camelCasing(駝峰命名法亦渗,小寫(xiě)開(kāi)頭):用于形參、局部變量法精、私有字段等的命名多律。舉例EncryptFile(string plainFile, string cypherFile)。
匈牙利命名法(小寫(xiě)開(kāi)頭狼荞,首單詞為數(shù)據(jù)類型):不推薦使用帮碰,因?yàn)镮DE的智能提示很容易讓你知道變量的類型粘秆。舉例:intCount、iCount收毫。(其實(shí)攻走,我們對(duì)匈牙利命名法有誤解此再,下篇再談)
另外,微軟建議不要在單詞間使用下劃線输拇。
(2)名字空間的命名
Company.Product.Subnamespace。舉例:
HuazemingTech.RailwayMis.Web
(3)類(結(jié)構(gòu))及對(duì)象的命名
名詞或名詞短語(yǔ)逛裤,因?yàn)樗鼈兇硐到y(tǒng)中的實(shí)體。舉例:
Student student;
List students;
(4)接口的命名
表示類型層次的根基時(shí):名詞或名詞短語(yǔ)带族,如:IList;
表示某種能力時(shí):形容詞或形容詞短語(yǔ)蝙砌,如IComparable择克。
(5)方法的命名
動(dòng)詞或動(dòng)詞短語(yǔ),DoSomething()肚邢。如:String.Split()
返回布爾值時(shí)使用表示肯定性的短語(yǔ),并考慮第三人稱缀旁。如:collection.Contains(item)
(6)屬性的命名
名詞短語(yǔ)或形容詞勺鸦。舉例:
public class ListView{
public ItemCollection Items {get;}//這里用復(fù)數(shù)形式
}
用肯定性短語(yǔ)命名布爾屬性,考慮前綴“Is/Can/Has”换途。舉例:CanRead、IsPostBack剃执。
(7)命名規(guī)范不是一成不變的
命名規(guī)范不是一成不變的懈息,在特定場(chǎng)景下可以有自己風(fēng)格的約定,前提是要使代碼保持一致辫继、易讀。比如遣耍,一般我們強(qiáng)烈反對(duì)使用漢語(yǔ)拼音命名變量炮车,可是在有些項(xiàng)目中酣溃,特別是涉及國(guó)內(nèi)政府纪隙、院校的信息標(biāo)準(zhǔn)時(shí),其數(shù)據(jù)庫(kù)字段(量很大)完全是按漢語(yǔ)拼音首字母制定的碘饼,如果非要翻譯成英文就有點(diǎn)矯枉過(guò)正了(工作量本身也很大)麸拄。一旦熟悉了這個(gè)行業(yè)之后黔姜,這些漢語(yǔ)拼音簡(jiǎn)寫(xiě)也就成了業(yè)務(wù)領(lǐng)域知識(shí)的一部分了,也就不那么別扭了秆吵,這也算中國(guó)特色吧。
4.如何檢測(cè)你的代碼是否規(guī)范主穗?
(1)人工檢測(cè):讓同伴閱讀你的代碼(結(jié)對(duì)編程毙芜,代碼復(fù)審),發(fā)現(xiàn)問(wèn)題晦雨。自我檢測(cè)隘冲,不懈追求――“讓人閱讀你的代碼,就像閱讀文章一樣流暢展辞!”。
(2)工具檢測(cè):FxCop洽腺,微軟的一個(gè)開(kāi)發(fā)工具覆旱,可以對(duì)編譯過(guò)的托管代碼進(jìn)行分析,并告訴用戶哪些地方不符合設(shè)計(jì)規(guī)范度液。(博友【金色海洋(jyk)陽(yáng)光男孩】推薦:R#--ReSharper: http://www.jetbrains.com/resharper/).
5.重構(gòu)你的代碼,做得更好一點(diǎn)點(diǎn)堕担!
嗅嗅代碼的壞味道:如果你發(fā)現(xiàn)在單頁(yè)中寫(xiě)了過(guò)多的MySubFunction,如果你檢測(cè)到不符合設(shè)計(jì)規(guī)范的代碼佑惠,如果你寫(xiě)了過(guò)長(zhǎng)的函數(shù)齐疙,如果你發(fā)現(xiàn)你在重復(fù)拷貝相同的代碼段……是時(shí)候重構(gòu)你的代碼了!
何謂重構(gòu)赌厅?重構(gòu)是對(duì)軟件內(nèi)部結(jié)構(gòu)的一種調(diào)整轿塔,目的是在不改變軟件可察行為的前提下,提高其可理解性勾缭,降低其修改成本。
為何重構(gòu)毒嫡?改進(jìn)軟件設(shè)計(jì)(消除重復(fù)幻梯,Don’t Repeat Yourself);使代碼更易理解(提高可讀性)膳叨;幫你找到Bug(Keep Your Code Clean)痘系;助你提高編程速度(后退是為了大踏步的前進(jìn))。
何時(shí)重構(gòu)汰翠?三次法則:事不過(guò)三,三則重構(gòu)健田。重構(gòu)不是重構(gòu)的目的佛纫,當(dāng)重構(gòu)能幫助你把后續(xù)的事情做得更好总放,那么還等什么好爬?重構(gòu)的時(shí)機(jī):添加功能時(shí),修補(bǔ)錯(cuò)誤時(shí)炬搭,復(fù)審代碼時(shí)穆桂。
如何重構(gòu)?小步前進(jìn)灼芭,不斷驗(yàn)證驼侠。(Done is Better Than Perfect)
常見(jiàn)的重構(gòu)原因和對(duì)策:
(1)代碼重復(fù)谆吴。提取為公共類/函數(shù)。
(2)代碼形式重復(fù)笋熬∧骞剑考慮模板類/泛型。
(3)過(guò)多函數(shù)的類筹吐。考慮使用partial分部類嘉竟,將類分拆到多個(gè)文件中去洋侨,每個(gè)分部類對(duì)應(yīng)一個(gè)文件。如MVC中Controller類往往會(huì)成為包含過(guò)多Action函數(shù)的類边苹,就可將其按功能域拆分為多個(gè)分部類裁僧。
(4)過(guò)長(zhǎng)的參數(shù)列表慕购。構(gòu)造一個(gè)對(duì)象茬底,包含所有要用的參數(shù)硝岗,然后將這個(gè)對(duì)象當(dāng)作參數(shù)即可移斩。
編程的過(guò)程實(shí)際是一個(gè)不斷重構(gòu)(改進(jìn))的過(guò)程赴魁。通過(guò)不斷重構(gòu)丹弱,可以去除代碼的壞味道谨胞,編寫(xiě)可讀性更好的代碼蒜鸡。同時(shí)也深化了你對(duì)設(shè)計(jì)的理解,提高了你的編程素養(yǎng)叶沛。
重構(gòu)忘朝,是一種生活態(tài)度,每天做得更好一點(diǎn)點(diǎn)溉箕。不要有過(guò)多的期望悦昵,一點(diǎn)點(diǎn)就好!不斷前進(jìn)但指,逐步逼近完美枚赡。
6.向微軟學(xué)習(xí),向MSDN學(xué)習(xí)贫橙!
微軟作為業(yè)界最為成功的軟件生產(chǎn)商,在各方面都有值得我們學(xué)習(xí)的地方疲迂。我覺(jué)得Windows、Office等是我們做界面和為用戶設(shè)計(jì)操作模式的最好老師郑气,當(dāng)我沒(méi)有思路的時(shí)候腰池,我都會(huì)打開(kāi)Windows的某個(gè)功能看看,就會(huì)受到啟發(fā)讳侨。
MSDN是我們學(xué)習(xí)編程的最好老師奏属。MSDN是眾多大師的智慧結(jié)晶。經(jīng)秤掠ぃ看MSDN中的類庫(kù)嘱腥,不僅可以系統(tǒng)的掌握類庫(kù)的功能,還可以學(xué)到如何給變量命名爹橱,如何進(jìn)行架構(gòu)設(shè)計(jì)等愧驱⊥终担看MSDN中的示例代碼,也是快速上手的捷徑掏颊;特別是一些“快速指南”乌叶,能很快讓你了解某個(gè)方面的開(kāi)發(fā)技術(shù)∽荚。總之乐横,看MSDN有百利而無(wú)一害今野,呵呵罐农,比看很多爛書(shū)強(qiáng)多了。(最近也發(fā)現(xiàn)了MSDN中一些代碼比較爛)
MSDN是幫助文檔涵亏,我們?cè)谑褂煤芏嘬浖龅絾?wèn)題時(shí)气筋,是否忽略了開(kāi)發(fā)者精心給我們準(zhǔn)備的幫助文檔呢?
(現(xiàn)在做APP裆悄,沒(méi)思路的時(shí)候就看看淘寶光稼、京東、微信艾君、支付寶冰垄,看他們的UI布局/設(shè)計(jì)、看他們的操作流程虹茶,能夠得到啟發(fā))
7.小結(jié)
通過(guò)注釋理清思路,給變量起好名字董济,重構(gòu)你的代碼要门,從MSDN中領(lǐng)悟大師真諦,其實(shí)都是一些編程習(xí)慣封豪,養(yǎng)成好的炒瘟、適合自己的習(xí)慣會(huì)受益終身。軟件大師Kent Beck說(shuō):
“我不是個(gè)偉大的程序員藻雌,我只是個(gè)有著一些優(yōu)秀習(xí)慣的程序員而已⊙倍牛”
——與諸君共勉做个!希望大家都成為具有優(yōu)秀習(xí)慣的程序員,編寫(xiě)散文詩(shī)一樣的代碼顽频!
參考文獻(xiàn)/推薦閱讀:
《編寫(xiě)可讀代碼的藝術(shù)》
《代碼整潔之道》
《.NET設(shè)計(jì)規(guī)范:約定太闺、慣用法與模式》
《重構(gòu)——改善既有代碼的設(shè)計(jì)》
備注:本文以C#編程為例,不足之處蟀淮,敬請(qǐng)批評(píng)指正钞澳。這是本人以前寫(xiě)的文章,第一次使用“簡(jiǎn)書(shū)”策治,試發(fā)一下兰吟,歡迎交流。