【软件构造】第四章第一节 面向可理解性的构造

第四章第一节 面向可理解性的构造

Outline

  • 代码可理解性
  • 编码规范

Notes

## 代码的可理解性

代码的可理解性能够理解为代码的可读性。具体来讲,可从如下几个方面来看:java

  • 是否遵循特定的命名规范?
  • 是否足够的注释/说明?
  • 是否足够的内聚性?
  • 方法是否太长或过短、是否容易理解?

【代码质量测量:WTFs / min】程序员

  简单来讲,好的代码让人更容易理解,其余程序员在阅读时就会发出更少的WTF(What the fuck)来抱怨你的代码质量,而很差的代码则更加让人暴躁抓狂。函数

【标识符名称长度】布局

标识符的长度包含类名、变量名、方法名等的长度。主要看如下方面性能

  • 是否具备自描述性?不看注释就能够理解其含义
  • 是否足够简洁?太长的变量名下降效率

度量方式:全部标识符的平均长度。测试

【命名独特性比例(UNIQ)】编码

  当两个实体名称相同时,它们可能会混合在一块儿。 UNIQ衡量全部名字的独特性。在许多地方使用相同的名称是能够接受的。 然而,这个名字应该是指一样的逻辑事物。spa

【代码复杂度和代码行数】3d

复杂的代码不可能被理解。 
一个方法越长,它可能越难理解。code

【注释的密度 MCOMM%】

代码中的注释越多,阅读和理解越容易。

【如何编写易于理解的代码】

  • 遵循命名规范
  • 限制代码行的最大长度、文件的最大LoC
  • 足够的注释
  • 代码有好的布局:缩进、空行、对其、分块、等。
  • 避免多层嵌套—增长复杂度
  • 文件和包的组织

代码的可读性/可理解性不少时候比效率/性能更重要,不可读、不可理解代码可能蕴含更多的错误。 所以先写出可读易懂的代码,再去逐渐调优!

【可读性强的语句的栗子】

Example A:z = ((3*x^2) + (4*x) - 5) - (( 2*y^2) - (7*y) + 11) / ((3*x^2) + (4*x) - 5)

Example B:a = (3*x^2) + (4*x) - 5; b = ( 2*y^2) - (7*y) + 11; z = (a - b) / a

B的代码可读性强于A

 

## 编码规范 

  • 编码规范:定义了一系列的规则,按这些规则进行编码,有助于提高代码可读性,例如—— 命名、代码布局/缩进、数据声明方式、文件组织方式 、etc。

【命名】

  • 变量,函数或类的名称应告诉你,它为何存在,它作了什么以及如何使用它。 
  • 若是名称须要注释,则名称没必要显示意图:
    int d; // elapsed time in days 
    int elapsedTimeInDays; 
    int daysSinceCreation;
  • 须要注意一下内容:
    • 避免造假:避免留下模糊代码含义的虚假线索。例如仅当accountList实现List时才使用accountList; 其余状况下accounts更好。
    • 作出有意义的区别
    • 使用可发音名称
    • 使用可搜索的名称
  • 命名规范:
    • 包名称应该是小写的;
    • 类和接口名称应该是名词和大写;
    • 方法名称应该是动词并以小写开始;
    • 常量命名:全部大写字母之间带下划线;
    • 参数命名,确保你的参数意味着什么。

行数限制】

  • 限制每一行的长度;
  • 每个方法大概三十行,在一页内实现;
  • 每个文件大概200行,最多不超过500行。

【垂直格式化:空行】  

 

  • 单行空行
    • 在局部变量声明 和 方法中的第一个代码之间
    • 在块注释以前
    • 在代码的逻辑段之间提升可读性
  • 双行空行
    • 在方法之间
    • 在类和接口声明之间
    • 在源文件的任何其余部分之间
  • 垂直密度意味着密切关联,所以密切相关的代码行应该垂直密集。
  • 密切相关的概念应该保持垂直相互靠近。
  • 他们的垂直分离应该衡量每一个人对另外一我的的可理解性有多重要。

【横向格式化:空格】

  咱们使用水平空白区域来关联强烈关联的事物,并将与强调它们的关系更加微弱的事物分开。

【横向格式化:缩进】

  代码必须根据其嵌套级别进行缩进。你能够选择缩进量,但应该保持一致。很差的缩进会使程序难以阅读,也可能成为一个难以理解的错误来源。

【横向格式化:换行】

  当一个表达式不适合单独一行时,根据如下通常原则将它换行:

  • 逗号后换行
  • 在操做符前换行
  • 将新行与上一行中相同级别的表达式的开头对齐。

【文件组织】

  • 在源文件中的顺序:
    • 包或文件级别的注释
    • 包和导入的说明
    • public的类和接口的声明
    • private的类和接口的声明
  • 导入说明的顺序:
    • 标准包(java.io, java.util, etc
    • 第三方包(例如com.ibm.xml.parser )
    • 你本身的包
  • 类部分的顺序:
    • Javadoc 注释
    • 类声明的说明
    • 整个类的注释
    • 类静态变量声明(public,protected,package,private)
    • 类实例变量声明(public,protected,package,private)
    • 函数声明(构造函数优先)
  • Principles of Package:
    • 复用/发布等价原则(REP)
      • 复用的粒度应等价于发布的粒度
      • 粒度:粒度大的复杂度大,粒度小的能够高度重用。
    • 共同封闭原则(CCP) 
      • 一个包中的全部类针对同一种变化是封闭的;
      • 一个包的变化将会影响包里全部的类,而不会影响到其余的包;
      • 若是两个类紧密耦合在一 起,即两者老是同时发生变化,那么它们就应属于同一个包。
    • 共同复用原则(CRP) 
      • 一个包里的全部类应 被一块儿复用;
      • 若是复用了其中一个类,那么就应复用全部的类
  • Principles of Package Coupling:
    • 无圈依赖原则 (ADP) 
      • 不容许在包依赖 图中出现任何圈/回路;
      • 无圈将容易进行测试、维护与理解;
      • 若存在回路依赖,很难预测该包的变化将会如何影响其余包。
      • 消除圈的两种方式:建立新包和利用DIP<依赖倒置原则>和ISP<接口隔离原则>。 
        • 建立新包 
        • 利用DIP<依赖倒置原则>和ISP<接口隔离原则> 
    • 稳定依赖原则(SDP) 
      • 包之间的依赖关系只能指向稳定的方向;
      • 被依赖者应更稳定于依赖者;
      • 稳定的包较难发生改变;
      • 若是不稳定的包却被不少其余包依赖,会致使潜在的问题。 

         

    • 稳定抽象原则(SAP) 
      • 在稳定性与抽象度之间创建关联;
      • 一个包是稳定的,那么它就应该尽量抽象;
      • 一个彻底稳定的包中只应包含抽象类;
      • 不稳定的包应是具体的,以便于容易的进行修改。
  • SAP与SDP比较:
    • SAP和SDP共同构成了包之间的“ 依赖倒置原则DIP”;
    • SDP: 依赖应指向稳定的方向,SAP: 稳定性隐含着抽象;
    • 所以,依赖应指向抽象的方向。