SOLID是面向对象的软件开发中的5条准则,也是开发人员可以提升自己代码质量的准则。那么如何衡量自己的代码是否符合SOLID准则呢?NDepend这款工具也许可以帮得上忙。本文将介绍一些NDepend的规则,这些规则可以帮助你来衡量你的代码的SOLID程度,并且提供一些可以让你的代码变得更好的建议。

原文连接:Use NDepend to Measure How SOLID Your Code Is - NDepend
作者 Carlos Schults。授权翻译,转载请保留原文链接。

https://www.ndepend.com/

NDepend和SRP

我们将首先处理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中的“基类不应该使用派生”规则通过指示基类永远不要提及其子类来帮助我们防止这种情况。

LSP 里氏替换原则

Robert Martin在一篇文章中对里氏替换原则下过如下定义:

派生类必须可以替代其基类。

当面对这样一条定义时,一些人会认为里氏替换原则多此一举,显得多余。那么这条原则的意义是什么呢?

好吧,这条原则的关键是人们一直在违反它!一种非常常见(也许是最常见)的情况是,让一个类实现一个或多个接口,然后抛出某种方式不适用的方法。

而NDepend恰好有一条规则可以警告你这种情况,这条规则被相当恰当地称为“实现抛出NotImplementedException的方法。”

你会发现,在使用TDD时,此异常最有用。这是一个非常常见的情况,如下所示:

  • 为一段代码编写测试时,你将调用一些不存在的方法。
  • 此时编译器会抱怨,而这是一件好事。
  • 然后你接受了Visual Studio的建议并生成了一个方法存根,因为你现在也不希望立即实现该方法。

如果你以后忘记实现该方法,则测试将失败,而这会提醒你。

这是NotImplementedException的可接受用法。如果你使用此(或其他)异常来避免实现某个接口,那么你将破坏LSP准则。

ISP 接口隔离原则

接口隔离原则指的是:

不应强迫客户端依赖于不使用的接口。

为了遵循此原理,你应该使接口尽可能的小和精细。换句话说,你应该避免接口太大,这是我们现在要讨论的NDepend规则的确切名称。

“太大”有多大?根据NDepend的文档:10。也就是说,该规则将提示具有10种以上方法的接口。

关于此规则的一件好事是,它也可以帮助你遵守之前提到过的里氏替换原则。如果使接口尽可能小,则可以降低客户端必须提供有意义的实现的可能性。一石二鸟!

DIP 依赖反转原则

所谓的依赖反转原则指的是:抽象接口不应该依赖于具体实现。而具体实现则应该依赖于抽象接口。

假设你有一个应用程序紧密耦合使用Microsoft SQL Server作为持久性解决方案。如果之后你需要更改使用另一个RDBMS,将​​会发生什么?这注定是一个痛苦的过渡过程。

反过来,如果你的应用程序的业务逻辑甚至没有意识到数据库的存在(通过采用适当的体系结构是可能的),则无需进行任何更改即可进行过渡。

为了帮助您解决此问题,NDepend制定了一个规则,即“高凝聚,低耦合”。 “高凝聚,低耦合”类似于“关注点分离”,简而言之,你希望你的软件具有很高的内聚性(“做一件事情并做好”),同时彼此之间的耦合性也很低。

这条NDepend规则通过鼓励你将包含抽象的命名空间与包含具体内容的命名空间(即所述抽象的实现)分开来帮助你实现此目的。

准备好编写更多SOLID代码了吗?

我们上面介绍的规则只是NDepend提供的规则中的一部分。它们足以使您的应用程序符合SOLID原则吗?当然不会。没有任何工具或技术可以保证一定改善你的代码。

但是,虽然规则本身并不能自动使你的代码完美无缺,但它们鼓励你编写较小,集中且不太复杂的类型,从而为你提供极大的帮助。

除此之外,通过不断阅读和研究SOLID原理,适当的架构以及通用的最佳实践和模式,你便可以正确地编写出色的应用程序。


阅读更多:

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

使用NDepend衡量代码的SOLID程度的更多相关文章

  1. 代码整洁 vs 代码肮脏

    写出整洁的代码,是每个程序员的追求.<clean code>指出,要想写出好的代码,首先得知道什么是肮脏代码.什么是整洁代码:然后通过大量的刻意练习,才能真正写出整洁的代码. WTF/mi ...

  2. [代码质量] 代码质量管控 -- 复杂度检测 (JavaScript)

    转载自: https://juejin.im/post/59bb8b546fb9a00a4247532e 背景 代码的复杂度是评估一个项目的重要标准之一.较低的复杂度既能减少项目的维护成本,又能避免一 ...

  3. 高效完成R代码

    为什么R有时候运行慢? 参考https://www.cnblogs.com/qiaoyihang/p/7779144.html 一.为什么R程序有时候会很慢? 1.计算性能的三个限制条件 cpu ra ...

  4. 华为Java编程军规,每季度代码验收标准

    引言: 这个标准是衡量代码本身的缺陷,也是衡量一个研发人员本身的价值. 军规一:[避免在程序中使用魔鬼数字,必须用有意义的常量来标识.] 军规二:[明确方法的功能,一个方法仅完成一个功能.] 军规三: ...

  5. 深入理解javascript---如何编写高质量的代码?

    如何书写可维护的代码? 最小全局变量 JavaScript通过函数管理作用域.在函数内部声明的变量只在这个函数内部,函数外面不可用.另一方面,全局变量就是在任何函数外面声明的或是未声明直接简单使用的( ...

  6. 深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点

    深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点 2011-12-28 23:00 by 汤姆大叔, 139489 阅读, 119 评论, 收藏, 编辑 才华横溢的 ...

  7. 高质量JavaScript代码书写基本要点

    翻译-高质量JavaScript代码书写基本要点 by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/ ...

  8. 【转】华为Java编程军规,每季度代码验收标准

    引言: 这个标准是衡量代码本身的缺陷,也是衡量一个研发人员本身的价值. 军规一:[避免在程序中使用魔鬼数字,必须用有意义的常量来标识.] 军规二:[明确方法的功能,一个方法仅完成一个功能.] 军规三: ...

  9. 阅读Google的C++代码规范有感

    李开复曾在微博上说过,Google的C++代码规范是全球最好的一份C++代码规范,没有之一.最近花了点时间看了下这份代码规范,收获确实很大,在编程过程中一些乱七八糟的坏习惯也该改一改了.最新的英文版见 ...

随机推荐

  1. Windows核心编程 第四章 进程(中)

    4.2 CreateProcess函数 可以用C r e a t e P r o c e s s函数创建一个进程: BOOL CreateProcessW( _In_opt_ LPCWSTR lpAp ...

  2. 神经网络与机器学习 笔记—支持向量机(SVM)(上)

    支持向量机(SVM)的主要思想: 给定训练样本,支持向量机建立一个超平面作为决策曲面,使得正例和反例之间的隔离边缘被最大化. 线性可分模式的最优超平面 训练样本{(xi,di)}^N i=1 ,其中x ...

  3. IntelliJ IDEA打开Maven项目,Spring boot所有依赖红名,不可用

    导入外部的springboot项目时,出现报红线,无论怎么刷新maven就是不下载依赖包,情况如下 解决办法: 1)直接去自己的maven仓库,找到Spring boot,然后直接删除下面的文件 2) ...

  4. 一些代码小技巧&经典代码

    请说明逻辑与(&&)在下边表达式中起到的重要作用 count != 0 && sum/count 答:该表达式使用逻辑与(&&)来确保 sum/coun ...

  5. MySQL连接本地服务器

    1.打开"控制面板" 2.搜索"管理工具",并点击第一个"管理工具" 3.双击"服务" 4.找到"MySQL& ...

  6. OOP第二章博客

    OO第二次博客作业 (1)作业分析 三次作业在处理多线程的协同配合时都是使用将同步放在自己写的"线程安全类"(经测试有些许漏洞_,但是不影响结果就是了): 我个人倾向于把wait( ...

  7. JAVA基础——包机制

    包机制 包的语法格式package pkg1[.pkg2[.pkg3...]] 一般利用 公司域名倒置 作为包名; 例如www.baidu.com,则建立报的名字com.baidu.www 一般不要让 ...

  8. golang:TCP总结

    在TCP/IP协议中,"IP地址+TCP或UDP端口号"唯一标识网络通讯中的一个进程."IP地址+端口号"就对应一个socket.欲建立连接的两个进程各自有一个 ...

  9. [刷题] 209 Minimum Size Subarray Sum

    要求 给定一个含有 n 个正整数的数组和一个正整数 s 找出该数组中满足其和 ≥ s 的长度最小的连续子数组 如果不存在符合条件的连续子数组,返回 0 示例 输入:s = 7, nums = [2,3 ...

  10. 005.Python条件if语句

    一  流程控制 流程控制的定义 流程:代码执行的过程 流程控制:对代码执行过程的管控 流程控制三大结构: 顺序结构:从上到下,代码依次执行 分支结构: 一共4个 循环结构:while for 分支结构 ...