go 后端笔记5 高质量编程

87 阅读3分钟

高质量代码要求正确可靠,简洁清晰

  • 边界条件是否考虑完备
  • 异常情况处理是否稳定
  • 逻辑尽可能简单,代码易读易维护

编程原则

简单性

  • 消除多余的复杂性,以简单清晰的逻辑编写代码
  • 不理解的代码难以维护,无法修复、改进

可读性

编写可维护代码的第一步是确保代码可读性

生产力

团队整体工作效率非常重要

编码规范

代码格式

  • gofmt:自动格式化工具,将 Go 风格统一为官方风格
  • goimports:在 gofmt 的基础上自动增删依赖包引用,并将依赖按字母排序分类

推荐使用 gofmt 自动格式化

注释

  • 注释应包含声明的每个公共符号:变量、常量、函数、结构等
  • 任何不明显也不简短的公共功能必须注释
  • 无论长度和复杂度,任何函数都必须注释

例外:不需要注释接口的实现

注释应解释以下几个方面:

  • 代码作用:公共符号
  • 如何实现
  • 实现原因:代码外的因素,额外上下文
  • 出错情况:代码的限制条件、处理方法

代码是最好的注释,注释应提供代码未表达的信息

命名规范

变量命名

  • 简洁胜于冗长,但要明确功能
  • 缩略词全大写,但位于开头且 private 时全小写
  • 变量距离使用位置较远时尽量多携带一些上下文信息

函数命名

  • 函数名包含包名上下文信息(调用时通常函数与包名是同时出现的)
  • 函数名尽量简短
  • 当名为 foo 的包函数返回 Foo 类型时,可以省略返回类型,不会引起歧义
  • 当名为 foo 的包函数返回非 Foo 类型时,可以在函数名中添加返回类型信息

包名

  • 只用小写组成,不包含大写字母、下划线
  • 简短并包含一定的上下文信息
  • 不与标准库同名,如 syncstrings
  • 尽量不要使用常用变量名作为包名,如 bufio 不用 buf
  • 尽量使用单数而不是复数,如 encoding 不用 encodings
  • 谨慎使用缩写,要求不影响上下文阅读,如 fmt 不用 format

流程控制

  • 避免嵌套
    • 当多个分支都有 return,去除冗余分支
  • 尽量保持正常代码路径为最小缩进
    • 优先处理错误情况或特殊情况,尽早结束嵌套

提高可读性和可维护性,故障问题大多出现在复杂条件语句中

错误与异常处理

简单错误

仅出现一次的错误,且在其他位置不需要处理

  • 优先使用 errors.New 创建匿名变量直接表示简单错误,直接返回或其他处理
  • 需要格式化也可以使用 fmt.Errorf

复杂错误

使用 WrapUnwrap

  • 实质是将一个错误嵌套进另一个错误,形成 error
  • fmt.Errorf 中使用 %w 关联一个错误
  • 使用 errors.Is 判断某错误是否位于错误链中
  • 使用 errors.As(err, &subErr) bool 在错误链中提取特定错误

panic

若不进行 recover 处理程序将崩溃

  • 不建议在程序中使用 panic
  • 问题可以被屏蔽或解决的情况下应使用 error
  • 程序启动阶段发生不可逆错误时可以在 maininit 中使用 panic

recover

panic 时触发

  • 只能在 defer 函数中使用,注意 defer 先进后出的顺序
  • 嵌套无法生效
  • 只能在 goroutine 中生效
  • 可以在其中通过 debug.Stack() 记录异常堆栈信息