Go高质量编程 | 青训营笔记

40 阅读3分钟

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

下面相关内容仅供本人回顾使用。如有错误,烦请评论反馈,感激不尽!!!

高质量编程简介

高质量的定义:

编写的代码能够达到正确可靠、简洁清晰的目标。

  • 正确性:是否考虑各种边界条件,错误的调用是否能够处理
  • 可靠性:异常情况或者错误的处理策略是否明确,依赖的服务出现异常是否能够处理
  • 简洁:逻辑是否简单,后续调整功能或新增功能是否能够快速支持
  • 清晰:其他人在阅读代码的时候是否能清楚明白,重构或修改功能是否不用担心出现无法预料的问题

高质量的代码并不仅仅局限于哪一门语言或者哪一个工程,而应当是作为一个coder的基本素养。

  • 简单性:消除多余的复杂性,以简单清晰的逻辑编写代码,因为不好理解的代码无法修复改进
  • 可读性:代码是写给人看的,而不是机器,编写可维护代码的第一步是确保代码可读
  • 生产力:团队整体的工作效率非常重要,为了减低新员工上手项目代码的成本,Go语言甚至通过工具强制统一所有代码格式。

编码规范

如何编写高质量的Go代码?需要注意:

  • 代码格式:推荐使用gofmt自动格式化代码

  • 注释:Good code has lots of comments, bad code requires lots of comments.

    • 注释应该解释代码作用
    • 注释应该解释代码如何做的
    • 注释应该解释代码实现的原因
    • 注释应该解释代码什么情况会出错
    • 公共符号始终要注释
  • 命名规范:

    • 简洁胜于冗长

    • 缩略词全大写,但当期位于变量开头且不需要导出时,使用全小写

      • 使用ServeHTTP而不是ServeHttp
      • 使用XMLHTTPRequest而不是xmlHTTPRequest
    • 变量距离其被使用的地方越远,则需要携带越多的上下文信息

    • 函数名不携带包名的上下文信息且尽量简短

    • package名只由小写字母组成

  • 控制流程:

    • 避免嵌套,保持正常流程清晰,例如去掉不必要的else
    • 尽量保持正常代码路径为最小缩进,能对称就对称
    • 故障问题的大多出现在复杂的条件语句和循环语句中,尽量化简
  • 错误和异常处理:

    • 简单错误:指仅出现一次的错误,且在其他地方不需要捕获该错误

    • 优先使用errors.New来创建匿名变量来直接表示简单错误

    • 如果有格式化需求,请使用fmt.Errorf

    •  // 一个例子
       func defaultCheckRedirect(req *Request, via []*Request) error {
       if len(via) >= 10 {
          // 使用errors.New
          return errors.New("stopped after 10 redirects.")
       }
       return nil  // 去掉不必要的else
       }
      

错误判定:

  • 判定一个错误是否为特定错误,用errors.ls,不同于使用==,该方法可以判定错误链上的所有错误是否含有特定的错误
// 一个例子
data, err = lockedfile.Read(targ)
if errors.Is(err, fs.ErrNotExist) {
    return []byte{}, nil
}
return data, err
  • 在错误链上获取特定种类的错误,使用errors.As
// 一个例子
if _, err := os.Open("non-existing"); err != nil {
    var pathError *fs.PathError
    if errors.As(err, &pathError) {
        fmt.Println("Failed at path:", pathError.Path)
    } else {
        fmt.Println(err)
    }
}
  • panic:比错误更严重,表示程序无法正常工作,在业务代码中不建议使用,故不展开介绍。

  • recover:与panic对应,如果需要更多的上下文信息可以在recover后在log中记录当前的调用栈

生效条件:
  • 只能在被defer的函数中使
  • 嵌套无法生效
  • 只在当前goroutine生效
  • 注意defer是一个栈