这是我参与「第五届青训营」伴学笔记创作活动的第 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是一个栈