使用NDepend衡量程式碼的SOLID程度

陳嘉棟 發表於 2021-06-17

SOLID是物件導向的軟體開發中的5條準則,也是開發人員可以提升自己程式碼質量的準則。那麼如何衡量自己的程式碼是否符合SOLID準則呢?NDepend這款工具也許可以幫得上忙。本文將介紹一些NDepend的規則,這些規則可以幫助你來衡量你的程式碼的SOLID程度,並且提供一些可以讓你的程式碼變得更好的建議。

原文連線:Use NDepend to Measure How SOLID Your Code Is - NDepend
作者 Carlos Schults。授權翻譯,轉載請保留原文連結。

https://www.ndepend.com/

NDepend和SRP

使用NDepend衡量程式碼的SOLID程度

我們將首先處理SOLID中的“ S”:單一責任原則。這可能是SOLID原則中最容易被誤解的東西,公平地說,這似乎是有原因的。關於什麼構成責任存在一定程度的主觀性。那麼NDepend如何幫助解決這個難題呢?

避免型別過大

顧名思義,這條規則建議你保持較小的型別。保證你的類較小並不一定會使它們只承擔一種責任,但是肯定會引導事情朝著這個方向發展。

聽上去不錯,但是“太大”有多大?根據規則的文件,超過200條邏輯程式碼行的類就屬於過大了。

避免太多方法的型別

你可能會認為,鑑於前一個規則,這條規則有些多餘,但事實並非如此。 除了大量方法外,型別還可能由於其他原因而過大,例如它可能有很多其他成員,或者可能只有一個巨大的方法。

但是,按照以前的規則,我們不得不問:“太多”是多少? 該規則的文件指出,如果每種型別有20個或更多的方法則被視為擁有太多方法,並補充說,諸如建構函式,屬性和事件訪問器之類的方法不被視為計數的一部分。

避免太多欄位的型別

作為“避免太多...”系列的規則,這條規則涉及到了欄位。該規則的文件說,它針對具有15個以上欄位的型別,並且不考慮常量和只讀靜態欄位以及列舉型別。

避免過大和過於複雜的方法

在這裡,我們繼續遵循鼓勵簡化設計的規則,但是現在我們關注的是方法級別。那麼,方法的情況如何呢?我們是否只是要重複使用剛剛看到的相同規則,但是將“型別”替換為“方法”?

不,不是那麼容易。在處理方法時,事情會變得有些複雜。首先讓我們看看“避免方法過大和過於複雜”規則的文件說了些什麼:

//<b> This rule matches methods where *ILNestingDepth* > 2
</b>//<b> and (*NbLinesOfCode* > 35
</b>//<b> or *CyclomaticComplexity* > 20
</b>//<b> or *ILCyclomaticComplexity* > 60)
</b>//<b> Such method is typically hard to understand and maintain.</b>

簡而言之,該規則擔心巢狀深度大於2且也符合其他幾種條件之一的方法,例如程式碼行和迴圈複雜度。

避免使用引數過多的方法

該規則的名字已經表明了它的內容。我們真正需要做的是量化。多少是太多?

同樣,我們必須求助於文件,這次文件中描述了引數過多指的是超過8個引數。呼叫這樣的方法會十分痛苦。同樣需要注意的是,一個有很多引數的方法是否也有可能本身的邏輯已經十分冗雜,處理多個事務了呢?有這樣方法的類,應該使用單一職責原則來進行重構。

避免使用過多區域性變數的方法

終於,最後一條用來幫助你使用單一職責原則檢查自己程式碼的規則。就像之前介紹過的大多數規則一樣,這條規則的名字也說明了它的內容。並且,這條規則只需要定義它所謂的“過多”是多少。而這個問題的答案,根據文件,是15個。

通過這一節的介紹,我們大致介紹了NDepend中可以幫助你使用SOLID原則中的單一職責原則的規則。

OCP 開閉原則

使用NDepend衡量程式碼的SOLID程度

很多人認為開閉原則是所有原則中最難理解和應用的。所謂的開閉原則,指的是你的型別應該對擴充開放,但是對修改關閉。換句話說,對子類的增加一定不能導致父類的任何修改。NDEpend中的“基類不應該使用派生”規則通過指示基類永遠不要提及其子類來幫助我們防止這種情況。

LSP 里氏替換原則

使用NDepend衡量程式碼的SOLID程度

Robert Martin在一篇文章中對里氏替換原則下過如下定義:

派生類必須可以替代其基類。

當面對這樣一條定義時,一些人會認為里氏替換原則多此一舉,顯得多餘。那麼這條原則的意義是什麼呢?

好吧,這條原則的關鍵是人們一直在違反它!一種非常常見(也許是最常見)的情況是,讓一個類實現一個或多個介面,然後丟擲某種方式不適用的方法。

而NDepend恰好有一條規則可以警告你這種情況,這條規則被相當恰當地稱為“實現丟擲NotImplementedException的方法。”

你會發現,在使用TDD時,此異常最有用。這是一個非常常見的情況,如下所示:

  • 為一段程式碼編寫測試時,你將呼叫一些不存在的方法。
  • 此時編譯器會抱怨,而這是一件好事。
  • 然後你接受了Visual Studio的建議並生成了一個方法存根,因為你現在也不希望立即實現該方法。

如果你以後忘記實現該方法,則測試將失敗,而這會提醒你。

這是NotImplementedException的可接受用法。如果你使用此(或其他)異常來避免實現某個介面,那麼你將破壞LSP準則。

ISP 介面隔離原則

使用NDepend衡量程式碼的SOLID程度

介面隔離原則指的是:

不應強迫客戶端依賴於不使用的介面。

為了遵循此原理,你應該使介面儘可能的小和精細。換句話說,你應該避免介面太大,這是我們現在要討論的NDepend規則的確切名稱。

“太大”有多大?根據NDepend的文件:10。也就是說,該規則將提示具有10種以上方法的介面。

關於此規則的一件好事是,它也可以幫助你遵守之前提到過的里氏替換原則。如果使介面儘可能小,則可以降低客戶端必須提供有意義的實現的可能性。一石二鳥!

DIP 依賴反轉原則

使用NDepend衡量程式碼的SOLID程度

所謂的依賴反轉原則指的是:抽象介面不應該依賴於具體實現。而具體實現則應該依賴於抽象介面。

假設你有一個應用程式緊密耦合使用Microsoft SQL Server作為永續性解決方案。如果之後你需要更改使用另一個RDBMS,將​​會發生什麼?這注定是一個痛苦的過渡過程。

反過來,如果你的應用程式的業務邏輯甚至沒有意識到資料庫的存在(通過採用適當的體系結構是可能的),則無需進行任何更改即可進行過渡。

為了幫助您解決此問題,NDepend制定了一個規則,即“高凝聚,低耦合”。 “高凝聚,低耦合”類似於“關注點分離”,簡而言之,你希望你的軟體具有很高的內聚性(“做一件事情並做好”),同時彼此之間的耦合性也很低。

這條NDepend規則通過鼓勵你將包含抽象的名稱空間與包含具體內容的名稱空間(即所述抽象的實現)分開來幫助你實現此目的。

準備好編寫更多SOLID程式碼了嗎?

使用NDepend衡量程式碼的SOLID程度

我們上面介紹的規則只是NDepend提供的規則中的一部分。它們足以使您的應用程式符合SOLID原則嗎?當然不會。沒有任何工具或技術可以保證一定改善你的程式碼。

但是,雖然規則本身並不能自動使你的程式碼完美無缺,但它們鼓勵你編寫較小,集中且不太複雜的型別,從而為你提供極大的幫助。

除此之外,通過不斷閱讀和研究SOLID原理,適當的架構以及通用的最佳實踐和模式,你便可以正確地編寫出色的應用程式。


 

閱讀更多:

https://docs.microsoft.com/en-au/learn/?WT.mc_id=DT-MVP-5001664