代码维护原则

《代码不朽》_编写客维护软件的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 在展示给终端用户之前,先将特定的异常系想你转换成通用的信息

十一、后续

将原则变成实践

低层级(代码单元)原则要优于高层级(组件)原则
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值