如何代码整洁

什么是整洁的代码

代码的整洁和代码能否运行无关,作为开发者每天都要花费大量时间去阅读代码,如果代码的整洁度不够,会导致浪费大量的时间和生产力,并且糟糕的代码会导致整个代码库的死亡,因为没有人能完全理解掌控。

归根结底,它是可读和可理解的有意义的代码。这可以减轻必须经历的认知负担,认知负担会更小,整洁的代码确保项目的可维护性,是别人可以理解代码,作为开发者应该把自己的代码当做一篇好故事,一篇文章。确保代码是易于理解的,有趣的。

关键痛点&如何去做

痛点

命名:变量、函数、类

代码格式化:格式化、注释

函数:代码量,参数数量

条件语句:深嵌套、没有错误处理

类、数据结构:没有保持区别和数据结构分隔、臃肿的类

解决方案

  • 规则和概念
  • 模式和原则
  • 测试驱动开发

强类型语言能够帮你预防错误和提高代码的可读性,但这不是必须的,不使用类型一样可以编写出可读性强的代码

干净的架构和干净的代码的关系:干净的代码是专注于如何编写代码,如何去编写一段程序或一个文件,而干净的架构更加专注于架构的依赖,数据的存储,代码的分发,但是要实现干净的架构同样也依赖干净的代码

编写整洁的代码是一个渐进的过程,没有人能一开始就编写出最好的代码,随着项目的不断修改,迭代,功能的增加,需要不断添加新功能和旧功能一起实施,同时也是一个不断重构的过程,重构是一件非常正常的事,是在开发中要做的事情,不断地更新重构和质疑代码,明天就会有更好的代码,也会大大加快项目构筑的速度,如果一直写脏代码,随着时间项目将逐渐难以维护,添加新功能和修复bug也会越来越难

命名

为什么命名重要

名字应该有意义

对一个事情有好的命名可以在不了解全部细节的情况知道功能

命名形式

下划线命名法、蛇形命名法 驼峰式命名法 帕斯卡命名法、大驼峰命名法 短横线命名
范例 snake_case camelCase PascalCase kebap-case
规则 下划线连接,全部小写 首单词小写,后续全部单词首字母大写 所有单词首字母大写 短横线连接,全部小写
适用范围 变量、函数、方法 变量、函数、方法 自定义html元素

命名形式只是约定的惯例,和本身代码质量没有关系,用哪种都可以,但是得确保和语言本身契合,这也是需要注意的一点

如何命名

变量、常量、属性:微小的数据容器,使用带形容词的名词或短语

// Object
user
authenticatedUser
database
sqlDatabase
// Number or String
name
firstName
age
// Boolean
isActive
isActiveUser
LoggedIn

命名有的时候短好,有的时候长好,这取决于有没有把这个名字背后的事物描述清楚

函数、方法:不应该带数据,是具体逻辑的抽离,使用带形容词的动词或短语

// 进行操作的函数
getUserByEmail()
response.send()
// 取布尔值的函数
emailIsValid()
purchase.isPaid()

函数的命名应该提供更多的细节来介绍功能

:创造对象,实例化某些事物,使用名词与名词或短语连用,多个名词互相组合,首字母大写

class Customer
class RequestBody
class DatabaseManager

常见问题

  • 不要在命名中包含多余信息,命名是为了知道主要功能,而不是描述一切
  • 避免俚语,不清楚的缩写和虚假信息
  • 避免使用过于相似的名字
  • 应该保持命名风格的统一

注释

有的时候注释是冗余的信息,如果代码能够不需要注释就能很好的阅读,注释反而会使理解变的困难

代码的注释如果太长时间不需要这段代码应该删除而不是注释,如果需要应该通过版本控制系统来找回,不需要害怕删除

如果可以,最好尽量控制项目中出现少的注释,因为多余的文字影响阅读

什么是好的注释

  • 法律信息注释
  • 对行为解释的注释
  • 警告某些行为的注释
  • todo list 注释
  • 文档注释,用于解释一些功能,这一点取决于项目类型

格式化

可以提高代码的可读性并且帮助我们在代码中传递信息

垂直格式化:代码文档自上而下的整体结构

  • 大文件:代码应该很容易去阅读,避免从上到下多处进行跳跃,如果代码中涉及许多概念,应该将其拆分到多个文件中去,保持文件的简短可读
  • 单文件多概念:使用空行去分割每部分代码,而相似概念的内容则可以归类在一起不需要分隔
  • 密切相关概念的联系:彼此具有联系的代码应该尽可能靠近放,增强阅读联系

水平格式化:单行或多行代码的结构

  • 避免需要水平滚动的,很长不可读的句子,应该使用缩进和换行还改善
  • 中断长句子,部分过长的部分可以使用const 来保存后调用
  • 避免强描述性的过长命名

函数

参数

最大程度的减少函数的参数,参数越多,越难以调用,参数的顺序和意义都会令人困惑,会导致阅读更多的代码

在调用时,最方便的是不需要参数的函数,参数最大能接受3个,非常不建议超过3个参数

如果原函数需要不相关的不同参数,应该根据参数的意义拆分函数,使每个函数的功能单一且不需要过多参数

如果有许多相关的参数,因为参数的顺序会限制内部的逻辑,所以应该将所有参数打包成对象传入来避免这样的问题,因为使用对象可以解决强顺序引起的不便利

避免输出参数,不应该将参数传入进行修改后传出,如果需要添加某些数据,对于函数的名称和参数应该做修改,使之更符合职能

抽象层级

在函数的编写中应该根据函数的功能来定义抽象层级,将大量代码的函数进行拆分为许多更低抽象层级的函数,保持每个函数的可读性和体积

在同一个函数中不要混入不同级别的抽象概念

拆分合并规则:

有着相同功能的函数进行合并

比周围代码需要更多解释的概念需要拆分

DRY原则 - don’t repeat youself

不要总是重复写相似的代码,拒绝复制粘贴,使用封装一处修改处处完善,但是拆分代码不是盲目的,过度拆分也不利于提高阅读性 ,下面的一些情况不需要拆分

  • 仅仅只是重命名操作
  • 寻找新函数将花费比读取代码更长的时间
  • 没有比较好的名字来命名函数

保持纯函数

纯函数:对于相同的输入产生相同的输出,输出是100%可以预先确定的。

副作用:副作用是一种操作,它不仅是对函数输入输出起作用,还有可能改变整个系统/程序状态。副作用并不是总是坏的,我们在程序中确实需要他们,但是应该避免意外的副作用

结构控制

创建守卫

使用if语句制造代码守卫,对于流程中的错误做到快速中断,避免其他代码继续执行,把多层嵌套的if判断解脱出来使之变成多层守卫。

if (index == this.current) {
  return 
}

抛出错误

抛出+处理错误可以替换if语句,并导致更集中的函数

如果某些事是错误的,就抛出错误,善于使用现在语言的内置错误机制

使用工厂函数和多态

对于不同条件下的函数逻辑,可以方法内拆分成多个函数,使用多态来分别处理不同的情况

对象和数据结构

对象可能包含了私有属性,并且允许使用公开api来操作对象

数据结构只是简单的对象,并且内部是公开的,没有方法和api

凝聚力

如果一个类中的数据和方法关联性不强,或者方法之间没有关联使用,这样的类只是数据和方法的集合,这就是凝聚力差的代码

德米特(demeter)定律:模块不应该知道其操作的对象的内部细节。 如果代码依赖于特定对象的内部细节,则很有可能一旦该对象的内部发生更改,它就会被破坏。

SOLID原则

  • S:single responsibility principle 单一职责原则
    • 一个类不应该因为一个以上的原因去改变状态
  • O: open-closed principle 开闭原则
    • 开放用于扩展,但因修改而关闭,这种可扩展性保证了小类的自动进行,否则随着功能的增加大类会变得臃肿,
  • L: liskov substitution principle 利斯科夫替代原则
    • 对象应该是可以被子类实例替换的,而不会影响任何行为。如果一个类继承自另一个类,那么子类应该支持父类的所有方法,从最初的应该正确的建立数据模型。这有助于编写良好可扩展的代码
  • I: interface segregation principle 接口分隔原则
    • 设置许多特定的客户端接口比设置一个通用接口要好
  • D: dependency inversion principle 依赖倒置原则
    • 代码应该依赖于抽象而不是一些在业务中外部的不确定因素,不应该让一些固定的业务写到抽象里
posted @   chenSee  阅读(88)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示