工作三年以來(lái)一直對(duì)寫出設(shè)計(jì)優(yōu)雅且可讀性較好的代碼抱有執(zhí)念,最初接觸到的關(guān)于代碼整潔和軟件設(shè)計(jì)的書是《代碼整潔之道》,這本書大概在我入職半年時(shí)讀完,并在很長(zhǎng)的一段時(shí)間內(nèi)將其中談到的“每個(gè)方法只做一件事”、“方法長(zhǎng)度最多不要超過(guò) 5 行”和“優(yōu)秀的代碼都是自解釋的,很少會(huì)有注釋”等等觀點(diǎn)奉為圭臬,但是由于其成書較早,其中的一些觀點(diǎn)顯然已經(jīng)不再使用當(dāng)前業(yè)務(wù)開發(fā)環(huán)境了。就拿前兩點(diǎn)來(lái)說(shuō),看上去能讓每個(gè)小方法盡可能的簡(jiǎn)單,但是對(duì)于復(fù)雜的業(yè)務(wù)系統(tǒng)來(lái)說(shuō),這將會(huì)產(chǎn)生很多的小方法堆疊,產(chǎn)生“方法風(fēng)暴”,在看一個(gè)方法時(shí),需要不斷的在各個(gè)小方法中往復(fù)跳轉(zhuǎn),使得可讀性大大降低。
然而,《軟件設(shè)計(jì)哲學(xué) A Philosophy of Software Design》我覺(jué)得相對(duì)來(lái)說(shuō)是更符合當(dāng)前軟件開發(fā)的指導(dǎo)書,其中談到了與其相反的觀點(diǎn):“方法的可讀性并不取決于它的長(zhǎng)度”,“隔離復(fù)雜性,設(shè)計(jì)深的模塊”和“寫完善的注釋內(nèi)容”等等,我認(rèn)為這些和我們當(dāng)前的開發(fā)是相契合的,以其中的原則作為開發(fā)設(shè)計(jì)指南也是非常合適的。
本文則主要是對(duì)其中談到的部分觀點(diǎn)進(jìn)行討論,深入學(xué)習(xí)還是推薦大家去看原書。
設(shè)計(jì)“深”的類
設(shè)計(jì)較好的類通常功能強(qiáng)大但是公開出的接口非常簡(jiǎn)單,這樣的類被稱為“深”的。什么是“深”的類呢?如下圖所示:
如果用矩形來(lái)表示類的話,則矩形的面積與類提供的功能成正比;矩形頂部邊緣表示類公開出的接口,邊緣長(zhǎng)度越長(zhǎng)則表示接口越復(fù)雜。較“深”的類,因?yàn)槠鋬?nèi)部復(fù)雜性只有很小一部分對(duì)調(diào)用者可見(jiàn),所以稱它設(shè)計(jì)較好。
以 Java 語(yǔ)言中的垃圾回收器為例,它在后臺(tái)操作垃圾回收,實(shí)現(xiàn)非常復(fù)雜,而這種復(fù)雜性對(duì)程序員卻是隱藏的,因?yàn)樗緵](méi)有公開出任何接口。
不過(guò),在《代碼整潔之道》中,深類的價(jià)值并沒(méi)有得到肯定,而且在軟件設(shè)計(jì)的傳統(tǒng)觀點(diǎn)中也認(rèn)為:“類應(yīng)該小,而不是深”,一些較大的類通常會(huì)被鼓勵(lì)拆分成多個(gè)小類。這種設(shè)計(jì)原則會(huì)導(dǎo)致創(chuàng)建大量的淺類(每個(gè)類都很簡(jiǎn)單),在《軟件設(shè)計(jì)哲學(xué)》中被稱為“多類癥”,是一種冗長(zhǎng)的編碼風(fēng)格。這些淺類都具有自己的接口,但并不會(huì)貢獻(xiàn)太多的功能,隨著這些淺類的累積,系統(tǒng)的復(fù)雜性會(huì)隨之增加。
Java IO 類庫(kù)是“多類癥”很好的例子,比如我們要在文件中獲取序列化的對(duì)象,要寫如下代碼:
FileInputStream fileStream = new FileInputStream(fileName); BufferedInputStream bufferedStream = new BufferedInputStream(fileStream); ObjectInputStream objectStream = new ObjectInputStream(bufferedStream);
我們必須創(chuàng)建 3 個(gè)對(duì)象來(lái)完成這個(gè)操作,前兩個(gè)步驟中 FileInputStream 提供基本的 I/O,BufferedInputStream 添加執(zhí)行緩沖的功能,而實(shí)際上我們想要的只是最后創(chuàng)建的 ObjectInputStream 對(duì)象,這使編碼看上去比較冗余。盡管這使得各個(gè)類的職責(zé)更加分明,并且允許用戶創(chuàng)建不帶有緩存機(jī)制的序列化對(duì)象,但這并沒(méi)有帶來(lái)簡(jiǎn)單易用的結(jié)果。提供選擇固然是好的,但如果沒(méi)有因此使其簡(jiǎn)單易用則背離了設(shè)計(jì)的初衷。
好好寫注釋
花時(shí)間來(lái)好好為變量和方法命名,是非常值得的,它能大大的提高可讀性,最好的情況是:當(dāng)讀者看到它時(shí),就已經(jīng)基本領(lǐng)會(huì)了它的作用。盡可能的讓它們明確、直觀且不太長(zhǎng)。如果很難為變量或方法找到一個(gè)簡(jiǎn)單的名稱,那么這可能暗示底層對(duì)象的設(shè)計(jì)不夠簡(jiǎn)潔,可以考慮拆分成多個(gè)分別定義或者為其添加上必要的注釋。
但《代碼整潔之道》中卻對(duì)注釋持有消極的觀點(diǎn):
... 注釋最多只能算是一種不得已而為之的手段。若編程語(yǔ)言有足夠的表達(dá)力,或者我們長(zhǎng)于用這些語(yǔ)言來(lái)表達(dá)意圖,就不那么需要注釋——也許根本不需要。
注釋的恰當(dāng)用法是彌補(bǔ)我們?cè)诖a中未能表達(dá)清楚的內(nèi)容... 注釋總是代表著失敗,我們總有不用注釋便很難表達(dá)代碼意圖的時(shí)候,所以總要有注釋,這并不值得慶賀。
曾經(jīng)我也對(duì)這個(gè)觀點(diǎn)信以為然,但是隨著我在開發(fā)中盡力寫自解釋的代碼時(shí)卻發(fā)現(xiàn):緊靠幾個(gè)簡(jiǎn)短的詞語(yǔ)并不能將方法的作用解釋清楚,想讓它自解釋就會(huì)導(dǎo)致方法名寫的很長(zhǎng),而且多數(shù)情況下,研發(fā)同事并不愿意花精力去翻譯那冗長(zhǎng)又蹩腳的方法名,給人更多的感受是:“這寫的都是什么?”
后來(lái),我漸漸放棄了寫自解釋的代碼,并通過(guò)添加注釋來(lái)增加可讀性,這不僅僅減少了大家對(duì)代碼提出的抱怨,而且還減輕了為方法命名的壓力。“好的代碼是自解釋的”的觀點(diǎn)也在心中祛魅,它其實(shí)更像是程序員心中的美好幻想。
注釋除了能提高可讀性之外,還能隱藏復(fù)雜性,提高抽象程度。它能對(duì)接口實(shí)現(xiàn)進(jìn)行概括,相當(dāng)于是實(shí)現(xiàn)的簡(jiǎn)化視圖,如果讀者必須要去接口實(shí)現(xiàn)中研究每一段代碼才能了解它的功能的話,那么就談不上任何抽象了。
還有一點(diǎn)值得注意的是:注釋并不是彌補(bǔ)方法名表達(dá)能力欠佳的補(bǔ)丁,也不是簡(jiǎn)單的對(duì)代碼的重復(fù),而是代碼書寫前的先決條件。因?yàn)?strong>先寫注釋能帶來(lái)很多好處:
能夠?qū)⒃O(shè)計(jì)時(shí)想到的東西記錄下來(lái),而且方便后續(xù)維護(hù)
先寫注釋能更在開發(fā)進(jìn)行時(shí)衡量設(shè)計(jì),如果方法或變量的注釋能夠以非常簡(jiǎn)潔的描述來(lái)概括它的功能,那么通常設(shè)計(jì)是較好的,如果注釋非常冗長(zhǎng),而且其中暴露出很多具體實(shí)現(xiàn)相關(guān)的內(nèi)容,那么設(shè)計(jì)可能需要重新考慮
如果你崇尚良好設(shè)計(jì)的話,那么寫注釋是一件有意思的事情,因?yàn)槟銜?huì)發(fā)現(xiàn),你的設(shè)計(jì)是如此的簡(jiǎn)潔,以至于你只需要寫一兩句話就能描述清楚它的功能
如果使用 AI 代碼自動(dòng)補(bǔ)全功能的話,你將能更強(qiáng)烈地感受到它的威力
隨著注釋寫的越來(lái)越多,你會(huì)發(fā)現(xiàn):注釋其實(shí)是代碼的一部分,因?yàn)樗还馓峁┐a之外的重要信息,還反映了開發(fā)者對(duì)代碼的設(shè)計(jì)和重視,隨著時(shí)間的推移,有新的開發(fā)者加入時(shí),也能讓他快速理解代碼,降低出現(xiàn) Bug 的概率。
注意事項(xiàng)
《軟件設(shè)計(jì)哲學(xué)》中還提到了一些在開發(fā)中需要謹(jǐn)慎注意的事情:
盡可能少用配置參數(shù)
這個(gè)觀點(diǎn)讓我想到在開發(fā)補(bǔ)購(gòu)查詢接口時(shí)為其添加的配置,其中可對(duì)查詢的數(shù)據(jù)規(guī)模和相關(guān)品類信息等進(jìn)行配置。雖然該配置僅供研發(fā)使用,但是實(shí)際上這提高了接口的復(fù)雜性。為了將其帶來(lái)的復(fù)雜性降到最低,采用了以下兩種方法:
詳細(xì)的注釋:為配置類中的每個(gè)字段添加上詳細(xì)的注釋,讓研發(fā)能清晰的了解每個(gè)參數(shù)的作用
指定默認(rèn)值:當(dāng)某些參數(shù)不被配置時(shí),提供默認(rèn)值來(lái)滿足基本的功能
自適應(yīng)變更配置是書中提到的一個(gè)不錯(cuò)的觀點(diǎn),通過(guò)代碼的執(zhí)行情況不斷自適應(yīng)調(diào)整參數(shù)值,減少人為的干預(yù),但是我認(rèn)為這種方法應(yīng)用的場(chǎng)景比較有限,它更像是算法中參數(shù)的自適應(yīng)調(diào)整。
保持一致性
有些項(xiàng)目可能開發(fā)較早,并沒(méi)有隨著軟件設(shè)計(jì)的發(fā)展而實(shí)時(shí)調(diào)整,但這并不能算得上是什么壞事,只要大家在項(xiàng)目中遵循現(xiàn)有約定,也能維持較好的系統(tǒng)設(shè)計(jì)。反倒說(shuō)貿(mào)然地引入新的設(shè)計(jì)原則,造成新原則和舊原則并存才是更糟糕的,因?yàn)檫@很可能會(huì)導(dǎo)致混亂。
尋求通用的設(shè)計(jì)
在開發(fā)需求時(shí),盡可能不進(jìn)行定制化開發(fā),而是思考通用的實(shí)現(xiàn)邏輯,即使在不考慮復(fù)用的情況下,通用性代碼也是更合理的。在進(jìn)行開發(fā)設(shè)計(jì)時(shí),可以嘗試思考如下問(wèn)題來(lái)引導(dǎo)自己找出通用設(shè)計(jì):
滿足當(dāng)前需求最簡(jiǎn)單的接口是什么?
這個(gè)方法會(huì)在多少種情況下被使用?
目前通用的 API 使用起來(lái)是否簡(jiǎn)單?
不管是專用的類或方法還是代碼里的特殊情況,都是軟件復(fù)雜性的主要來(lái)源。專用代碼無(wú)法完全消除,但通過(guò)良好的設(shè)計(jì)能夠顯著減少專用代碼,并將專用代碼與通用代碼分開。這能使類更深、隱藏復(fù)雜性以及讓代碼更簡(jiǎn)單、更清晰。
終:沒(méi)有孰是孰非
我覺(jué)得《軟件設(shè)計(jì)哲學(xué)》是站在代碼閱讀者的角度上,考慮的是該如何設(shè)計(jì)能讓讀者更輕松的讀懂,降低復(fù)雜性,像其中的提到的“永遠(yuǎn)不要反駁他人對(duì)代碼可讀性的評(píng)價(jià)”的觀點(diǎn),都是在對(duì)其進(jìn)行強(qiáng)調(diào)。而《代碼整潔之道》給我的感受是站在代碼的書寫者身上,因?yàn)槲矣X(jué)得像“一個(gè)方法只做一件事”、“代碼長(zhǎng)度不要超過(guò)多少行”和“盡可能不寫注釋”等原則,更多的是強(qiáng)調(diào)如何寫,或者說(shuō)是讓研發(fā)人員關(guān)注如何寫上,對(duì)于如何讓讀者讀懂,是沒(méi)有深入去考慮的。當(dāng)然《代碼整潔之道》也并不是一無(wú)是處,比如其中談到:“方法的排列要自上而下,讓讀者看起來(lái)就像讀報(bào)紙一樣,并不是簡(jiǎn)單的將公有或私有方法排列在一起”,這對(duì)代碼的可讀性也是有幫助的。所以,這兩本書更適合結(jié)合起來(lái)比較閱讀。
更重要的是,《軟件設(shè)計(jì)哲學(xué)》強(qiáng)調(diào)要成為一名軟件設(shè)計(jì)師,并不斷提高設(shè)計(jì)技能,降低系統(tǒng)的復(fù)雜性。雖然這可能會(huì)將大部分時(shí)間花在設(shè)計(jì)上,但是這些設(shè)計(jì)會(huì)很快帶來(lái)回報(bào),尤其是需要對(duì)這部分功能一遍又一遍地迭代時(shí),你一定會(huì)發(fā)出“幸虧做了良好設(shè)計(jì)”的感嘆,并從中獲得源源不斷的快樂(lè)。
That's all.
審核編輯 黃宇
-
接口
+關(guān)注
關(guān)注
33文章
8718瀏覽量
152027 -
JAVA
+關(guān)注
關(guān)注
19文章
2976瀏覽量
105222 -
代碼
+關(guān)注
關(guān)注
30文章
4837瀏覽量
69128
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
FPGA設(shè)計(jì)代碼整潔之道2
FPGA整潔代碼之道3-信號(hào)命名和定義應(yīng)該明確
軟件設(shè)計(jì)師全書
![<b class='flag-5'>軟件設(shè)計(jì)</b>師全書](https://file.elecfans.com/web2/M00/48/86/pYYBAGKhtAuAXufFAABAH2sRQQ0372.jpg)
代碼整潔之道
8051單片機(jī)C語(yǔ)言軟件設(shè)計(jì)8051單片機(jī)C語(yǔ)言軟件設(shè)計(jì)
![8051單片機(jī)C語(yǔ)言<b class='flag-5'>軟件設(shè)計(jì)</b>8051單片機(jī)C語(yǔ)言<b class='flag-5'>軟件設(shè)計(jì)</b>](https://file.elecfans.com/web2/M00/4A/08/pYYBAGKhvIyANgbbAAAgeM84xV4959.png)
CapTIvateTM軟件設(shè)計(jì)平臺(tái)的應(yīng)用介紹(3)
代碼質(zhì)量和其整潔度成正比有什么道理如何進(jìn)行代碼整潔教材免費(fèi)下載
軟件設(shè)計(jì)哲學(xué) 于延保代碼改造中的實(shí)踐
![<b class='flag-5'>軟件設(shè)計(jì)</b><b class='flag-5'>哲學(xué)</b> 于延保<b class='flag-5'>代碼</b>改造中的實(shí)踐](https://file1.elecfans.com//web1/M00/F2/B4/wKgaoWcIyU2ANWoaAACUAeaInlg195.png)
評(píng)論