Go语言最佳实战

Go 语言实战: 编写可维护 Go 语言代码建议

目录

1. 指导原则

1.1 简单性

1.2 可读性

1.3 生产力

2. 标识符

2.1 选择标识是为了清晰, 而不是简洁

2.2 标识符长度

2.3 不要用变量类型命名变量

2.4 使用一致的命名风格

2.5 使用一致的声明样式

2.6 成为团队的合作者

3. 注释

3.1 关于变量和常量的注释应描述其内容而非其目的

3.2 公共符号始终要注释

4. 包的设计

4.1 一个好的包从它的名字开始

4.2 避免使用类似 、 或 的包名称

4.3 尽早 而不是深度嵌套

4.4 让零值更有用

4.5 避免包级别状态

5. 项目结构

5.1 考虑更少,更大的包

5.2 保持 包内容尽可能的少

6. API 设计

6.1 设计难以被误用的 API

6.2 为其默认用例设计 API

6.3 让函数定义它们所需的行为

7. 错误处理

7.1 通过消除错误来消除错误处理

7.2 错误只处理一次

8. 并发

8.1 保持自己忙碌或做自己的工作

8.2 将并发性留给调用者

8.3 永远不要启动一个停止不了的

介绍

大家好,

我在接下来的两个会议中的目标是向大家提供有关编写 Go 代码最佳实践的建议。

这是一个研讨会形式的演讲,不会有幻灯片, 而是直接从文档开始。

贴士: 在这里有最新的文章链接

https://dave.cheney.net/practical-go/presentations/qcon-china.html

编者的话

终于翻译完了 Dave 大神的这一篇《Go 语言最佳实践》

耗时两周的空闲时间

翻译的同时也对 Go 语言的开发与实践有了更深层次的了解

有兴趣的同学可以翻阅 Dave 的另一篇博文《SOLID Go 语言设计》(第六章节也会提到)

正文

1. 指导原则

如果我要谈论任何编程语言的最佳实践,我需要一些方法来定义 “什么是最佳”。 如果你昨天来到我的主题演讲,你会看到 Go 团队负责人 Russ Cox 的这句话:

Software engineering is what happens to programming when you add time and other programmers. (软件工程就是你和其他程序员花费时间在编程上所发生的事情。)

— Russ Cox

Russ 作出了软件编程与软件工程的区分。 前者是你自己写的一个程序。 后者是很多人会随着时间的推移而开发的产品。 工程师们来来去去,团队会随着时间增长与缩小,需求会发生变化,功能会被添加,错误也会得到修复。 这是软件工程的本质。

我可能是这个房间里 Go 最早的用户之一,~ 但要争辩说我的资历给我的看法更多是假的~。 相反,今天我要提的建议是基于我认为的 Go 语言本身的指导原则:

简单性

可读性

生产力

注意:

你会注意到我没有说性能或并发。 有些语言比 Go 语言快一点,但它们肯定不像 Go 语言那么简单。 有些语言使并发成为他们的最高目标,但它们并不具有可读性及生产力。

性能和并发是重要的属性,但不如简单性,可读性和生产力那么重要。

1.1. 简单性

我们为什么要追求简单? 为什么 Go 语言程序的简单性很重要?

我们都曾遇到过这样的情况: “我不懂这段代码”,不是吗? 我们都做过这样的项目: 你害怕做出改变,因为你担心它会破坏程序的另一部分; 你不理解的部分,不知道如何修复。

这就是复杂性。 复杂性把可靠的软件中变成不可靠。 复杂性是杀死软件项目的罪魁祸首。

简单性是 Go 语言的最高目标。 无论我们编写什么程序,我们都应该同意这一点: 它们很简单。

1.2. 可读性

Readability is essential for maintainability.

(可读性对于可维护性是至关重要的。)

— Mark Reinhold (2018 JVM 语言高层会议)

为什么 Go 语言的代码可读性是很重要的?我们为什么要争取可读性?

Programs must be written for people to read, and only incidentally for machines to execute. (程序应该被写来让人们阅读,只是顺便为了机器执行。)

— Hal Abelson 与 Gerald Sussman (计算机程序的结构与解释)

可读性很重要,因为所有软件不仅仅是 Go 语言程序,都是由人类编写的,供他人阅读。执行软件的计算机则是次要的。

代码的读取次数比写入次数多。一段代码在其生命周期内会被读取数百次,甚至数千次。

The most important skill for a programmer is the ability to effectively communicate ideas. (程序员最重要的技能是有效沟通想法的能力。)

— Gastón Jorquera [1]

可读性是能够理解程序正在做什么的关键。如果你无法理解程序正在做什么,那你希望如何维护它?如果软件无法维护,那么它将被重写; 最后这可能是你的公司最后一次投资 Go 语言。

~ 如果你正在为自己编写一个程序,也许它只需要运行一次,或者你是唯一一个曾经看过它的人,然后做任何对你有用的事。~ 但是,如果是一个不止一个人会贡献编写的软件,或者在很长一段时间内需求、功能或者环境会改变,那么你的目标必须是你的程序可被维护。

编写可维护代码的第一步是确保代码可读。

1.3. 生产力

Design is the art of arranging code to work today, and be changeable forever. (设计是安排代码到工作的艺术,并且永远可变。)

— Sandi Metz

我要强调的最后一个基本原则是生产力。开发人员的工作效率是一个庞大的主题,但归结为此; 你花多少时间做有用的工作,而不是等待你的工具或迷失在一个外国的代码库里。Go 程序员应该觉得他们可以通过 Go 语言完成很多工作。

有人开玩笑说,Go 语言是在等待 C ++ 语言程序编译时设计的。快速编译是 Go 语言的一个关键特性,也是吸引新开发人员的关键工具。虽然编译速度仍然是一个持久的战场,但可以说,在其他语言中需要几分钟的编译,在 Go 语言中只需几秒钟。这有助于 Go 语言开发人员感受到与使用动态语言的同行一样的高效,而且没有那些语言固有的可靠性问题。

对于开发人员生产力问题更为基础的是,Go 程序员意识到编写代码是为了阅读,因此将读代码的行为置于编写代码的行为之上。 Go 语言甚至通过工具和自定义强制执行所有代码以特定样式格式化。这就消除了项目中学习特定格式的摩擦,并帮助发现错误,因为它们看起来不正确。

Go 程序员不会花费整天的时间来调试不可思议的编译错误。他们也不会将浪费时间在复杂的构建脚本或在生产中部署代码。最重要的是,他们不用花费时间来试图了解他们的同事所写的内容。

当他们说语言必须扩展时,Go 团队会谈论生产力。

2. 标识符

我们要讨论的第一个主题是标识符。 标识符是一个用来表示名称的花哨单词; 变量的名称,函数的名称,方法的名称,类型的名称,包的名称等。

Poor naming is symptomatic of poor design. (命名不佳是设计不佳的症状。)

— Dave Cheney

鉴于 Go 语言的语法有限,我们为程序选择的名称对我们程序的可读性产生了非常大的影响。 可读性是良好代码的定义质量,因此选择好名称对于 Go 代码的可读性至关重要。

2.1. 选择标识符是为了清晰,而不是简洁

Obvious code is important. What you can do in one line you should do in three.

(清晰的代码很重要。在一行可以做的你应当分三行做。(if/else 吗?))

— Ukiah Smith

Go 语言不是为了单行而优化的语言。 Go 语言不是为了最少行程序而优化的语言。我们没有优化源代码的大小,也没有优化输入所需的时间。

Good naming is like a good joke. If you have to explain it, it’s not funny.

(好的命名就像一个好笑话。如果你必须解释它,那就不好笑了。)

— Dave Cheney

清晰的关键是在 Go 语言程序中我们选择的标识名称。让我们谈一谈所谓好的名字:

好的名字很简洁。好的名字不一定是最短的名字,但好的名字不会浪费在无关的东西上。好名字具有高的信噪比。

好的名字是描述性的。好的名字会描述变量或常量的应用,而不是它们的内容。好的名字应该描述函数的结果或方法的行为,而不是它们的操作。好的名字应该描述包的目的而非它的内容。描述东西越准确的名字就越好。

好的名字应该是可预测的。你能够从名字中推断出使用方式。~ 这是选择描述性名称的功能,但它也遵循传统。~ 这是 Go 程序员在谈到习惯用语时所谈论的内容。

让我们深入讨论以下这些属性。

2.2. 标识符长度

有时候人们批评 Go 语言推荐短变量名的风格。正如 Rob Pike 所说,“Go 程序员想要正确的长度的标识符”。 [1]

Andrew Gerrand 建议通过对某些事物使用更长的标识,向读者表明它们具有更高的重要性。

The greater the distance between a name’s declaration and its uses, the longer the name should be. (名字的声明与其使用之间的距离越大,名字应该越长。)

— Andrew Gerrand [2]

由此我们可以得出一些指导方针:

短变量名称在声明和上次使用之间的距离很短时效果很好。

长变量名称需要证明自己的合理性; 名称越长,需要提供的价值越高。冗长的名称与页面上的重量相比,信号量较小。

请勿在变量名称中包含类型名称。

常量应该描述它们持有的值,而不是该如何使用。

对于循环和分支使用单字母变量,参数和返回值使用单个字,函数和包级别声明使用多个单词

方法、接口和包使用单个词。

请记住,包的名称是调用者用来引用名称的一部分,因此要好好利用这一点。

我们来举个栗子:

在此示例中,变量 的在第 行被声明并且也只在接下来的一行中被引用。 在执行函数期间存在时间很短。如果要了解 的作用只需阅读两行代码。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181107B0RX7900?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券