高质量编程 | 青训营笔记

141 阅读8分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第五天

一、本堂课重点内容:

  • 编码规范

二、详细知识点介绍:

首先我们来了解一下什么是高质量,这实际上是一个偏主观的标准,即编写的代码能够达到正确可靠、简洁清晰的目标可称之为高质量代码,要求不多,实际并不容易达到

正确性:是否考虑各种边界条件,错误的调用是否能够处理

可靠性:异常情况或者错误的处理策略是否明确,依赖的服务出现异常是否能够处理

简洁:逻辑是否简单,后续调整功能或新增功能是否能够快速支持

清晰:其他人在阅读理解代码的时候是否能清楚明白,重构或者修改功能是否不会担心出现无法预料的问题

如何编写高质量的代码,实际应用场景千变万化,各种语言的特性和语法各不相同,有哪些通用的原则吗?

简单性 消除“多余的复杂性”,以简单清晰的逻辑编写代码 在实际工程项目中,复杂的程序逻辑会让人害怕重构和优化,因为无法明确预知调整造成的影响范围 难以理解的逻辑,排查问题时也难以定位,不知道如何修复

可读性 可读性很重要,因为代码是写给人看的,而不是机器 在项目不断迭代的过程中,大部分工作是对已有功能的完善或扩展,很少会完全下线某个功能,对应的>功能代码实际会生存很长时间。已上线的代码在其生命周期内会被不同的人阅读几十上百次 听课时老师经常说的在课堂上不遵守纪律影响全班同学的时间,难以理解的代码会占用后续每一个程序>员的时间

生产力 编程在当前更多是团队合作,因此团队整体的工作效率是非常重要的一方面 为了降低新成员上手项目代码的成本,Go语言甚至通过工具强制统一所有代码格式 编码在整个项目开发链路中的一个节点,遵循规范,避免常见缺陷的代码能够降低后续联调、测试、验>证、上线等各个节点的出现问题的概率,就算出现问题也能快速排查定位

编码规范

接下来我们具体来看看要注意哪些方面才能让我们的代码更规范,具体详细的信息可以自行搜索各个大厂的编码规范

代码格式

首先是推荐使用gofmt自动格式化代码,保证所有的Go代码与官方推荐格式保持一致 而且可以很方便的进行配置,像Goland内置了相关功能,直接开启即可在保存文件的时候自动格式化

image.png

另外可以考虑goimports,会对依赖包进行管理,自动增删依赖的包引用,按字母序排序分类,具体可以根据团队实际情况配置使用 之所以将格式化放在第一条,因为这是后续规范的基础,团队合作review其他人的代码时就能体会到这条规范的作用了

image.png

注释

注释是我们写代码的时候会经常使用到功能,它就是我们程序员随手可以用的草稿本

而一个完美的注释需要满足哪些条件呢?

注释应该解释代码的作用

首先是注释应该解释代码作用,这种注释适合说明公共符号

比如对外提供的函数注释描述它的功能和用途. 只有在函数的功能简单而明显时才能省略这些注释(例如, 简单的取值和设值函数)

另外注释要避免啰嗦, 不要对显而易见的内容进行说明. 下面的代码中注释就没有必要加上,通过函数名可以很容易的知道作用 image.png

注释应该解释代码是如何做的

注释同样要对代码中复杂的,并不明显的逻辑进行说明,适合注释实现过程

下面的是一个反例,虽然是对过程注释,但是描述的是显而易见的流程,注意不要用自然语言直接翻译代码作为注释,信息冗余还好,有时候表述不一定和代码一致 image.png

注释应该解释代码实现的原因

注释可以解释代码的外部因素,这些因素脱离上下文后通常很难理解

比如像这样 image.png

注释应该解释代码什么情况下会出错

注释应该提醒使用者一些潜在的限制条件或者会无法处理的情况

函数的注释中可以说明是否存在性能隐患,输入的限制条件,可能存在哪些错误情况,让使用者无需了解实现细节

例子 image.png

总之,注释部分我们重要的要记住两点

  • 代码是最好的注释
  • 注释应该提供代码未表达出的上下文信息

命名规范

介绍完注释,接下终于要看看实际写代码时的一些约定和规范 写代码时最常见的就是命名,不管是变量命名还是函数命名都希望能够简洁清晰

变量命名

在为变量进行命名时,我们应该

  • 简洁胜于冗长
  • 缩略词全大写,但是当其位于变量开头而且只在函数内部进行调用的时候,使用全小写 -变量距离其被使用的地方越远,则需要携带越多的上下文信息,使得在不同的地方也可以轻易辨认出其含义

函数命名

在为函数命名时,我们应该

  • 函数名不携带包名的上下文信息,因为包名和函数名总是成对出现的
  • 函数名尽量简短
  • 当名为foo的包某个函数返回类型为Foo时,可以省略类型信息而不导致歧义
  • 当名为foo的包某个函数返回类型为T时(T并不是Foo),可以在函数名中加入类型信息

包命名

比函数更高一层的就是包,如何对包进行更好的命名也有一些经验 标准库有很多地方在使用,同时使用时需要指定别名,比较麻烦

  • 只由小写字母组成,不包含大写字母和下划线等字符
  • 简短并包含一定的上下文信息
  • 不要与标准库同名

以下规则可以尽量满足

  • 不使用常用变量名作为包名
  • 使用单数而不是复数
  • 谨慎合理地使用缩写

总体来说,命名的核心在于降低阅读理解代码的成本 人们在阅读理解代码的时候会尝试模拟计算机运行程序,好的命名能让人把关注点留在主流程上,清晰地理解程序的功能,避免频繁切换到分支细节,增加理解成本

控制流程

当我们能够给变量或者函数选择合适的名称后,接下来就是实现具体功能了,经常用到的就是if else这种条件控制语句,那么在使用中需要注意哪些点?

  • 要遵循线性原理,处理逻辑尽量走直线,避免复杂地嵌套分支
  • 正常流程代码沿着屏幕向下移动
  • 提升代码的可维护性和可读性
  • 故障问题大多出现在复杂的条件语句和循环语句中

一个功能如果可以通过多个功能的线性结合来实现,那它的结构就会非常简单。反过来,用条件分支控制代码、毫无章法地增加状态数等行为会让代码变得难以理解。需要避免这些行为,提高代码的可读性。 如果能让正常流程自上而下、简单清晰地进行处理,代码的可读性就会大幅提高,与此同时,可维护性也将提高,添加功能等改良工作将变得更加容易

错误和异常处理

因为错误和异常是不正常的情况,除了希望程序能兼容这些场景外,重要的也有记录问题的上下文信息,方便后续定位原因 在明确panic recover这些功能的作用范围的情况下,编写更可靠的程序

  • error尽可能提供简明的上下文信息链,方便定位问题
  • panic用于真正异常的情况
  • recover生效范围应当在当前goroutine的被defer的函数之中

三、课后个人总结:

在项目生产中,学会写出一手高质量且遵循规范的代码是非常重要的

因为这个项目在前前后后会经过许许多多的人手,如果其中有一个人不遵循这些规范导致代码不规范,可读性变低,那就会影响之后所有维护该代码的效率。

在此次学习中我知道了该如何去写一手符合基本规范的代码,也为之后去到企业工作时养成良好的编码习惯。