高质量编程与性能调优实战—第一部分|青训营笔记
什么是高质量——编写的代码能够达到正确可靠、简洁清晰的目标可称之为高质量代码
- 各种边界条件是否考虑完备
- 异常情况处理,稳定性保证
- 易读易维护
编程原则
- 简单性
- 可读性
- 生产力
编码规范
-
代码格式
- 推荐使用 Gofmt 自动格式化代码。
- Gofmt:Go 语言官方提供的工具,能自动格式化 Go 语言代码为官方统一风格,常见 IDE 都支持方便的配置。
- Goimports:也是 Go 语言官方提供的工具,实际等于 Gofmt 加上依赖包管理,自动增删依赖的包引用、将依赖包按字母序排序并分类。
-
注释
- 注释应该解释代码作用。
- 注释应该解释代码如何做的。
- 注释应该解释代码实现的原因。
- 注释应该解释代码什么情况会出错。
-
命名规范
- 变量的命名:简洁胜于冗长。缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写。变量距离其被使用的地方越远,需要携带的信息就需要越多。
- 函数的命名:函数名不必携带包名的上下文信息。函数名需要尽可能地简短。当函数返回类型与包名相同时,可以省略类型信息。
- 包的命名:包名仅由小写字母组成。包名简短且包含一定的上下文信息。不要与标准库问名。
控制流程
-
线性原理,处理逻辑尽量走直线,避免复杂的嵌套分支。如果两个分支中都包含return语句,则可以去除冗余的else。
// Bad if foo { return X } else { return nil } // Good if foo { return X } return nil
-
尽量保持正常代码路径为最小缩进 优先处理错误情况特殊情况,尽早返回或继续循环来减少嵌套
// Bad func OneFunc( ) error { err := doSomething( ) if err == nil{ err := doAnotherThing( ) if err == nil{ return nil // normal case } return err } return err } // Good func OneFunc( ) error { if err := doSomething(); err != nil { return err } if err. := doAnotherThing(); err != nil { return err } returrpnil // normal case }
-
正常流程代码沿着屏幕向下移动。
-
提升代码可维护性和可读性。
-
故障问题大多出现在复杂的条件语句和循环语句中。
错误和异常处理
-
简单错误
- 简单的错误指的是仅出现一次的错误, 且在其他地方不需要捕获该错误
- 优先使用
errors.New
来创建匿名变量来直接表示简单错误 - 如果有格式化的需求,使用
fmt.Errorf
-
错误的Wrap和Unwrap
- 错误的Wrap实际上是提供了一个
error
嵌套另一个error
的能力,从而生成一个error
的跟踪链 - 在
fmt.Errorf
中使用: %w关键字来将一个错误关联至错误链中
- 错误的Wrap实际上是提供了一个
-
错误判定
-
判定一个错误是否为特定错误,使用
errors.Is
-
不同于使用==,使用该方法可以判定错误链.上的所有错误是否含有特定的错误
data, err = lockedfile. Read( targl2209 if errors.Is(err, fs.ErrNotExist) { // Treat non-existent as empty,to bootstrap the "latest" file // the first time we connect to a given database. return []byte{}, nil } return data, err
-
在错误链上获取特定种类的错误,使用
errors.As
if _,err := os.0pen( "non-existing"); err != nil { var pathError *fs. PathEr r if errors.As(err, &pathEroor) { fmt. Println("Failed at path:", pathError .Path) } else { fmt.Println(err) } }
-
-
panic
- 不建议在业务代码中使用
panic
- 调用函数不包含
recover
会造成程序崩溃 - 若问题可以被屏蔽或解决,建议使用error代替
panic
- 当程序启动阶段发生不可逆转的错误时,可以在init或main函数中使用
panic
- 不建议在业务代码中使用
-
recover
recover
只能在被defer的函数中使用- 嵌套无法生效
- 只在当前
goroutine
生效 defer
的语句是后进先出