ITPUB

代码洁癖症?这 100 个技巧治好你的强迫症!

个人其它平台技术文章:

  • 知乎ID:砖一块一块搬
  • 小红书ID:码农有道

每个开发者都能写出“可以运行”的代码,但并不是每个开发者都能写出“干净”的代码。

所谓干净的代码,简单来说,就是“让人读得懂、改得动、测得好”的代码,具体而言可以从以下几个方面来理解:

  1. 易读性
  • 代码应像文章一样清晰,让别人(包括未来的自己)一眼就能理解它在做什么;
  • 变量、函数和类的命名要明确、语义清楚;
  • 逻辑层次要分明,控制结构简单直观。
  • 易修改性
    • 当需求发生变化时,可以自信地修改代码而不破坏其他部分;
    • 良好的模块化设计,功能独立,遵循单一职责原则(SRP);
    • 避免重复代码(DRY),减少修改带来的连锁反应。
  • 可测试性
    • 逻辑清晰,容易编写单元测试。
    • 数据和行为分离得当,便于模拟和验证。
  • 高内聚、低耦合
    • 相关的功能集中在一起,减少模块之间的依赖。
    • 代码结构要清楚,便于扩展和重构。
  • 简洁而不复杂
    • 实现应当尽量简单,避免炫技或不必要的复杂性;
    • 避免过早优化或实现不必要的功能。

    记住:能运行的代码只能交付功能;而干净的代码,才能构建持久的软件。

    下面我整理了 100 条实用的技巧,帮助大家写出不仅今天能跑、而且在未来依然可读、可测、可维护的代码。

    命名要干净

    在所有技巧中,命名是最容易被忽视,却最能体现代码质量的部分。一个好名字往往胜过一段注释,它能让代码一目了然,减少沟通成本,也降低后续维护的风险。下面是一些命名的建议:

    • 使用有意义的名字,并融入业务语义;
    • 避免把技术细节或实现方式写进名字里;
    • 选择便于发音、便于讨论的名字;
    • 使用便于搜索的名字,方便快速定位;
    • 避免无意义或多余的修饰词;
    • 尽量不要使用缩写;
    • 布尔变量命名时使用 is/has/should/can 等前缀;
    • 布尔变量命名避免否定形式,让逻辑更直观;
    • 在整个项目中遵循统一的命名规范;
    • 布尔变量命名应使用形容词;
    • 类名应使用名词或名词短语;
    • 保持概念与词汇的一致性,避免一个意思出现多个叫法;Image

    函数要干净

    干净的函数能让逻辑更聚焦,理解起来更轻松,不需要额外的解释。要做到这一点,可以遵循以下原则:

    • 函数名应使用动词或动词短语;
    • 保持函数简洁、精炼,行数最好控制在 8–30 行以内;
    • 避免使用过多的参数;
    • 尽量避免将布尔值作为参数传入;
    • 力求函数无副作用;
    • 使用枚举代替标志位参数;
    • 用空行分隔不同的逻辑块;
    • 如果理解一个函数的作用需要超过 30 秒,就该考虑是否应该重构它

    类要干净

    干净的类能让系统的结构更清晰,职责更明确。

    • 一个类应当只承担一项核心职责;
    • 避免出现过大的类(100 行以上往往是坏味道)
    • 力求每个类只暴露 5 个以下公共方法;
    • 将具体的小任务拆分成私有函数;
    • 按照执行流程组织函数顺序

    注释要干净

    理想的代码应该是自解释的,过多或无意义的注释不仅无益,反而会成为负担。因此,在写注释时应当遵循以下原则:

    • 能不用注释就尽量不用;
    • 不要写显而易见的内容;
    • 不要过度依赖注释;
    • 用清晰的命名代替注释;
    • 只有在解释“为什么”时才使用注释;
    • 注释还可以用于揭示隐含的行为,或用于生成 API 文档。
    Image

    测试用例要干净

    测试是代码能在生产环境长期稳定运行的重要保障。干净的测试用例能帮助我们及时发现问题,在编写测试用例时,有以下几点需要注意:

    • 使用具备场景意义的测试名称;
    • 采用 Given/When/Then 或 Should/When 的模板来组织;
    • 使用 Arrange / Act / Assert 的结构编写测试;
    • 避免在测试中使用逻辑语句(if、for、while);
    • 每个测试用例只验证一个行为;
    • 使用有意义的测试数据;
    • 隐藏无关的测试数据;
    • 编写能直接反映业务行为的断言;
    • 确保测试具有确定性(可重复、可预期);
    • 使用参数化测试消除重复;
    • 模拟第三方依赖时,更倾向于使用 fake
    Image

    测试的 F.I.R.S.T 原则

    干净的测试不仅要可读、可维护,还需要遵循一些核心原则。其中 F.I.R.S.T 原则能帮助我们判断测试是否可靠:

    • Fast(快速):测试要能快速执行;
    • Independent(独立):测试用例之间要相互独立;
    • Repeatable(可重复):测试用例应当可重复运行;
    • Self-Validating(自我验证):测试用例要能自我验证;
    • Thorough(全面覆盖):测试用例要覆盖正常路径、边界情况、异常情况、安全性以及非法输入。

    Git 提交要干净

    清晰、规范的 Git 提交历史,不仅有助于团队成员之间协作,也能在回溯问题时节省大量时间,要做到这一点,可以参考以下做法:

    • 尽早提交、频繁推送;
    • 提交信息要有意义,能够解释提交的原因;
    • 提交信息使用现在时态;
    • 在提交中附上相关的需求、任务或缺陷的参考链接
    Image

    代码坏味道要避免

    在日常开发中,应当主动识别并消除代码中的“坏味道”。这些坏味道往往是潜在问题的信号,如果不及时处理,可能会演变成维护灾难。常见的坏味道包括:

    • 使用魔数;
    • 冗长的条件判断;
    • 滥用全局变量;
    • 过长的参数列表;
    • 滥用基础类型——用丰富的类型建模业务;
    • 过深的嵌套逻辑;
    • 控制圈复杂度;
    • 难以测试的逻辑

    代码格式要统一

    保持统一的代码格式,是为了让代码更容易阅读。格式不一致虽然不一定会导致 bug,但会严重影响团队协作和整体质量。建议做到:

    • 制定团队统一的编码规范;
    • 使用自动化格式化工具;
    • 限制单行的最大长度;
    • 不要使用横向对齐;
    • 不要破坏缩进规则;
    • 在变量使用的地方就近声明

    核心原则

    要写出干净的代码,离不开一些贯穿始终的核心原则。

    • 不要重复自己(DRY):消除重复的代码;
    • 保持简单(KISS):简单可读性强的代码胜过复杂或“聪明”的代码;
    • 不要做不需要的事(YAGNI):不要提前实现当下业务用不到的功能;
    • Tell, don’t ask:让数据与逻辑绑定在一起,而不是分离;
    • 单一职责原则(SRP):模块应只因一个原因而发生变化;
    • 里氏替换原则(LSP):子类必须能够替换父类而不影响程序正常运行;
    • 接口隔离原则(ISP):将庞大的接口拆分为小而明确的接口;
    • 依赖倒置原则(DIP):高层模块不应依赖底层模块,二者都应依赖抽象;
    • 多用组合,少用继承:继承会导致强耦合,组合则更灵活;
    • 分而治之:将复杂问题拆分为更小的部分,以降低复杂度
    • 高内聚:把相关逻辑放在一起,方便查找、维护更容易;
    • 低耦合:模块之间保持独立,这样修改内部实现时,不会轻易影响到其他模块
    Image

    额外提示

    除了前面提到的,还有一些简单却非常实用的小建议,可以帮助我们在日常工作中保持代码整洁:

    • 使用带有重构工具的优秀 IDE;
    • 熟练掌握 IDE 快捷键,提高开发效率;
    • 采用基于功能的文件夹结构,避免杂乱无章;
    • 结对编程有助于保持代码整洁;
    • 删除未使用的代码——它只会成为负担;
    • 代码不只是给机器跑的,还是给人读的;
    • 可读性比“聪明”更重要;
    • 大部分情况下,可读性优先于效率;
    • 始终让代码比你接手时更干净;
    • 尽早测试、频繁测试;
    • 尽早重构、持续重构;
    • 不要只做 PR 审查,尽量做实时的代码审查;
    • 用“三次法则”来消除重复;
    • 避免使用 NULL —— 它通常是代码坏味道;
    • 能运行的代码 ≠ 干净的代码;
    • 没有测试,就不可能有干净的代码;

    Image