如何保障Go语言基础代码质量?

为什么要谈这个topic?

实践中,质量保障体系的建设,主要针对两个目标: 一是不断提高目标业务测试覆盖率,保障面向客户的产品质量;二就是尽可能的提高人效,增强迭代效率。而构建全链路质量卡点就是整个体系建设的核心手段。笔者用下图来描述这整个链路:

可以看到,虽然保障业务迭代的方向性正确排在最前面,但在具体操作上,这一步需要的是强化流程规范和构建企业文化,同时对各负责人技能培训,可以说多数是软技能。而保障基础代码质量环节发力于自动化建设链路之始,是可以通过技术手段来消灭潜在的质量问题,所以构建好的话能极大的降低心智负担,非常值得关注。

我们都知道,代码的好坏会直接影响到业务质量,团队协作,以及后期技术债等。有一个经典的图来描述代码质量的好坏,当能深切表达程序员的内心:

而同时我们相信,绝大部分程序员都有追求卓越的初心,且会尽可能的在自己能力范围内编写高质量的代码。

但是,保障基础代码质量光靠程序员的个人素质一定是不全面,是人就会犯错,可能会疏忽。我们最需要的是一种自动化的机制来持续确保不出问题。这也是自动化的魅力,一次构建,持续收获价值。

此类工具在业界一般叫linter,不同的语言有不同的实现。本文主要探究Go语言相关的。
在介绍相关工具之前,我们先看看几个经典的代码坏味道:

这段代码常规运行不会有问题,但是在一些场景下循环执行,那可能就会有问题了, 我们来看看:

(注:ex2是上述代码编译出的可执行文件名字)

很明显,有句柄泄露。原因也很简单,http response的body没有关闭。但这个关闭语句,一不注意也容易写错:

这时候如果百度挂了,上述程序程序就会因为空指针引用,造成非预期的panic,非常的不优雅。所以正确的做法应该是在err判断之后再行关闭body(关于Client.Do 具体的各种限制,大家可以参考这里: https://golang.org/pkg/net/http/#Client.Do)

如此种种,此类小问题在实际编码活动中非常常见,且不容易一眼看出问题。甚至常规的测试可能也难检测出来,可谓非常棘手。好在Go语言的开发者们为我们想到了这一点,内置工具链中的vet命令,就能方便的检测到很多类似的问题。

还比如下面的代码场景,我在实际的测试用例和业务代码都看到过:

go vet 可以很容易检测出这个问题(其他vet功能,可以参考这里: https://golang.org/cmd/vet/)。

go的工具链中,还有一个不得不提,那就是大名鼎鼎的go fmt,其了却了其他语言经常陷入的代码风格之争,是Go语言生态构建非常巧妙的地方。另外golint也是google主推的go语言代码代码风格工具,虽非强制,但强烈建议新项目适用。

Go linters业界现状

上面主要说到Go工具链的内置工具,还有一些非官方的工具也比较有名,比如 staticcheck, errcheck在github上Star都较多。此类工具有个专门的的github库,收集的比较全,参见 awesone-static-analysis

同时还有些项目旨在聚合此类工具,提供更方便的使用方式,以及一些酷炫的产品化。比如golangci-lint, 其衍生的商业化项目,可以自动针对github PR做代码审核,对有问题的地方自动comments,比较有意思。

如何才能优雅的落地linter检查?

linter工具必须为产品质量服务,不然就是做无用功。实践中,我们应该思考的是如何才能优雅的落地linter检查,如何才能建立有效的质量卡点。

推荐针对PR,做代码检查,保障入库代码质量。基于PR做事情是我比较看好的,因为这是调动所有研发力量,天然契合的地方。且进一步讲,这也是测试基础设施更能体现价值的地方。

目前Github上有很多这方面的集成系统做的都比较好,能够快速的帮我们落地PR测的检查,比如Travis, Circle CI等。另外就是著名的Kubernetes社区,也自行构建了强大的Prow系统,其不光是基于CICD系统,还构建了chat ops模式,为参与Kubernetes的社区的贡献者提供了方便。

细看Kubernetes库,会发现,其会针对每个PR都做如下静态检查:

  • gofmt: https://github.com/kubernetes/kubernetes/blob/master/hack/verify-gofmt.sh
  • govet: https://github.com/kubernetes/kubernetes/blob/master/hack/make-rules/vet.sh
  • golint: https://github.com/kubernetes/kubernetes/blob/master/hack/verify-golint.sh
    因为golint只是纠正代码风格,并不是强制,所以k8s官方就弄了比较软的方案,对于当前已经存在的代码如果有问题,先排除掉(如下)。对于新生代码,如果检查失败,ci就挂掉。
    https://github.com/kubernetes/kubernetes/blob/master/hack/.golint_failures

Kubernetes只利用了官方的几款工具, 在检测准确性上比较有保障。有了这些检查点,也能倒逼研发人员关注提交代码的质量,会迫使其在本地或者IDE上就配置好检查,确保每次提交的PR都能通过检查,不浪费CI资源。这也是合格工程师的基本要求。

总结

高质量的代码是业务质量保障的基础。而编写高质量的代码是技术问题,同时也应该是企业文化问题。因为当大家都开始注重技术,注重代码质量时,自然会朝着精益求精的路上行进,视糟糕的代码为仇寇。

我的一位老板跟我说过,要做就做Number One。而在没达到第一的时候,那就要向业界标杆看齐,比如Netflix,Google,Facebook等。当大家都非常注重自己代码质量时,工程师才有时间去关注解决更加系统性的问题,而不用一直在Low Level徘徊。笔者深以为然。

Contact me?

Email: jinsdu@outlook.com

Blog: http://www.cnblogs.com/jinsdu/

Github: https://github.com/CarlJi

原文地址:https://www.cnblogs.com/jinsdu/p/10486645.html

时间: 2024-07-30 05:53:36

如何保障Go语言基础代码质量?的相关文章

程序语言基础 8.14课堂代码

1.判断一个5位数是不是回文数! #include <stdio.h> void main() { int num,ge,shi,qian,wan; printf("请输入一个5位数:"); scanf("%d",&num); ge = num % 10; shi = num / 10 % 10; qian = num / 1000 % 10; wan = num / 10000; (ge == wan && shi == qia

C语言基础:将整数格式化成其它进制输出的代码

如下的资料是关于C语言基础:将整数格式化成其它进制输出的代码. #include <stdio.h> int main () { int value = 255; printf("The decimal value %d in octal is %on", value, value); printf("The decimal value %d in hexadecimal is %xn", value, value); printf("The

C语言基础:延迟执行的代码

下边代码段是关于C语言基础:延迟执行的代码,希望能对大家也有用. #include <stdio.h>#include <time.h> int main (void){time_t current_time;time_t start_time; printf("About to delay 5 secondsn"); do { time(&current_time); } while ((current_time - start_time) <

C语言基础:if条件语句使用演示的代码

学习期间,将写内容过程较好的内容段备份一下,下边内容段是关于C语言基础:if条件语句使用演示的内容,应该是对各位朋友有所用. #include <stdio.h> void main () { int age = 21; int height = 73; if (age == 21) printf("User's age is 21n"); if (age != 21) printf("User's age is not 21n"); if (heigh

C语言基础:格式化整数输出的代码

将写内容过程重要的内容段珍藏起来,下面内容内容是关于C语言基础:格式化整数输出的内容. #include <stdio.h>int main () { int value = 5; printf ("%1dn", value); printf ("%2dn", value); printf ("%3dn", value); printf ("%4dn", value);return 1; } gcc编译输出 5 5

20165103学习基础和C语言基础调查

20165103学习基础和C语言基础调查 学习基础和C语言基础调查 技能及其学习经验 在阅读老师做中学系列文章的时候,读到了一句话: 开发极点起因主要是个人兴趣爱好和工作需要. -- 引用自<做中学之五笔输入法实践教程> 回顾自己的不断的学习实践过程中,自己所学得比较好的知识.技能大多都是由于自身的兴趣加上工作需要才一步步逐渐掌握.在最近掌握的几个技能当中,太极拳这项技能勉强可以达到一个较高的水平. 学习经验 入门 首先还是因为对传统武术有一定兴趣,加之可以锻炼身体,便决定加入学校社团,开始学

安卓基础代码的重要性--------Fox出品

第一次写博客其实感觉挺奇怪的.本人是做视频加直播开发一年多.想写一些心得体验.那现在进入正题. 对程序员而言最重要的素质是代码质量.一年的多的工作其实感悟很大,或许很多人没有体验到代码的质量到底是什么.那么我在这边先提一下作为第一篇博客. 代码的质量不仅仅体现在代码少,实现一样的功能.代码的质量包括1:格式  2:注释 3:代码逻辑 4:语言的沉淀量 那么先讲解一下代码格式:其实我把代码格式放第一位是有原因的,个人认为代码的格式是代码里面最重要的一部分.格式:有千千万,可是代码的统一标准最好可以

Python源码剖析笔记0 ——C语言基础

python源码剖析笔记0--C语言基础回顾 要分析python源码,C语言的基础不能少,特别是指针和结构体等知识.这篇文章先回顾C语言基础,方便后续代码的阅读. 1 关于ELF文件 linux中的C编译得到的目标文件和可执行文件都是ELF格式的,可执行文件中以segment来划分,目标文件中,我们是以section划分.一个segment包含一个或多个section,通过readelf命令可以看到完整的section和segment信息.看一个栗子: char pear[40]; static

提高代码质量:如何编写函数

阅读目录 命名 函数参数 编写函数体 总结 函数是实现程序功能的最基本单位,每一个程序都是由一个个最基本的函数构成的.写好一个函数是提高程序代码质量最关键的一步.本文就函数的编写,从函数命名,代码分布,技巧等方面入手,谈谈如何写好一个可读性高.易维护,易测试的函数. 回到顶部 命名 首先从命名说起,命名是提高可读性的第一步.如何为变量和函数命名一直是开发者心中的痛点之一,对于母语非英语的我们来说,更是难上加难.下面我来说说如何为函数命名的一些想法和感受: 采用统一的命名规则 在谈及如何为函数取一