《设计模式之美》笔记:规范与重构

理解重构

  • 重构是一种对软件内部结构的改善,目的是在不改变软件的可见行为的情况下,使其更易理解,修改成本更低。
  • 在保持功能不变的前提下,利用设计思想、原则、模式、编程规范等理论来优化代码,修改设计上的不足,提高代码质量。
  • 重构是避免过渡设计的有效手段。在我们维护代码的过程中,真正遇到问题的时候,再对代码进行重构,能有效避免前期投入太多时间做过度的设计。
  • 不要等到代码烂到一定程度才去重构,持续重构是一个良好的习惯。


单元测试

  • 单元测试的测试对象是类或者函数,是代码层级的测试。
  • 代码的可测试性是评判代码质量的一个重要标准。
  • 写单元测试的过程本身就是代码重构的过程。
  • 单元测试用例实际上就是用户用例,反映了代码的功能和如何使用,有助于帮助其他人快速熟悉相关的代码。
  • 写单元测试就是针对代码设计覆盖各种输入、异常、边界条件的测试用例,并将这些测试用例翻译成代码的过程。
  • 依赖注入是实现代码可测试性的最有效的手段。


常见的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、算法是否可以优化?
  • 是否有安全漏洞?比如,输入输出校验是否全面?

你可能感兴趣的:(《设计模式之美》笔记:规范与重构)