Go编程风格指南:开篇
以下是我正在撰写的付费技术专栏的第一篇文章的全文。现免费提供给大家,希望能对你所有帮助。(这篇专栏的暂定名为《Go编程风格指南》)
// -- BEGIN --
01 本质:Go语言的编程哲学
从 Golang 的 1.5 版本开始,来自Google公司的那只大神云集的开发团队几乎用Go语言实现了Go语言的全部——这就是传说中的自举。这包括:
编译器:即从编译器前端到编译器后端的所有代码。它不像有的编程语言,还需要使用LLVM作为自己的编译器后端,如 Rust、Julia、Swift 等。
工具链:即所有标准工具的全部功能。Go语言自带的工具几乎可以伴随我们走过软件生命周期的每一个阶段。它不像有的编程语言,还需要我们花费精力去寻找和学习第三方的工具。
标准库:即它自带的每一个函数库。这非常有利于我们对Go语言的使用和学习。一旦碰到了不熟悉的API,我们就可以直接去阅读相应的源代码。不像有的编程语言,很多底层功能甚至一些函数库都是由C语言程序实现的。
当然了,因为编程语言终归是要建立在操作系统之上的,所以Go语言的实现也免不了包含少许的汇编代码。
正因为Go语言的完全自举,我们才能从头至尾地欣赏到实现一门编程语言所需要涉及的全部代码、算法和设计。而且,它们都是非常经典的。也正因为这样,Go语言才能如此彻底地落实自己的编程哲学。
1.1 简约至上
Go语言是崇尚简约的,即:尽量用简洁的代码实现程序的一切功能。如果你仔细阅读过Go语言及其标准库中的源代码,那么应该会有所体会。
我认为,对于应用程序的编写来讲,Go语言的简约主要体现在了以下几个方面:
Go语言的关键字和操作符都是非常少的。它的关键字只有区区 25 个,而它的操作符和特殊符号(包括分号、冒号、逗号、点号、括号等)全部加起来也只有 47 个。
Go程序中无需添加多余的符号。或者说,所有的表达式和语句都足够的简洁。比如,Go程序中的每条语句都不需要尾随烦人的英文分号。又比如,跟在 if 关键字或 for 关键字后边的表达式并不需要用圆括号包起来。诸如此类。
Go语言只包含了极少的语法糖。你也许会着迷于一些编程语言中的语法糖。但是,你可能还没有意识到,很多语法糖都是规模化软件开发的隐形杀手。它们可以在无形当中大大地增加开发的协作成本和软件的维护成本。
在Go语言中,几乎每一类程序实体的声明都只有一种最佳的方式。对于操纵各种值的方式来说,也是这样的。比如,我们若要声明一个接口,必须让每一个方法声明都独占一行(类似的还有结构体类型的声明)。又比如,我们若要初始化一个字典或者通道,使用 make 函数准没错。
Go语言实际上是在用一定的内部复杂性换取应用程序的简洁性。比如,Go语言支持面向代码包的 init 函数,以及面向函数的 defer 函数。而在并发编程方面,不论是go程(goroutine)还是通道(channel)也都深刻地体现了这一点。
当然了,凡事都是有特例的。更何况,有时候过分的求简就相当于摒弃了编程的灵活性。拿变量的声明和数组的初始化来说,Go语言就提供了多种看起来差不多的方式。这就使得我们需要在编程的过程中进行适当的选择。至于怎样做选择,我在后边的文章里会详细论述。
你可能已经知道,相较于其他的编程语言,我们使用Go语言编写同样功能的程序有时候确实需要更多的代码行。但你可以思考一下,我们在追求“一行多用”的时候,是不是也正在增加程序的阅读难度呢?
为了实现同样的小功能,无论我们编写多行,还是只写一行,对于计算机来说几乎是无所谓的。然而,对于阅读程序的人来讲,这两种编写方式的差别还是很明显的。至于哪一种编写方式会让阅读更加困难,就不用我多说了吧?所以,程序的清晰和整洁要比潇洒和性感更重要。
解释一下,我在本课程中说Go语言的语法多么简约、并发模型多么易用、工具链多么完整、自举多么彻底,并不是要把这些事情再论述一遍。关于它们,我在我之前撰写的图书和专栏里已经说了很多了。我在这里要说的重点是,我们需要从Go语言的编程哲学和文化中吸取一些东西,并以此来优化我们的程序设计方式,以及提升我们的编程技巧。
1.2 契约优先
Go语言的安装可以很简单:
下载(与本地计算机的操作系统和计算架构)相对应的安装压缩包;
解压这个包得到 go 文件夹;
将go文件夹移动到一个合适的目录下(如 /usr/local/ );
设置一下系统环境变量 PATH(如追加 /usr/local/go/bin );
完成!
如果你使用过早期版本的Go语言的话,那么一定会发现,我们连 GOROOT 和 GOPATH 这两个环境变量都不用配置了。甚至,如果你对于“在任意的命令行下都可以执行go命令”这件事不在意的话,那么也不用去改动 PATH 变量。这意味着Go语言是“开箱即用”的。
如果从软件开发的角度讲,我们就需要提到“契约”这个词。我们可以把契约看作是一种多方都认可的约定。具体到这里,它是一种关于程序行为的约定。
你还记得在Go程序中怎样实现一个接口吗?很简单,对吧?只要一个类型的方法集合中包含了某一个接口定义的所有方法,那这个类型就自动地实现了该接口。我们不用在定义类型的时候明确指出它将要实现哪些接口,也不用在一开始就完全确定这件事情。这其实就是一种契约,只要你做了某件特定的事(或者说输入),就必然会产生对应的结果(或者说输出)。
不要忘了,只要我们把从属于某个类型的方法写到该类型所在的代码包中,这个方法和这个类型就可以自动且无缝地衔接上了。这就意味着,我们可以在需要的时候向一个类型追加一些方法,以使得它实现更多的接口,而不用去修改先前已经写好的代码和文件。这不但更加方便,还大大地降低了引入新BUG的可能性。
说到这里,你可能已经理解了。我们编写的程序应该为使用方多提供契约,少提供“必选”的配置。至少,我们要做到“开箱即用”。也就是说,用户在一开始使用程序的时候几乎不用做任何的配置,直接就可以用起来。当然了,如果用户在之后有一些特殊的要求,那么也应该可以自己做一些“可选“的配置。当用户能想到自己去定制一些东西的时候,他们很可能已经对程序比较熟悉了,从而不会遇到太大的障碍。
我再举一个例子。假设你为他人提供了一个函数作为API,这个函数有一些参数,并可以返回相应的结果。重点是,这些参数都是有默认值的。函数的调用方在不提供任何特定的参数值的情况下就可以直接进行调用,并能够得到基本的结果。也就是说,只要他有调用的动作,就会调用成功。另一方面,如果调用方在调用你的函数的时候提供了一些特殊的参数值,那么他就可以得到更加精确或者更加个性化的结果。
我们可以把“开箱即用”看作是一种契约。在缺省的情况下,供需双方衔接时不用再去对暗号,而是用默契取而代之。我再次建议我们在写程序时”多立契约,少做配置“,并把这当作一种风格甚至规范,严格的贯彻下去。这种贯彻可以明显地降低编程的成本。
1.3 实用主义
我们再来说Go语言的实用主义。你肯定知道,Go语言是一门“工程化”的编程语言。什么叫工程化呢?你可以把它理解成“为具有一定流程和规模的软件开发工作而提供便利”。
这主要体现在它自带的标准工具上。我们之前也说过,这些工具几乎覆盖了一个软件的全生命周期,包括开发、测试、文档、构建、安装、运行、监控、调优、迭代,等等。
另外,Go语言的语法也让开发变得简单,并间接地让维护更加容易。比如,对未使用变量的严格检查、对数值类型的精确划分、对流程控制的化繁为简、对指针的有限支持、对错误体系及错误处理方式的设计、对程序测试的有力支撑,等等。
关于它们的细节,只要对我们的程序编写和设计有启发的,我都会在后面一一讲到。现在,我们只需要知道,Go语言在基于标准流程的软件开发工作中的优势是非常明显的。其原因就在于,它提供给我们的每一样东西几乎都有利于人与人之间的协作,以及人与机器的协作。
你也许会觉得Go语言的一些特性仿佛并没有对提高开发效率有明显的帮助,甚至还略有降低,比如说“不支持泛型”和“通过结果值传递错误”。但是你要知道,软件开发过程当中最难以控制的成本是沟通和协作,而不是个人的开发工作量。对于有一定规模的软件开发工作来说,这一点尤为突出。
最后,我们也许可以反思一下,我们编写的程序是否足够的实用呢?是否可以切实地帮助开发团队节约成本和精力呢?
1.4 小结
在这一课,我们先从Go语言的自举谈起。Go语言的自举相当彻底。可以说,Go语言是一个完备且自洽的软件基础设施。这也使得它的编程哲学得以贯彻。
Go语言是崇尚简约的。它用简洁的代码实现了自身所需的全部功能,并为应用程序的开发者们提供了易用的API。只要仔细阅读它的源代码,我们就能感受得到。甚至,它在用一定的内部复杂性换取应用程序的简洁。由此可知,在Go语言看来,程序的清晰和简洁要比潇洒和性感重要得多。
Go语言推崇契约优先。Go语言本身可以做到“开箱即用”,其标准库中的绝大多数程序实体也是开箱即用的。当然了,如果你需要定制,Go语言也提供了一些可选的配置。这是一种优良的契约。不但如此,Go语言的语法也是基于契约的,比如接口的实现方式,类似的还有函数类型的实例化方式,等等。这也是Go语言的编程风格之一——多契约,少配置。
Go语言高举实用主义大旗。它为流程化和大规模的软件开发工作提供了相当多的便利。其中最突出的当属它自带的一系列标准工具。而Go语言的语法不但让开发工作变得简单,也间接地让维护更加容易。它给予我们的每一样东西几乎都有利于人与人之间的协作,以及人与机器的协作。要知道,这方面的成本消耗问题往往要比个人的开发效率问题更加重要。
好了,请你记住以上三个要点。它们都体现了Go语言最重要、最底层的编程哲学。在后面的课程中,我们提及的很多东西都会基于它们。
// -- END --
双 11 临近,我在这里也为大家提供一些实惠吧。没有任何套路,也不会额外占用大家的时间。
大家可能已经知道,我在 知识星球App 上创建了一个编程技术讨论类的星球(或者说群组空间),叫做 GoHackers VIP 。这个星球是付费进入的。
我刚刚发起了一个价格优惠,仅为原价的75% 。并且,我还给大家制作了 大力度的优惠券。这些优惠叠加之后,已经相当于 半价 了!如果你对编程感兴趣,对Go语言或Julia语言感兴趣,我非常欢迎你加入我的知识星球!无论如何,下面的优惠券还请你先收下(新人用第一个,老人用第二个),扫码即可查看并加入我的星球!
感谢你读到这里!期待我们在我的新专栏里再见!