什么是高质量:编写的代码能够达到正确可靠,简洁清晰的目标可称之为高质量代码
- 各种边界条件是否考虑完备
- 异常情况处理,稳定性保证
- 易读易维护
编程原则:
- 简单性
- 消除”多余的复杂性“,以简单清晰的逻辑编写代码
- ’不理解的代码无法修复改进
- 可读性
- 代码是写给人看的,而不是机器
- 编写可维护的代码的第一步是确保代码可读
- 生产力
- 团队整体的工作效率非常重要
编码规范:
-
代码格式尽可能地统一
- 推荐使用gofmt自动格式化代码
-
注释(好的代码有很多注释,不好的代码需要很多注释,应该提供一些使用该代码的上下文信息)
- 注释应该做的:
- 注释应该注释的内容
- 注释应该解释的代码,它是如何做的
- 注释应该解释代码实现的原因,适当解释代码的外部因素,提供额外的上下文
- 注释应该解释代码什么情况下可能会出错,解释代码的限制条件
- 公共符号始终要进行注释
- 包中声明的每个公共的符号:变量,常量,函数,以及结构都需要进行注释
- 任何及不明显也不简短的公共功能必须予以注释
- 无论长度或者复杂程度如何,对库中的任何函数进行注释
- 有一个例外,不需要注释实现接口的方法
- 注释应该做的:
-
命名规范(核心目标是降低阅读代码的成本,重点考虑上下文的信息)
- 简洁胜于冗长
- 缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写
- 利用ServeHTTP而不是ServeHttp
- 使用XMLHTTPResquest或者xmlHTTPRequest
- 变量距离其被使用的地方越远,则需要携带更多的上下文信息,参数名是可以代表着一些特点含义,知道它的意思
- 函数名:
- 函数名不携带包名的上下文信息,因为包名和函数名总是成对出现的
- 函数名尽量简短
- 当名为foo的包某个函数返回类型Foo时,可以省略类型信息而不导致歧义
- 当名为foo的包某个函数返回类型T时,可以在函数中加入类型信息
- 包名:
- 只由小写字母组成。不含有大写字母或者下划线等
- 简短并且包含一定的上下文信息
- 不要与标准库重名
-
控制流程
-
避免嵌套,保持正常流程
-
尽量保持正常代码路径为最小缩进。优先处理错误情况或者特殊情况,尽早返回
-
故障问题大多数出现在复杂的条件语句和循环嵌套当中
// Bad func OneFunc() error{ err:= doSomething() if err == nil{ err := doAnoterThing() if err == nil{ return nil } return err } return err } // 进行改进 func OneFunc() error{ if err := doSomething(); err != nil{ return err } if err := doAnotherthing(); err != nil{ return err } return }
-
-
错误和异常处理
-
简单的错误指仅出现一次的错误,其在其它的地方不需要捕获该错误
-
优先使用errors.New来创建匿名变量来直接表示简单错误
-
如果由格式化的需求,使用fmt.Errof
func defaultCheckRedirect(req *Request, via []*Request) error { if len(via) >= 10 { return errors.New("stopped after 10 redirects") } return nil }
-
错误的Wrap和Unwrap
-
错误的wrap实际上是提供了一个error嵌套另一个error的能力,从而生成error的跟踪链
-
在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 true,nil }
-
在错误链上获取特定种类的错误,使用errors.As
if errors.As(err,fs.pathError)
-
panic
- 业务中不建议使用你panic,如果出现说明业务基本崩溃了,用于真正的异常
- 若有问题可以被屏蔽或者解决,建议使用error来代替panic
- 调用时不使用recover会让程序奔溃
-
recover
- recover只能在defer的函数中使用
- 嵌套无法失效
- 只能在gotuntine中被defer的函数生效
- defer语句会在函数返回前被调用,多个defer语句是后进先出的
-