天天看點

什麼樣的代碼是高品質的代碼?

在作者的工作經曆中,每當同僚評論項目代碼品質的時候,作者聽到最多的評論是“代碼 寫得很爛”或“代碼寫得很好”。作者認為,用“好”“爛”這樣的字眼來描述代碼品質是非常 籠統的。當作者詢問代碼到底“爛”在何處或“好”在哪裡時,盡管大部分同僚都能簡單地羅 列幾個“爛”的方面或好的方面,但他們的回答往往都不夠全面,知識點零碎, 也無法切中 要害。

當然,也有一些軟體工程師對如何評價代碼品質有所認識,如認為好代碼是易擴充、易讀、 簡單、易維護的,等等,但他們對于這些評價的了解往往隻停留在表面上,對于諸多更加深入 的問題, 如“怎麼才算可讀性好?什麼樣的代碼才算易擴充、易維護?可讀、可擴充與可維護 之間有什麼關系?可維護中的‘維護’兩字該如何了解?”,等等,他們并沒有太清晰的認識。

實際上,對于代碼品質的描述,除“好”“爛”這樣比較簡單、籠統的描述方式以外,還 有很多語義豐富、專業和細化的描述方式,如下所示:

靈活性(flexibility)、可擴充性(extensibility)、可維護性(maintainability)、可讀性(readability)、 可了解性(understandability)、易修改性(changeability)、可複用性(reusability)、可測試性(testability)、子產品化(modularity)、高内聚低耦合(high cohesion loose coupling)、高效(high effciency)、高性能(high performance)、安全性(security)、相容性(compatibility)、易用 性(usability)、簡潔(clean)、清晰(clarity)、簡單(simple)、直接(straightforward)、少 即是多(less code is more)、文檔詳盡(well-documented)、分層清晰(well-layered)、正确 性(correctness 、bug free)、健壯性(robustness)、魯棒性(robustness)、可用性(reliability)、 可伸縮性(scalability)、穩定性(stability)和優雅(elegant)等。

面到如此多的詞彙,我們到底應該使用哪些詞彙來描述一段代碼的品質呢?

實際上,我們很難通過其中的某個或某幾個詞彙來全面地評價代碼品質,因為這些詞彙是 從不同角度描述代碼品質的。例如,在評價一個人的時候,我們往往通過多個方面進行綜合評 價,如性格、能力等,否則,對一個人的評價可能是片面的。同樣,對于代碼品質,我們也需 要綜合多種因素進行評價,不應該從單一的角度去評價。例如,一段代碼的可擴充性很好,但 可讀性很差,那麼,我們不能片面地認為這段代碼的品質高。

注意,不同的評價角度并不是完全獨立的,有些之間存在包含關系、重疊關系等,或者可 以互相影響。例如,代碼的可讀性和可擴充性好,可能意味着代碼的可維護性好。而且,各種 評價角度不是“非黑即白”。例如,我們不能簡單地将代碼評價為可讀或不可讀。如果用數字 來量化代碼的可讀性,那麼應該是一個連續的區間值,而非 0 、 1 這樣的離散值。

不過,我們真的可以客觀地量化一段代碼的品質嗎?答案是否定的。對一段代碼品質的評 價,常常帶有很強的主觀性。例如,對于什麼樣的代碼才算是可讀性好,每個人的評判标準都 不一樣。

正是因為代碼品質評價的主觀性,使得這種主觀評價的準确度與軟體工程師自身的經驗有 極大的關系。軟體工程師的經驗越豐富,給出的評價往往越準确。形成對比的是,資曆較淺的 軟體工程師常常覺得沒有一個可量化的評價标準作為參考,很難準确判斷一段代碼的品質。如 果無法辨識代碼寫得好或壞,那麼,即使寫再多的代碼,編碼能力也可能沒有太大提高。

在仔細閱讀前面羅列的代碼品質評價标準之後,讀者會發現,有些詞彙過于籠統、抽象, 而且偏向于對整體的描述,如優雅、好、壞、整潔和清晰等;有些過于注重細節、偏重方法 論,如子產品化、高内聚低耦合、文檔詳盡和分層清晰等;有些可能并不僅僅局限于編碼,與架 構設計等也有關系,如可伸縮性、可複用性和穩定性等。

為了讀者有重點地進行學習,作者挑選了7 個常用且重要的評價标準來詳細講解,包括可 維護性、可讀性、可擴充性、靈活性、簡潔性、可複用性和可測試性。

1 可維護性(maintainability)

對于代碼開發,“維護”無外乎修改 bug、修改舊的代碼和添加新的代碼等。“代碼易維護” 是指, 在不破壞原有代碼設計、不引入新的 bug 的情況下, 能夠快速修改或添加代碼。“代碼 不易維護”是指,修改或添加代碼需要冒極大的引入新 bug 的風險,并且需要很長的時間才能 完成。

對于一個項目,維護代碼的時間可能遠遠大于編寫代碼的時間。軟體工程師可能将大部分 時間花在修複 bug、修改舊的功能邏輯和添加新的功能邏輯之類的工作上。是以,代碼的可維 護性就顯得格外重要。

對于維護、易維護和不易維護這 3 個概念,我們不難了解。不過,對于實際的軟體開發,更重要的是需要清楚如何判斷代碼可維護性的高低。

實際上,可維護性是一個難以量化、偏向對代碼整體進行評價的标準,它類似之前提到的 “好”“壞”“優雅”之類的籠統評價。代碼的可維護性高低是由很多因素共同作用的結果。代 碼簡潔、可讀性好、可擴充性好,往往就會使得代碼易維護。更深入地講,如果代碼分層清 晰、子產品化程度高、高内聚低耦合、遵守基于接口而非實作程式設計的設計原則等,就可能意味着 代碼易維護。除此之外,代碼的易維護性還與項目的代碼量、業務的複雜程度、技術的複雜程 度、文檔的全面性和團隊成員的開發水準等諸多因素有關。

2 可讀性(readability)

軟體設計專家 Martin Fowler 曾經說過:“Any fool can write code that a computer can understand. Good programmers write code that humans can understand. ”(任何人都可以編寫計算機能了解的 代碼, 而好的程式員能夠編寫人能了解的代碼。)在 Google 内部, 有一個稱為“Readability” 的認證。隻有拿到這個認證的軟體工程師,才有資格在 Code Review 的時候準許别人送出的代 碼。可見,代碼的可讀性有多麼重要,畢竟,代碼被閱讀的次數有時候遠遠超過被編寫和執行 的次數。

代碼的可讀性如此重要,在編寫代碼的時候,我們要時刻考慮代碼是否易讀、易了解。代 碼的可讀性在很大程度上會影響代碼的可維護性,因為無論是修複 bug 還是添加 / 修改功能代 碼,我們首先要讀懂代碼。如果我們對代碼一知半解,就有可能因為考慮不周而引入新 bug 。

既然代碼的可讀性如此重要,那麼我們如何評判一段代碼的可讀性呢?

我們需要檢視代碼是否符合代碼規範,如命名是否達意、注釋是否詳盡、函數長度是否合 适、子產品劃分是否清晰, 以及代碼是否“高内聚、低耦合”等。除此之外,Code Review 也是 一個很好的測試代碼可讀性的手段。如果我們的同僚可以輕松地讀懂我們寫的代碼,往往能夠 說明我們的代碼的可讀性不差;如果同僚在讀我們寫的代碼時,有很多疑問,那麼可能在提示 我們,代碼的可讀性存在問題,需要重點關注。

3 可擴充性(extensibility)

代碼的可擴充性是指在不修改或少量修改原有代碼的情況下,能夠通過擴充方式添加新功 能代碼。換句話說,代碼的可擴充性是指在編寫代碼時預留了一些功能擴充點,我們可以把新 功能代碼直接插入擴充點,而不會因為添加新的功能代碼而改動大量的原始代碼。可擴充性也 是評價代碼品質的重要标準。代碼的可擴充性表示代碼應對未來需求變化的能力。與代碼的可 讀性一樣,代碼是否易擴充也在很大程度上決定了代碼是否易維護。

4 靈活性(flexibility)

靈活性也可以用來描述代碼品質。例如, 我們經常會聽到這樣的描述:“代碼寫得很靈 活”。那麼,我們如何了解這裡提到的“靈活”呢?

盡管很多人用“靈活”描述代碼品質,但實際上,“靈活”是一個抽象的評價标準,給“靈活”下定義是很難的。不過,我們可以想一下,我們在什麼情況下才會說代碼寫得很靈活呢?

作者羅列了 3 種場景,幫助讀者了解什麼是代碼的靈活性。

1)當我們添加新功能代碼時,由于原有代碼中已經預留了擴充點,是以,我們不需要修 改原有代碼,隻需要在擴充點上添加新代碼。這個時候,我們除可以說代碼易擴充以外,還可 以說代碼寫得很靈活。

2)當我們要實作一個功能時,如果原有代碼中已經抽象出了很多位于底層且可複用的模 塊、類等,那麼我們可以直接使用。這個時候,我們除可以說代碼易複用以外,還可以說代碼 寫得很靈活。

3)當我們使用某個類時,如果這個類可以應對多種使用場景,滿足多種不同需求,那麼, 我們除可以說這個類易用以外,還可以說這個類設計得很靈活或代碼寫得很靈活。

從上述場景來看,如果一段代碼易擴充、易複用,或者易用,我們一般可以認為這段代碼 寫得很靈活。是以,“靈活”的含義寬泛,很多場景都可以使用。

5 簡潔性(simplicity)

有一條非常著名的設計原則,大部分讀者應該都聽過,那就是 KISS 原則:“Keep It Simple ,Stupid”。該原則的意思是“盡量保持代碼簡單”。代碼簡單、邏輯清晰往往意味着代 碼易讀、易維護。在編寫代碼的時候,我們往往會把“簡單、清晰”原則放到首位。

不過,很多程式設計經驗不足的程式員會覺得,簡單的代碼沒有技術含量,喜歡在項目中引入 一些複雜的設計模式,覺得這樣才能展現自己的技術水準。實際上,思從深而行從簡,真正的 程式設計高手往往能用簡單的方法解決複雜的問題。

除此之外,雖然我們都能認識到,代碼要盡量寫得簡潔,要符合 KISS 原則,但怎樣的代 碼才算足夠簡潔?怎樣的代碼才算符合 KISS 原則呢?實際上,不是每個人都能準确地做出判 斷,是以,在第 3 章介紹 KISS 原則的時候,我們會通過具體的代碼示例詳細說明。

6 可複用性(reusability)

我們可以将代碼的可複用性簡單地了解為“盡量減少重複代碼的編寫,複用已有代碼”。 在後續章節中,我們會經常提到“可複用性”這一代碼評價标準。例如,當介紹面向對象特性 的時候,我們會提到繼承、多态存在的目的之一就是提高代碼的可複用性;當介紹設計原則的 時候,我們會提到單一職責原則與代碼的可複用性相關;當介紹重構技巧的時候,我們會提到 解耦、高内聚和子產品化等能夠提高代碼的可複用性。可見,可複用性是一個重要的代碼評價标 準,也是很多設計原則、設計思想和設計模式等所要實作的最終效果。

實際上,代碼的可複用性與 DRY(Don’t Repeat Yourself)原則的關系緊密,是以,在第 3 章介紹 DRY 原則的時候,我們還會介紹代碼複用相關的更多知識,如提高代碼的可複用性的 程式設計方法等。

7 可測試性(testability

相比上述 6 個代碼品質評價标準,代碼的可測試性較少被提及,但它同樣重要。代碼的可 測試性的高低可以從側面準确地反映代碼品質的高低。代碼的可測試性低,難以編寫單元測試,那麼,基本能夠說明代碼的設計有問題。

以上内容選自《設計模式之美》

什麼樣的代碼是高品質的代碼?

谷歌前工程師小争哥代碼程式設計實戰經驗,23種常用的設計模式,追本溯源,展現高品質代碼知識,提升程式員的看家本事!

本書結合真實項目案例, 從面向對象程式設計範式、設計原則、代碼規範、重構技巧和設計模式 5 個方面詳細 介紹如何編寫高品質代碼。

第 1 章為概述, 簡單介紹了本書涉及的各個子產品, 以及各個子產品之間的聯系;第 2 章介紹面向對象程式設計範 式;第 3 章介紹設計原則; 第 4 章介紹代碼規範; 第 5 章介紹重構技巧; 第 6 章介紹建立型設計模式; 第 7 章 介紹結構型設計模式;第 8 章介紹行為型設計模式。

繼續閱讀