【青训营】Go的高质量编程
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
Go的高质量编程
本文内容总结自字节跳动青年训练营 第五届 后端组
什么是高质量
- 各种边界条件是否完备
- 异常情况能正常处理稳定性有保障
- 易读易维护
Go语言开发者Dave Cheney指出编程需要遵循以下原则
简单性
- 消除多余的复杂性以简单清晰的逻辑编写代码
- 无法理解的代码意味着无法修复和改进
可读性
- 代码是给人看的
- 编写可维护代码的第一步是确保代码可读
生产力
- 团队整体工作效率很重要
一、注释
- 包中生命的每个公共符号包括变量、函数以及结构体都要注释
- 任何既不明显也不简短的公共功能 都要注释
- 无论长度或者复杂程度库中任何函数都需要进行注释
- 实现接口的函数不需要注释
gofmt是Go语言官方提供的工具能够自动格式化Go语言代码为官方统一风格一般的IDE比如GoLand直接内置并且默认开启gofmt
除了gofmt之外还有goimport实际上等于gofmt加上依赖包管理会自动增删依赖包的引用并且按照字母排序并分类
注释需要 解释代码作用、代码的逻辑、代码实现的原因、在什么情况下会出错
1.解释代码的作用
在功能和逻辑不太明显的情况需要额外注释而对于逻辑清晰的比如
for e := range elements{
process(e)
}
可以不需要注释
2.注释代码的实现原因
对于注释我们应该解释代码实现的原因另外还可以解释代码的外部因素和额外的上下文关系
3.注释代码出错的原因
适合解释代码的限制条件比如对于将字符串转化为时间格式的方法
那么上面则解释了传入非法的、不符合格式的字符串会触发什么异常
4.公共符号始终要注释
小结
总而言之代码就是最好的注释而注释需要提供代码未表达的上下文信息
二、命名
1.变量名
- 简洁胜于冗长
- 缩略词全大写但是如果位于变量头则全小写
- 变量距离其被使用的地方越远则需要携带更详细的信息
比如:
for i := 0; i < 10; i++ {
process()
}
for index := 0; index < 10; index++ {
process()
}
上述例子中i和index作用域仅限于for内部因此index的额外长度几乎没有增加对程序的理解因此使用更短的i是更适合的
还有一个例子新建一个接受截止时间的函数
func(c *Client) send(req *Request, deadline time.Time)
func(c *Client) send(req *Request, t time.Time)
上述例子中deadline可以更详细描述变量作用因此比t更适合
2.函数名
- 函数名不懈怠包名已有的上下文信息因为包名和函数名会一起出现
- 函数名尽量简短
- 当名为foo的包的某个函数返回的类型T并不是Foo的时候可以在返回的函数名中加入类型信息
比如在http包中有一个创建服务的函数有以下两种命名
func Serve(l net.Listener, handler Handler)
func ServeHTTP(l net.Listener, handler Handler)
其中要调用这个函数分别是使用http.Serve和http.ServeHTTP。我们发现http.ServeHTTP对于http重复描述了实际上不够好更合适的命名方式为http.Serve
3.包名
- 只使用小写字母组成不包含大写字母和下划线
- 简短并包含一定上下文信息
- 不要和标准库同名
小结
核心目标是降低阅读理解代码的成本重点考虑上下文名称设计简洁清晰的名称
三、流程控制
1.避免嵌套保证流程清晰
如果两个分支中都有return则需要去除冗余的else
2.复杂的控制流程优先处理错误和特殊情况尽早返回或者继续循环来减少嵌套
也就是要尽量的扁平减少嵌套层数
3.小结
- 线性原理处理逻辑尽量走直线避免复杂的嵌套分支
- 故障问题大多出现在复杂的条件语句和循环语句中
四.错误和异常
1.简单错误
只出现一次的错误而且在其他地方都不需要捕获该错误。优先使用errors.New来创建匿名变量直接表示简单错误如果有格式化要求则使用fmr.Errorf
func defaultCheckRedirect(req *Request, via []*Request) error{
if len(Via) >= 10{
return errors.New("stopped after 10 redirects")
}
return null
}
2.错误的Wrap和Unwarp
这是错误的包装和解包这可以使得一个错误嵌套另外一个错误从而形成错误链条方便跟踪排查问题。在fmt.Errorf中使用%w的关键字将一个错误关联到错误链中
3.错误判定
使用errors.Is判断错误
使用errors.As在错误链上获取指定类型的错误
4.painc
painc错误是一种严重的异常用于指明一些程序已无法继续运行的严重错误。
5.recover
6.defer
defer是后进先出的