代码维护原则

《代码不朽》_编写客维护软件的10大原则
电子工业出版社

主要内容及体会记录如下:

一、编写短小的代码单元

1.原则
[list]
[*]代码单元的长度应该限制在15行代码以内
[*]因此首先不要编写超过15行代码的单元,或者将单元分解成多个更短的单元,直到每个单元都不超过15行代码
[*]该原则能提高可维护性的原因在于,短小的代码单元易于理解、测试及重用
[/list]

2.
代码单元是独立维护和执行的最小代码集合。在Java中,代码单元指的是方法或者构造函数。代码单元总是作为一个整体执行。
代码单元是可以被重用及测试的最小单元。

3.目的

3.1 短小的代码单元易于测试

单一原则,一个代码单元只做一件事情。相比较一个大段的代码单元,更容易测试。

3.2 短小的代码单元易于分析

条例清晰明了。不必添加多余的注释在各行代码上进行说明或备注。

3.3 短小的代码单元易于重用

代码短小,逻辑就足够简单,重复调用的可能性就很高。

4.使用

4.1 添加新的功能时

可以单独建立一个方法单元,将实现写在单元内,而将方法调用的位置放到指定的位置;
而不是直接在调用的方法内写功能。

好处:
如果有一天被告知此功能暂时不需要上线,避免注释掉大段的代码;只需要把调用该方法的位置注释掉即可。
单一原则,不互相干涉。如果几个方法都对同一个对象进行修改,就会出现各种问题;避免同名变量

4.2 代码书写完毕后的重构

4.2.1 提取方法

将几行实现一个功能的代码,抽取出来,作为一个独立的代码单元;

4.2.2 在方法内部使用对象

当方法的参数数量多于4个时,将参数抽象成一个对象
既减少传入参数的数量(避免类型、位置对应不上的问题)也减少方法内部的处理

二、编写简单的代码单元

1.原则

[list]
[*]限制每个代码单元分支点的数量不超过4个
[*]将复杂的代码单元拆分成多个简单的代码单元,避免多个复杂的单元在一起
[*]分支点越少,代码单元越容易被修改和测试
[/list]

2.代码测试

功能覆盖率,代码编写完毕后要进行初步的测试,测试的原则就是要覆盖每个分支
减少分支数量,就是在一定程度上减少测试成本及时间

3.使用

3.1 分支包括
[list]
[*] if else
[*] switch case default
[*] a > b ? a : b
[*] && ||
[*] for while
[*] try catch finally
[/list]

3.2 减少else

使用return ,
比如:判断某集合不空,就进行某种处理。
if(CollectionUtils.isEmpty(list))
return ;
空了就不处理,也就不需要else

能够减少好多代码且条例清晰

3.3 抽象对象

比如:多个分支,多个参数处理、switch 的 各个case 的处理逻辑基本相同且参数很多

将参数抽象成对象,然后对此对象进行处理

三、不写重复代码

1.原则

[list]
[*]不要复制代码
[*]编写可重用的、通用的代码、并且或者调用已有的代码
[*]如果复制代码,就需要在多个地方修改Bug
[/list]

2.
复制代码似乎能够快速完成目标,既然代码都有了,何必要再写一遍?复制会导致代码重复出现,而冲农夫代码就是问题的根本所在。

3.目的

3.1 重复代码更加难以分析

3.2 代码重复更加难以修改

4.使用

提取方法,在代码开发过程中或开发完毕后,尝试将各个功能拆分,找出共同点

四、保持代码单元的接口简单

1.原则

[list]
[*]限制每个代码单元的参数不能超过4个
[*]将多个参数提取成对象
[*]较少的参数可以让代码单元更容易理解和重用
[/list]

2.目的

2.1 短接口更易于理解和重用

2.2 短接口的方法更易于修改


五、分离模块之间的关注点

1.原则

[list]
[*]避免形成大型模块,以便能达到模块之间的松耦合
[*]将不同职责分给不同的模块,并且隐藏接口内部的实现细节
[*]该原则能提高可维护性的原因在于,相比起紧耦合的代码库来说,对松耦合代码库的修改更容易监督和执行
[/list]

2.针对于如何提高系统中单个代码单元的可维护性

3.目的

3.1 小型、松耦合的模块允许开发人员独立进行工作

3.2 小型、松耦合的模块降低了浏览代码库的难度

3.3 小型、松耦合的模块避免了让新人感到手足无措

4.使用

4.1 根据不同关注点拆分类

举例:
一个用户接口
第一次开发:用户信息的增加、删除、修改、查询
第二次开发:用户信息通知接口
第三次开发:用户锁定接口

完全放在一个接口文件中时,代码量过大,且不易维护

建议:按照不同的关注点,拆分成多个接口

4.2 隐藏接口背后的特定实现

举例:
普通相机类:基本功能
高级相机类:如果为了兼容高级相机提供的特定功能,而扩充普通相机方法中的功能,就会显得代码过多

建议:抽象出接口,普通相机与高级相机分别实现接口,高级相机中添加特定的方法

调用接口时,利用多态的原理,保证调用的对象不同

六、架构组件松耦合

1.原则

[list]
[*]顶层组件之间应该做到松耦合
[*]尽可能减少当前模块中需要暴露给(例如,被调用)其他组件中模块的相关代码
[*]独立的组件可以单独进行维护
[/list]

2.举例

层与层之间设计中给的单向依赖

用户接口 --》 服务层 --》 业务逻辑层 --》 数据抽象层 --》 数据库层

如果相互之间调用混乱了,对于后续维护就不方便

如 用户接口直接调用 数据抽象层的接口

3.目的

3.1 低组件以来允许独立的维护

3.2 低组件依赖可以分离维护职责

4.使用

4.1 限制作为组件接口的模块的大小

4.2 在更高的抽象层次上来定义组件接口,这是为了限制跨越组件边界的请求类型,避免请求了解太多的实现细节

4.3 避免使用透传调用,即接收传入调用,又同时代理给其他组件。那么此时接口要同时为两个不同的组件进行服务,违反单一职责原则。

七、保持架构组件之间的平衡

1.原则
[list]
[*]平衡代码中顶层组件的数量和体积
[*]保持源代码中组件的数量接近于9,并且这些组件的体积基本一致
[*]该原则能提高可维护性的原因在于,平衡的组件可以帮助定位代码,并且允许独立对组件进行维护
[/list]


2.目的

2.1 好的组件平衡能让查找和分析代码变得更加容易

2.2 好的组件平衡能隔离维护所带来的影响

2.3 好的组件平衡能够分离维护职责

3.使用

3.1 顶层系统组件个数在理想状态下应为9个,通常来说位于 6 到 12 个 之间

3.2 各个组件的代码量应该大致相同

八、保持小规模代码库

1.原则

[list]
[*]保持代码库规模尽可能小
[*]控制代码库增长,并主动减少代码库的体积
[*]拥有小型的代码、项目和团队是成功的一个因素
[/list]

2.解释

代码库时存储在一个仓库中的所有源代码的集合,可以独力地进行编译和部署,并且由一个团队进行维护。

3.目的

3.1 以大型代码库为目标的项目更容易失败

3.2 大型代码库更加难以维护

3.3 大型系统会出现更密集的缺陷

4.使用

4.1 功能层面的方法

4.1.1 控制需求蔓延

项目开发过程中,需求不断增加,不断的迭代,有些需求看上去高大上,其实,实际应用中的效果不是很好,或者说反而会拖累当前的系统,那这样的需求的上线价值与以后的系统维护成本之间要做好权衡。

4.1.2 功能标准化

将功能实现代码标准化;底层实现的方式基本相同,可重用性的代码会增加

4.2 技术层面的方法

4.2.1 不要复制粘贴代码

复制粘贴,就说明代码可单独抽出一个方法;同时如果出现问题,同样的错误不用修改很多次;

4.2.2 重构已有代码

增加可维护性,减小代码体积

4.2.3 使用第三方库和框架

九、自动化开发部署和测试

1.原则

[list]
[*]对你的代码进行自动化测试
[*]通过使用测试框架来编写自动化测试
[*]自动化测试让开发过程可预测并且能够降低风险
[/list]

2.目的

2.1 自动化测试让测试可以重复

2.2 自动化测试会让开发更有效率

2.3 自动化测试让代码行为可预测

2.4 测试是对被测试代码的一种说明文档

2.5 编写测试能让你编写更好的代码

测试驱动开发,若一个方法内部实现了多个功能,那么测试用例就要考虑多种分支可能,所以为了方便测试,就会考虑如果将方法按照功能点进性拆分

3.使用

3.1 Junit 测试入门

3.2 编写良好单元测试的基本原则

3.2.1 正常情况和特殊情况都要进行测试

3.2.2 像维护非测试代码一样维护测试代码

3.2.3 编写独立的测试,他们的输出应该只反映被测试主体的行为

3.3 测试覆盖率来确定是否有足够的测试用例

覆盖率:指的是单元测试中执行的代码行数占代码库总行数的百分比。

通常80%以上。

十、编写简洁的代码

1.原则

[list]
[*]编写简洁的代码
[*]不应该在完成开发工作后留下代码坏味道
[*]简洁的代码是可维护的代码
[/list]

2.使用

2.1 不要编写单元级别的代码坏味道

忌:过长的代码单元;复杂的代码单元;长接口的代码单元

2.2 不要编写不好的注释

取消代码行内的注释;

代码远离注释;

不要为了注释而去写注释,每行代码上都有一行注释;而是必要的位置才去写注释

2.3 不要注释代码

版本控制上会留有一份旧的代码,所以不要留有注释的代码;

注释的代码对于一个新人来说就是一个具有挑战性的问题:
为什么前面的那个哥们把它注释掉了,是一个坑还是一个雷?我要不要试着修复它,万一出问题了怎么办?要不把它留着,留给后面的接班人?最好还是不动了,免得惹祸上身。

2.4 不要保留费期代码

方法中无法到达的代码

无用的私有方法

注释中的代码:避免在注释中使用代码

2.5 不要使用过长的标识符名称

避免:
使用表示多个职责的:generateConsoleAnnotataionScriptAndStylesheet
包含过多技术术语:GlobalProjectNamingStrategyConfigure

2.6 不要使用魔术常量

代码中不要出现数字,所有的数字均可用常量代替

2.7 不要使用为正确的处理的异常

2.7.1 捕获一切异常。

2.7.2 捕获特定异常。
在特定的调用地方,要对相应的异常进行指定捕获。

2.7.3 在展示给终端用户之前,先将特定的异常系想你转换成通用的信息

十一、后续

将原则变成实践

低层级(代码单元)原则要优于高层级(组件)原则
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值