这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
如何实现高质量编程呢,一方面是编写代码的高质量,一方面是性能高质量
加油加油加油!!!
高质量编程
高质量代码--正确可靠,简洁清晰的目标
- 边界条件
- 异常处理,稳定性保证
- 易读易维护,注意团队合作!!!
编写原则
- 简单性 简洁清晰的逻辑编写代码(复杂的难以修改与维护
- 可读性 代码是写给人看的!!!
- 生产力 即工作效率
注意
- 代码格式
- 注释
- 命名规范
- 控制流程
- 错误与异常处理
注释
公告符号始终要进行注释,功能说明
注释主要是提供额外信息!!要有用
有一个完整的能提供信息的代码注释,无论是他人或者自己对于代码的使用都有很大帮助
- 代码作用
- 代码如何做(实现过程)
- 实现的原因
- 为什么会出错
- 代码限制条件
- 修改代码逻辑时要更新注释
推荐使用gofmt自动格式化代码
命名规范
变量命名
- 简洁
- 缩略词全大写,但位于开头且不需要导出时全小写
- 全局变量时要带上自己的信息
函数命名
- 不需携带包名的上下文信息,因为是成对出现的
- 尽可能简短
包命名
- 只小写字母
- 不与标准库同名
- 简短并包含一定的信息
- 缩写的话需要不破环原意
命名规范与注释的核心目标是降低代码阅读理解的成本!
控制流程
- 避免分支上的嵌套,去除不需要的else
- 尽量避免多重缩进
- 线性原理,逻辑尽量直线
错误和异常处理
- 简单错误
error.New 创建匿名变量表示简单错误,格式化:fmt.Errorf
- 复杂错误
Warp 和 Unwarp (错误的嵌套,实现错误的跟踪链),在fmt.Errorf中使用%w关键字将错误关联到错误链中
list, _, err := c.GetBytes(cache.Subkey(a.actionID, "srcfiles))
if err! != nil {
return fmt.Errorf("reading srcfiles list: %w", err)
}
- 错误判定
错误链上获取特定错误,使用errors.Is
if errors.Is(err, fs.ErrNotExist) {
return []byte{}, nil
}
错误链上获取特定种类的错误,使用errors.As
if errors.As(err, &pathError){
fmt.Println(err)
}
- panic
不建议在业务代码中使用panic,
调用函数不包含recover 会造成程序崩溃,
问题可以被解决或者屏蔽时用error代替,
启动时发生不可逆错误时,可以在 init 或者 main 使用 panic
- recover
recover 只能在被 defer 的函数中使用
嵌套无法生效
只能在当前 goroutine 生效
defer 语句后进先出
性能调优
- 性能评估
首先,我们需要对我们的项目代码进行性能评估,Golang提供了相关的基准性能测试--benchmark工具
$ go test -bench=. -benchmem
$ go test -run=. -v
结果说明:
性能优化建议
-
预分配 slice的初始化提供容量信息,防止多次内存分配(需要扩容)
-
在已有切片上创建切片,不会释放原底层数组,占用空间。 可以创建新的切片,用copy进行引用
-
map预分配内存 初始化make一个容器大小,与slice的扩容同理
-
字符串处理 字符串为不可变类型,每次使用+凭借都会重新分配内容,使用stings.Builder维护了一个[]byte数组,并转化成字符串返回。
同理,在预知大小的情况也可以进行预分配
-
空结构体节省内存 因为空结构体不占用内存空间,可以用来占位 比如实现cet用map实现时,只需要键不需要值的时候
-
多线程时的线程安全可使用atomic包(硬件调用),维护一个原子变量,对比加锁(系统调用)保护一个变量,时间性能更好,
加锁更适合用于保护一段逻辑。
小结
从代码质量与性能优化的方向来讲高质量代码,个人认为代码的可读性、可靠性的优先级更高一点,在实现了代码可读性,安全性等条件之后再去追求高性能更好。