vlambda博客
学习文章列表

提高代码质量的Tips

及时获取有趣有料的技术文章

本文来源:http://r6d.cn/HPg4

1. 如何重构

1.1 为什么要重构代码?

重构是一种对软件内部结构的改善,目的是在不改变软件的可见行为的情况下,使其更易理解,修改成本更低。

即 重构是指保持功能不变的前提下,利用设计思想、原则、模式和编程规范等理论来优化代码,修改设计上的不足,提高代码的质量。

如果没有维护,物体势必会往熵增加的方向去演变的。如果不做代码的维护,代码总归会往越来越混乱的方向演进,当混乱到一定程度,量变引起质变,项目的维护成本已经高过了重新开发一套新代码的成本,再去重构就会变得十分困难了。

1.2 重构的对象

  • 大型重构

    • 包括
    • 重构的手段
    • 系统
    • 模块
    • 代码结构
    • 类与类之间的关系
    • 分层
    • 模块化
    • 解耦
    • 抽象可复用的组件
    • 对顶层代码设计的重构
  • 小型重构

    • 对于代码细节的重构
    • 针对类,函数,变量等代码级别的重构

1.3 什么时候重构?

持续重构的概念,即没事情的时候,看看项目中有哪些写得不够好,可以优化的代码,主动去重构一下。或者在修改添加某个功能代码的时候,也可以顺手把不符合编码规范,不好的设计重构一下。

1.4 如何解耦代码?

  • 解耦的目的
    • 高内聚
    • 松耦合
  • 为什么需要解耦
    • 控制代码的复杂性
    • 使得我们可以聚焦在某一模块或类当中,不需要了解太多其他模块或类的代码
    • 使得代码改动相对集中,引入bug的风险就减少了很多
  • 如何判断是否需要解耦
    • 在做修改的时候是否需要跨很多个包来进行改动
    • 需要通过解耦的方式让依赖关系变得清晰,简单一些
  • 如何进行解耦
    • 单一职责原则
    • 基于接口而非实现编程
    • 依赖注入
    • 多用组合少用继承
    • 迪米特法则
    • 不应该有直接依赖关系的类
    • 对于一个大型复杂系统来说,没有人能够掌控所有细节
    • 通过划分成不同的独立模块,让不同的人负责不同的模块
    • 这样即便在不了解全部细节的情况下,管理者也能够协调各个模块,让整个系统有效运转起来
    • 将每个模块都当做一个独立的library来进行开发,只提供封装了内部实现细节的接口给其他模块使用,以此来减少不同模块之间的耦合度
    • 引入中间层能够简化模块或类之间的依赖关系
    • 即我们可以让开发和重构同步进行
    • 例如需要进行接口的修改
    • 先引入一个中间层,包裹老的接口,提供新的接口定义
    • 新开发的代码依赖中间层提供的新接口
    • 将依赖老街口的代码改为调用新接口
    • 确保所有的代码都调用新接口之后,删掉老接口
    • 有效隐藏实现的复杂
    • 隔离实现的易变性
    • 给依赖的模块提供稳定易用的抽象接口
    • 封装与抽象
    • 引入中间层
    • 模块化
    • 遵循设计思想和原则

2. 代码的可测试性

做重构,如何保证你做的改动能够按照既定的想法运行,那么我们需要来写单元测试,来保证新的代码仍然能够通过,即原有的逻辑的正确性没有被破坏。

另外,单元测试的阅读实际上是快速熟悉代码的一种方式

一些常见的Anti-patterns:

  • 未决行为
    • 代码的输出是随机的,或者不确定的
  • 全局变量
  • 静态方法
  • 复杂继承
  • 高耦合代码

3. 编程规范

3.1 命名与注释

  1. 在足够表达含义的情况下,命名尽量短

命名时候的缩写,只对大家比较熟知的使用,减少阅读时候的障碍的感觉。

  1. 利用上下文简化命名

比如POJO当中,类名往往对这是个什么类做了定义了,成员变量就不用再添加类前缀了

  1. 命名需要可读,可搜索

英文上可读,方便发音,哪怕是第一次见到,也需要尽可能简单的能够直接读出来

另外需要遵从一些大家约定俗成的规范,即比如使用selectXXX 还是queryXXX 来表示选择,从数据库里面拿东西,一旦选定,就需要一起遵从规定了。

  1. 对于接口,抽象类的命名
  • 对于接口的命名
    • 加前缀I,比如IUserService
    • 或者加后缀Impl, UserServiceImpl
  • 抽象类的命名
    • 加上前缀Abstract
    • 或者不带

皆可,但是需要形式上的统一。

  1. 注释
  • 目的
    • 让代码更容易看懂
  • 写什么
    • 是什么,为什么,怎么办 三大问题
    • 能够起到总结性和文档的作用
    • 总结性注释也能够让整个代码更加清晰
  • 在哪里写
    • 一般来说是在类和函数上写注释
    • 函数内部尽量通过好的命名,提炼函数,解释性的变量来提高代码的可读性

3.2 代码风格

  1. 类和函数的大小

软标准,只是要尽量注意,对于很大的类,最好将其分割开

  1. 一行代码的长度的限制,譬如100字符或者150字符
  2. 使用空行分割单元块
  • 对于比较长的函数,如果逻辑上可以分为几个独立的代码块,可以使用空行来分割各个代码块
  • 在类的成员变量和函数之间
  • 静态成员变量和普通成员变量之间
  • 各个函数之间
  • 各个成员变量之间
  1. 缩进风格的统一
  2. 类当中成员的排列顺序
  • 首先是类的所属包名
  • 然后罗列import引入的依赖类
  • 类当中
    • 先静态,后普通
    • 作用域从大到小来排序
    • 大原则
    • 成员变量
    • 各种方法

3.3 编程技巧

  1. 将代码分割为更小的单元块

大部分人阅读代码的习惯都是先看整体再看细节,因为我们要有模块化和抽象思维,善于将大块的负责逻辑提炼成类或者函数,屏蔽掉细节

通过提炼函数,通过函数名字,直接读懂这段代码是做什么用的

  1. 避免函数参数过多
  • 考虑函数是否职责单一,能否通过拆分多个函数的方式来减少参数
  • 将函数的参数封装成对象
  • 不要使用函数的参数(true/ false) 来控制逻辑,直接分成几个不同的函数会更好
  1. 函数的设计,职责单一
  2. 移除过深的嵌套层次
  • 去掉多余的if else语句
  • 使用continue break return等关键字,来提前退出嵌套
  • 调整执行顺序来减少嵌套
  • 将部分嵌套逻辑封装成函数调用,以此来减少嵌套
  1. 使用解释性变量
  • 常量替代magic number
  • 使用解释性变量来解释复杂表达式


墙裂推荐

【深度】互联网技术人的社群,点击了解!




如果资源对你有帮助的话

       
         
         
       
❤️ 给个 「在看」 ,是最大的支持❤️