《设计模式之美》笔记:规范与重构
2021-01-02 本文已影响0人
Jinglever
理解重构
- 重构是一种对软件内部结构的改善,目的是在不改变软件的可见行为的情况下,使其更易理解,修改成本更低。
- 在保持功能不变的前提下,利用设计思想、原则、模式、编程规范等理论来优化代码,修改设计上的不足,提高代码质量。
- 重构是避免过渡设计的有效手段。在我们维护代码的过程中,真正遇到问题的时候,再对代码进行重构,能有效避免前期投入太多时间做过度的设计。
- 不要等到代码烂到一定程度才去重构,持续重构是一个良好的习惯。
单元测试
- 单元测试的测试对象是类或者函数,是代码层级的测试。
- 代码的可测试性是评判代码质量的一个重要标准。
- 写单元测试的过程本身就是代码重构的过程。
- 单元测试用例实际上就是用户用例,反映了代码的功能和如何使用,有助于帮助其他人快速熟悉相关的代码。
- 写单元测试就是针对代码设计覆盖各种输入、异常、边界条件的测试用例,并将这些测试用例翻译成代码的过程。
- 依赖注入是实现代码可测试性的最有效的手段。
常见的Anti-Patterns (即测试性不好的代码)
- 未决行为:代码的输出是随机或者说不确定的,比如跟时间、随机数有关的代码。
- 全局变量
- 静态方法
- 复杂继承
- 高耦合代码
解耦
- 解耦,是保证代码不至于复杂到无法控制的有效手段。
- 如何判断代码是否需要解耦?
- 修改代码是否牵一发而动全身?
- 把模块间、类间的依赖关系画出来,看看依赖关系图是否过于复杂?
- 解耦的手段
- 封装与抽象:可以有效地隐藏实现的复杂性,隔离实现的易变性,给依赖的模块提供稳定且易用的抽象接口。
- 中间层
- 模块化:模块化思想的本质就是分而治之。
- 其他设计思想和原则
- 单一职责原则
- 基于接口而非实现变成
- 依赖注入
- 多用组合少用继承
- 迪米特法则
编码规范
- 命名
- 长度:首先要求准确达意,在此基础上越短越好。
- 利用上下文简化命名。
- 命名要可读、可搜索。
- 可读就是,得让人能读出来,比如 eyrie 这种命名,没人知道怎么读。
- 可搜索就是,整个项目有个命名习惯,比如,统一使用getxxx,不要这里用getxxx,那里用queryxxx。
- 对接口和抽象类的命名,项目内统一一下,比如:接口类都写成Ixxx。
- 注释
- 注释跟命名同等重要。
- 注释写什么?
- 目的是为了让代码更容易看懂,应包含三个方面:做什么、为什么、怎么做。
- 具体情况具体分析,简单易懂的函数,没必要写“为什么、怎么做”,但对于复杂的函数,或者一些类来说,注释起到了总结性作用、文档的作用,可以让阅读代码的人通过注释就能大概了解代码的实现思路,对阅读代码有帮助。
- 目的是为了让代码更容易看懂,应包含三个方面:做什么、为什么、怎么做。
- 注释是否越多越好?
- 通常类和函数一定要写注释,且酌情详细些。函数内部的注释相对少一些。
- 代码风格
- 类、函数多大才合适?
- 看感觉。团队项目约定。
- 一行代码多长合适?
- 看感觉。团队项目约定。
- 善用空行分割单元块。
- 四格缩进还是两格缩进?
- 团队项目约定。反正,不要用tab,因为不同的IDE下,tab的显示宽度不同。
- 大括号是否要另起一行?
- 团队项目约定。
- 类中成员的排列顺序
- emmm..在现代IDE的加持下,感觉不太所谓呢,如果追求好看就约定一下吧。(这句我说的)
- 类、函数多大才合适?
- 提高代码可读性的一些编程技巧
- 把代码分割成更小的单元块。
- 把大块的复杂逻辑提炼成类或者函数,屏蔽掉细节,让阅读代码的人不至于迷失在细节中。
- 只有代码逻辑比较复杂的时候才建议提炼。
- 避免函数参数过多。
- 处理方法:
- 考虑函数是否职责单一,能否拆分成多个函数。
- 将函数的参数封装成对象。
- 处理方法:
- 勿用函数参数来控制逻辑。
- 明显未被单一职责原则和接口隔离原则。
- (我说的)这个还是具体情况具体分析,没那么绝对。比如要写一个支持筛选获取列表的接口,筛选条件本身就会影响逻辑,但不太适合拆开,不然得写一堆函数。
- 函数设计要职责单一。
- 移除过深的嵌套层次。
- 代码嵌套过审往往是因为if-else、switch-case、for循环过度嵌套导致。
- 如果嵌套超过两层,就要思考一下能否减少嵌套。嵌套本身就不好理解,嵌套过深,不仅理解起来费劲,也会因为多次缩进影响代码整洁。
- 常见的解决思路:
- 去掉多余的if或else。
- 使用continue、break、return关键字,提前退出嵌套。
- 调整执行顺序来减少嵌套。
- 将部分嵌套逻辑封装成函数调用。
- 学会使用解释性变量。
- 常量取代魔法数字。比如:定义一个PI,替换代码里的3.1415魔法数字。
- 使用解释性变量来解释复杂表达式。
- 把代码分割成更小的单元块。
- 统一编码规范(最重要)
如何发现代码质量问题 - 常规 checklist
- 目录设置是否合理,模块划分是否清晰,代码结构是否满足“高内聚、松耦合”?
- 是否遵循经典的设计原则和设计思想(SOLID、DRY、KISS、YAGNI、LOD等)?
- 设计模式是否应用得当?是否有过度设计?
- 代码是否容易扩展?如果要添加新功能,是否容易实现?
- 代码是否可以复用?是否可以复用已有的项目代码或类库?是否有重复造轮子?
- 代码是否容易测试?单元测试是否全面覆盖各种正常和异常的情况?
- 代码是否易读?是否符合编码规范(比如命名和注释是否恰当、代码风格是否一致等)?
如何发现代码质量问题 - 业务需求 checklist
- 代码是否实现了预期的业务需求?
- 逻辑是否正确?是否处理了各种异常情况?
- 日志打印是否得当?是否方便debug排查问题?
- 接口是否易用?是否支持幂等、事务等?
- 代码是否存在并发问题?是否线程安全?
- 性能是否有优化空间,比如,SQL、算法是否可以优化?
- 是否有安全漏洞?比如,输入输出校验是否全面?