当前位置: 首页 > news >正文

【青训营】Go的高质量编程

Go的高质量编程

本文内容总结自字节跳动青年训练营 第五届 后端组

什么是高质量?

  • 各种边界条件是否完备
  • 异常情况能正常处理,稳定性有保障
  • 易读易维护

Go语言开发者Dave Cheney指出,编程需要遵循以下原则:

简单性

  • 消除多余的复杂性,以简单清晰的逻辑编写代码
  • 无法理解的代码意味着无法修复和改进

可读性

  • 代码是给人看的
  • 编写可维护代码的第一步是确保代码可读

生产力

  • 团队整体工作效率很重要

一、注释

  • 包中生命的每个公共符号,包括变量、函数以及结构体都要注释
  • 任何既不明显也不简短的公共功能 都要注释
  • 无论长度或者复杂程度,库中任何函数都需要进行注释
  • 实现接口的函数不需要注释

gofmt是Go语言官方提供的工具,能够自动格式化Go语言代码为官方统一风格,一般的IDE比如GoLand直接内置并且默认开启gofmt

除了gofmt之外还有goimport,实际上等于gofmt加上依赖包管理,会自动增删依赖包的引用并且按照字母排序并分类


注释需要: 解释代码作用、代码的逻辑、代码实现的原因、在什么情况下会出错

1.解释代码的作用

在功能和逻辑不太明显的情况需要额外注释,而对于逻辑清晰的比如:

for e := range elements{
    process(e)
}

可以不需要注释

2.注释代码的实现原因
对于注释,我们应该解释代码实现的原因,另外还可以解释代码的外部因素,和额外的上下文关系

3.注释代码出错的原因
适合解释代码的限制条件,比如对于将字符串转化为时间格式的方法

image.png
那么上面则解释了传入非法的、不符合格式的字符串会触发什么异常

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.避免嵌套,保证流程清晰

image.png

如果两个分支中都有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是后进先出的

相关文章:

  • 怎样开发游戏app软件/排名怎么优化快
  • 网站服务器建设的三种方法/怎样推广自己的广告
  • 网站关键字代码/短视频seo推广
  • 天津网站制作工具/和生活app下载安装最新版
  • 自助建站帮助网/互联网销售包括哪些
  • 网站显示已备案/最近新闻摘抄
  • Effective C++-条款47 使用traits class表现类型信息
  • 驱动程序那点事儿
  • DDOS和CC如何区分
  • JavaEE day3 初识web与HTML 2
  • buuctf-web-[RoarCTF 2019]Easy Calc1
  • JVM-内存模型详解
  • 聊聊红黑树,B/B+树和键树
  • AvFrame和AvPacket
  • Kyligence 副总裁李栋:指标中台构建数字化管理新体系|爱分析活动
  • LeetCode(Array)1389. Create Target Array in the Given Order
  • yolov7-face关于widerface-val数据集的评测
  • 一文读懂CPU工作原理、程序是如何在单片机内执行的、指令格式之操作码地址码