一.作用
高质量的编码是指能够达到正确可靠、简洁清晰的目标。首先各种边界条件是否考虑完备,异常情况处理和稳定性保证,易读易维护。遵循的编程原则有简单性,消除"多余的复杂性”,以简单清晰的逻辑编写代码,不理解的代码无法修复改进;可读性,代码是写给人看的,而不是机器,编写可维护代码的第一步是确保代码可读;生产力,团队整体工作效率非常重要。
二.原则
1.代码格式
推荐使用gofmt编码工具,因为这是Go语言官方提供的工具,能自动格式化Go语言代码为官方统一风木常见IDE都支持方便的配置。推荐使用goimports,这也是Go语言官方提供的工具,能够自动增删依赖的包引用、将依赖包按字母序排序并分类。
2.注释
为什么要编写注释?首先注释起到解释代码作用,其次注释可以解释代码如何做的,注释可以解释代码实现的原因,注释可以解释代码什么情况会出错。下列列举了一些写注释。
// Add the Referer header from the most recent
// request URL to the new one,if it's not https->http:
if ref :=refererForURL(reqs[len(reqs)-1].URL, req.URL);ref!="" {
ref != req .Header .Set("Referer", ref )
}
公共符号始终要注释
包中声明的每个公共的符号:变量、常量、函数以及结构都需要添加注释。任何既不明显也不简短的公共功能必须予以注释。无论长度或复杂程度如何,对库中的任何函数都必须进行注释。
// ReadAll reads from r until an error or EOF and returns thedata it read.
// A successful call returns err == nil,not err == EOF. BecauseReadAll is
// defined to read from src until EOF,it does not treat an EOFfrom Read
// as an error to be reported
func ReadAll(r Reader) ([]byte, error)
3.命名规范
变量: 简洁胜于冗长;缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写 例如使用 ServeHTTP 而不是 ServeHttp,使用 XMLHTTPRequest 或者 xmIHTTPRequest;变量距离其被使用的地方越远,则需要携带越多的上下文信息;全局变量在其名字中需要更多的上下文信息,使得在不同地方可以轻易辨认出其含义。
函数:函数名不携带包名的上下文信息,因为包名和函数名总是成对出现的;函数名尽量简短;当名为 foo 的包某个函数返回类型 Foo 时,可以省略类型信息而不导致歧义;当名为 foo 的包某个函数返回类型 T 时 (T 并不是 Foo),可以在函数名中加入类型信息。
包:只由小写字母组成;不包含大写字母和下划线等字符简短并包含一定的上下文信息,例如 schema、task 等;不要与标准库同名,例如不要使用 sync 或者 strings。
4.控制流程
避免嵌套,保持正常流程清晰。
if foo {
return x }
return nil
尽量保持正常代码路径为最小缩进。最常见的正常流程的路径被嵌套在两个 if 条件内;成功的退出条件是 return nil,必须仔细匹配大括号来发现;函数最后一行返回一个错误,需要追溯到匹配的左括号,才能了解何时会触发错误;如果后续正常流程需要增加一步操作,调用新的函数,则又会增加一层嵌套。
func OneFunc() error {
if err := doSomething(); err != nil {
return err
}
if err := doAnotherThing(); err != nil {
return err
}
return nil // normal case
}
5.错误和异常处理
简单错误。简单的错误指的是仅出现一次的错误,且在其他地方不需要捕获该错。优先使用 errors.New 来创建匿名变量来直接表示简单错误。如果有格式化的需求,使用 fmt.Errorf。
func defaultCheckRedirect(req *Request, via []xRequest) error {
if len(via) >= 10{
return errors.New("stopped after 10 redirects")
}
return nil
}
错误的Wrap和Unwrap。错误的 Wrap 实际上是提供了一个 error 嵌套另一个error 的能力,从而生成一个 error 的跟踪链。在 fmt.Errorf 中使用: % w 关键字来将一个错误关联至错误链中。
真正异常。不建议在业务代码中使用 真正异常。调用函数不包含 recover :会造成程序崩溃。若问题可以被屏蔽或解决,建议使用error 代替 panic。当程序启动阶段发生不可逆转的错误时可以在 init 或 main 函数中使用 panic。
func main() {
ctx cancel := context.withCancel(context.Background())
client, err := sarama.NewConsumerGroup(strings.Split(brokers,,group, config)
if err != nil {
log.Panicf("Error creating consumer group client: %v" err)
}
//...
} // Panicf is equivalent to Printf() followed by a call to panic().
func Panicf(format string, v ...interfacef}) {
s := fmt.Sprintf( format, v...)
std.Output(2,s )
panic(s)
}
生效范围。生效范围 只能在被 defer 的函数中使用。嵌套无法生效。只在当前 goroutine 生效。defer 的语句是后进先出。
三、心得体会
高质量编码主要从两个方面开展,一个是规范,一个是简便,从格式、注释、流程等多个方面控制编码的高质量,不仅方便他人观看,也方便自己的日后查看和进一步编程。