讀代碼整潔之道
本文關(guān)鍵詞:代碼整潔之道,由筆耕文化傳播整理發(fā)布。
現(xiàn)在的軟件系統(tǒng)開發(fā)難度主要在于其復(fù)雜度和規(guī)模,客戶需求也不再像Winston Royce瀑布模型期望那樣在系統(tǒng)編碼前完成所有的設(shè)計滿足用戶軟件需求。在這個信息爆炸技術(shù)日新月異的時代,需求總是在不停的變化,隨之在2001年業(yè)界17位大牛聚集在美國猶他州的滑雪勝地雪鳥(Snowbird)雪場,提出了“Agile”(敏捷)軟件開發(fā)價值觀,并在他們的努力推動下,開始在業(yè)界流行起來。在《代碼整潔之道》(Clean Code),提出一種軟件質(zhì)量,可持續(xù)開發(fā)不僅在于項目架構(gòu)設(shè)計,還與代碼質(zhì)量密切相關(guān),代碼的整潔度和質(zhì)量成正比,一份整潔的代碼在質(zhì)量上是可靠的,為團隊開發(fā),后期維護,重構(gòu)奠定了良好的基礎(chǔ)。在這本書中作者提出了注重實際開發(fā)實踐的細節(jié),而不是站在空洞的理論來談?wù)撜麧嵵馈?/p>
什么是整潔代碼?不同的人會站在不同的角度闡述不同的說法。而我最喜歡的是Grady Booch(《面向?qū)ο蠓治雠c設(shè)計》作者)闡述:
“整潔的代碼簡單直接。整潔的代碼如同優(yōu)美的散文。整潔的代碼從不隱藏設(shè)計者的意圖,充滿了干凈利落的抽象和直截了當?shù)目刂普Z句。”
整潔的代碼就是一種簡約(簡單而不過于太簡單)的設(shè)計,閱讀代碼的人能很清晰的明白這里在干什么,而不是隱澀難懂,整潔的代碼讀起來讓人感覺到就像閱讀散文-藝術(shù)的沉淀,作者是精心在意締造出來。
一:命名
命名包括變量、函數(shù)、參數(shù),類等,一個好的命名能夠很好的表述其所承載的業(yè)務(wù),從命名上就已經(jīng)很好的答復(fù)了為什么存在,做了什么事,應(yīng)該怎么用等的大部分的問題,閱讀者看到它的時候不必去深究其實現(xiàn)細節(jié),一切都在命名上一目了然。一個好的命名必須是名副其實,不存在歧義(雙關(guān)語或常見屬于沖突),直接了當(否定語句或者誤導(dǎo)性命名)。
二:函數(shù):
從匯編/C時代開始的到現(xiàn)在函數(shù)一直都存在與我們開發(fā)中不可或缺的一部分,結(jié)構(gòu)化組織,重用.作為函數(shù)式語言的一等公民,所有程序的第一組代碼。
三:注釋、格式:
并不是寫出完備的注釋就是好的開發(fā)人員,如果代碼清晰的表述自己意圖,那么注釋反而多余。在《重構(gòu)-改善現(xiàn)有代碼之道》中Martin Fowler指出多余的注釋是一種代碼壞味道。就是好的注釋隨著項目的維護不斷的重構(gòu)很多時候也會變得不那么適應(yīng),而我們很少會去主動維護。再則誤導(dǎo)性的注釋更為使用者所憎恨。當然有時我們也得使用注釋,注釋并不是萬惡的,當我們沒法用代碼來描述自己的時候,我們需要注釋去描述意圖;多余有副作用的代碼給使用者提供警告注釋。TODO開發(fā)時進度控制,比如你在進行較大規(guī)模領(lǐng)域重構(gòu),目前有些邏輯不再適應(yīng),不那么自然,而對它的重構(gòu)還在任務(wù)列表最后,你可以選擇標注在TODO中,最后完成從ToDoList中去掉每一個TODO任務(wù)。
良好的代碼格式,會使得我們閱讀更容易,一套共同的格式會讓我們查找理解更快速。每個團隊都應(yīng)該遵循一套固定的代碼格式規(guī)范,整個軟件系統(tǒng)的統(tǒng)風(fēng)格統(tǒng)一,而不是各自為政各成一體。
四:對象和數(shù)據(jù)結(jié)構(gòu):
數(shù)據(jù)結(jié)構(gòu)指的就是數(shù)據(jù)的載體,暴露數(shù)據(jù),而幾乎沒有有意義的行為的貧血類。最常見的應(yīng)用在分布式服務(wù),以wcf,webservice,reset之類的分布式服務(wù)中不可或缺的數(shù)據(jù)傳輸對象(DTO)模式,DTO(Request/Response)就是一個很典型的數(shù)據(jù)載體,只存在簡單的get,set屬性,并且更傾向于作為值對象存在。而對象則剛好相反作為面向?qū)ο蟮漠a(chǎn)物,必須封裝隱藏數(shù)據(jù),而暴露出行為接口,DDD中領(lǐng)域模型傾向于對象不僅在數(shù)據(jù)更多暴露行為操作自己或者關(guān)聯(lián)狀態(tài)。
數(shù)據(jù)結(jié)構(gòu)和對象之間看是細微的差別卻導(dǎo)致了不同的本質(zhì)區(qū)別:使用數(shù)據(jù)結(jié)構(gòu)的代碼便于在不改動現(xiàn)在數(shù)據(jù)結(jié)構(gòu)的前提下添加新的行為(函數(shù)),面向?qū)ο蟠a則便于不改動現(xiàn) 有函數(shù)的前提下添加新的類。換句話說就是數(shù)據(jù)結(jié)構(gòu)難以添加新的的數(shù)據(jù)類型,因為需要改動所有函數(shù),面向?qū)ο蟮拇a則難以添加新的函數(shù),因為需要修改所有的類。在任何一個復(fù)雜的系統(tǒng)都會同時存在數(shù)據(jù)結(jié)構(gòu)和對象,我們需要判斷的是我們需要的是需要添加的新的數(shù)據(jù)類型還是新的行為函數(shù)。
隱藏作為面向?qū)ο笾饕匦灾械淖钪匾匦裕庋b隱藏是面向?qū)ο笾凶钪匾奶匦,一個好的面向?qū)ο蟠a肯定是對對象的內(nèi)部細節(jié)做到很好的隱藏封裝,封裝過后才有是多態(tài),委派之類的。一個好的面向?qū)ο蟮拇a一定是具有很好的隱藏封裝,易于測試,不穩(wěn)定因素往往集中在一處很小或者固定的位置,不穩(wěn)定因素的變更不會導(dǎo)致更大面積的修改擴散。
對象的隱藏要求:方法不應(yīng)和任何調(diào)用方法返回的對象操作,換句話之和朋友說話,不和陌生人說話(迪米特法則,或被譯為最小知識原則),比如:ctxt.getOptions().getSearchDir().getAbsolutePath(),就是迪米特法則的反例模式。
五:異常處理:
每個軟件系統(tǒng)都避不開異常處理,需要防止它搞亂我們的邏輯。
六:邊界:
在系統(tǒng)開發(fā)中不可能一切都得從零開始,自己寫所有的代碼,更好的方案是需要整合一些開源或者第三方的項目,為我所用。但是不能讓這些非自己的代碼滲侵中我們的代碼各處,有一些所以功能很強大的第三方產(chǎn)品,但不一定具有很好的抽象。很多時候我更寧愿花些時間抽象出我們自己所需要的接口在第三方類庫上外覆一層自己的抽象,這樣不僅便于TDD,因為我們能夠很好的創(chuàng)建偽對象,使的測試獨立不依賴外部資源,得到快速反饋;而且在設(shè)計上得到很好的擴展,當由于某些原因如第三方類庫不再能滿足業(yè)務(wù)需求,或者權(quán)益收費等等,我們可以很好的切換底層而使得修改不會擴散到系統(tǒng)各處。外覆類也是處理遺留代碼帶入測試容器的一種很好實踐。
七:單元測試:
TDD中測試代碼在往往和產(chǎn)品代碼差不多,在系統(tǒng)中占據(jù)一半的代碼量,不好的測試代碼也可能拖累項目的開發(fā)。整潔的測試代碼應(yīng)該是遵循first原則的:
八:類:
面向?qū)ο蟮南嗨菩袨榈某橄螅瘮?shù)代碼塊的組織形式,在面向?qū)ο笾形覀兊能浖到y(tǒng)是由眾多的類和類之間的交互協(xié)作完成了。面向?qū)ο筇卣鳎悍庋b,繼承,多態(tài)度,委派。一個設(shè)計良好的類該是具有良好的封裝,站在使用者的調(diào)度考慮那些是使用接口,那些是內(nèi)部細節(jié);這是面向?qū)ο笞钪饕奶卣鳎怯袝r會與測試沖突,可以適當?shù)姆砰_并僅限于于測試調(diào)用。繼承和多態(tài)在面向?qū)ο笾锌梢詫崿F(xiàn)重用,但我更傾向于繼承不是為了重用,而是隔離變化;大量的濫用繼承不干凈的繼承體系將會導(dǎo)致龐大的繼承體系,繼承體系中眾多職責(zé)重復(fù)在各個同級派生類,理想的繼承應(yīng)該是滿足里氏替換原則(LSP:每個父類出現(xiàn)的地方都應(yīng)該可以被派生類所替換,并且能正確的工作);面oo第二原則組合優(yōu)先。而委派則是一個類把部分功能委派給其他類來完成,體現(xiàn)類之間的協(xié)作,類似組合。
九:并發(fā)編程:
并發(fā)是一種時間(When)和目的(What)的解耦,提供應(yīng)用程序的吞吐量,提高cpu利用率;但是并發(fā)編碼不是那么容易,再加上臨界資源競爭死鎖。在并發(fā)編程的時候我們必須盡量遵守一些原則:
更多關(guān)于簡單設(shè)計,迭進,逐步編程代碼,,壞味道,并發(fā)示例請參見代碼整潔之道。
本文關(guān)鍵詞:代碼整潔之道,由筆耕文化傳播整理發(fā)布。
本文編號:142216
本文鏈接:http://sikaile.net/wenshubaike/mishujinen/142216.html