Golang 的设计追求极致的简洁。在 Golang 创始人 Rob Pike 向另外两位创始人发送的邮件中提到, Golang 被起名为“go”的原因,就是 go 这个单词很简单,方便用键盘输入,并且 Golang 配套的工具的命名也可以很简单。不仅如此,我们可以看到,C 语言有 37 个关键字,C++ 有 84 个,Golang 仅仅有 25 个。精益求精的关键字让学习和使用的负担减少了很多。
大部分语言在并发和异步编程上都比较麻烦,而 Golang 的 Goroutine 和 Channel 则是处理并发和异步的两个神器。方法返回多返回值的设计使用起来也很方便。很多人在学习 Golang 时,都能够在几天内上手,并开发出一个性能很不错的工具。
因为 Golang 语法简单,并发和异步编程简单,所以它是一门易学易用、并发和异步编程无痛点的语言。也就是说,从语言设计的层面,Golang 是好用的。
放眼市面上有不少编程语言饱受赞誉,但却很少甚至没有人使用它来开发项目。所以语言层面上的好用,也不代表它在实际的开发工作上也好用。下面我们在项目实践的层面上看看 Golang 的情况如何。
随着 Golang 的不断发展,现在已经有了很多应用使用 Golang 来进行开发,其中就包括如今已经大名鼎鼎的 Docker 和 Kubernetes。随着 Docker 和 Kubernetes 的成熟,又有越来越多的项目基于它们开发、部署和运维。如今 Kubernetes 已经成为了服务编排事实上的标准,在云端大量使用 Docker 和 Kubernetes 的现状,使 Golang 被称为云计算新一代的开发语言。
在大型项目中,使用微服务是大趋势。项目上云,把服务打包成一个个 Docker 镜像,使用 Kubernetes 来管理部署,是现在流行的玩法。微服务中的“服务”可以使用很多技术来开发,比如传统的 Java,新兴的开源跨平台框架 .NET Core 等等。当然使用 Golang 也可以,相对于其他技术,使用 Golang 开发的服务有一个巨大的优势:同样的功能,使用 Golang 开发,打包出来的镜像是最小的。
假如有一个简单的服务,使用 Java 开发,打包出来的 Docker 镜像大小可能在 700 MB 左右;使用 .NET Core 开发,打包出的 Docker 镜像大小可能在 200 MB 左右。也有一些缩减镜像大小的技术和工具,可以使 Java 的镜像减少到 100 MB,使.NET Core 的镜像减少到 60 MB。虽然看起来已经足够小了,但是如果使用 Golang 开发,打包出的镜像大小可能只有7 MB。
由于每次服务升级的时候都要把新镜像拉取到本地,这样带来的好处就是,Golang 镜像在传输和存储上的开销可能比其他镜像节省十倍到百倍。
强烈的对比。
也许你觉得,只不过是几十 MB,几百 MB 的差距而已,又不是当年硬件吃紧不得不省着用的时代,毛毛雨啦。首先,公司要赚钱,无非就是开源节流,不必要的浪费应该能省则省。其次,如果一个服务的镜像同时运行在几十个、几百个容器中,并且有几十个、几百个服务同时运行,那么在传输和储存上的开销差距就变得非常大了。
反正我认为 Golang 上手简单、功能强大,并且在云计算中节省资源,是一门好用的语言。
Go背后的设计思想是现代编程的“保守派”思绪,它的产生是因为像谷歌这样的工程团队已经开始遇到一些非常棘手的问题而在现有编程语言框架下不能很好地解决。因此他们决定去创新,用一种“退步”的思想去面对软件开发领域的大量新问题,这种“以退为进”是其最大的哲学思辨,也是能否Get到它的好用的最核心一点。
科技主导的进步论是今天社会的主流信仰,在软件开发的世界里面也是如此。毕竟计算机编程是最近30年主导创新的最重要的科学和技术基底层,所以这个领域内充斥着进步论应该是很好理解的。
进步论具体怎么体现呢?比如你去学习Node.js,那种激进的、灵活的社区文化开始会让你很燃、很兴奋,然而过一段时间以后,尤其是你自己经历的项目多了以后,你会发现过于激进有时候=“聪明反被聪明误”。这种不够谨慎的“唯技术进步论“思想现在在开发领域很常见,比如在很多现代编程语言里面,为了实现一些技术性的突破,会发明一些语言级别的新语法,而这些语法又与语言以前的一些语法逻辑相互矛盾或者无法兼容(比如为人熟知的Python的2、3不兼容问题、JS的ES6改革引起的浏览器兼容问题等等)。
与进步论相互呼应的,就是开发思想的分化。比如,现代编程里面,一个简单的函数往往都有多种实现方法。这些方法有些是因为计算机执行上有本质的不同(这是一种非常合理的不同,GO这种奉行简单的语言也会支持这些不同);而更多的不同完全都是基于语法、习惯、思维方式等方面的差异,某些时候一种函数甚至有数十种实现方法,到了让人抓狂的程度。
方法多、思路宽初看是好事儿,但从长远看它只是满足了人们思维的贪欲,对提高效率或者解决问题没有多少实质性的帮助。因为,几乎所有的应用都只是在解决有限问题,而随着项目和公司的发展,参与软件编写的人会越来越多,因此软件所要包容的思想也就越来越多。这样一来,大多数软件开发面临的中长期问题都变成了「由于软件越来越复杂而导致工程难以维护」这个问题。
说到这里,基本解释了Go的好处是「保持编程的简单和愚蠢」,下面总结一下。第一,这个好处需要对比才能感觉到;第二,这个好处需要一些经验和反思才能体会到。总之,这个好处不那么容易被初涉此道的人明显地感觉到,而对于另外一些有经验的人则会感受强烈,这也就是为什么很多活跃的Go开发者都是掌握多种语言的老鸟的原因。而另一方面,这个好处是直指现代软件工程的一些核心问题的,因此我认为时间和历史会证明Go的高明(“低明”?)之处。
另外,为什么这种简约的思想会招致一些非常明确的反对声音呢?我认为有两类原因,一类是人云亦云的思维惯性,如果你基于过往的经验来看待一个新事物,给它挑挑毛病其实是一件很简单的事情,但是瑕不掩瑜,这些毛病与其带来的好处相比,大都不是很重要的。或者说,随着时间的推移,都是可以被明显改善的。
另一类是“思想背后的利益”在作祟。在现代软件工程师的文化圈子里面,存在一些利益“山头”,也就是由于一些人把大量精力注入到某些编程语言、工作流当中,这些已经给他们个人或集团带来了大量的既得利益(财富方面的、社会影响方面的……),因此他们会自觉不自觉地捍卫自己的利益——通过各种对比来贬低Go语言,或者夸大一些问题。这一方面充斥于大量校园、培训机构里面,另一方面已经成为了很多大型互联网企业内的政治势力或者既得利益集团。只要去稍稍了解一下为了面试BAT、谷歌、亚马逊的那些职位要预先读多少书、考多少试题就不难感受到这些山头的实在性。
下面我从“保持简单和愚蠢”为什么未来对一个工程师来说整体上是一件好事来总结一下。首先,如果你是最近几年才开始接触计算机编程,而不是从几十年前就开始学习编程的老司机的话,那么你要面对的现实有如下几个要点:
1、现代的编程经过几十年的发展,其知识体系已经变得非常庞大而复杂
2、现代的计算机硬件架构也与几十年前相比发生了巨大的变化
3、应用和软件的需求变得日趋复杂
4、项目团队的组成和工程师的思维愈发多元化
5、人的认知能力有限,而且绝大多数人都没有那么聪明
为了面对这些问题,绝大多数编程语言选择的道路都是激进地改革,它们选择在语言层面进行「创新」,制造很多新的语法、加入很多新的概念。前文已经提到了这种激进思想导致的后果 —— 你除了要学习编程语言本身外,你还需要学习很多额外的“思想”,问题变得越来越复杂。
事实上,我个人认为学习很多语言难以深入某种程度上都是因为那些额外的“思想”太复杂或者太难以理解。我个人对学习Java和Scala时读那些规矩的痛苦记忆犹新。那些厚重的宝典里面,记录的不仅仅是聪明的编程思想,还有很多“你要当心”的思维规则限制。有时候,一个那样的规矩会让你学习编程完全卡住,因为你搞不明白为什么要这样,然后就会有一些沮丧——怀疑是不是自己太笨了,怀疑是不是自己“基础不好”还得恶补。
这时,如果你去问那些老鸟们这是怎么回事。由于幸存者偏差,以及只有成功者愿意分享经验之类的规律,你听到的都是那些绕过了或者渡过了这些坑的人的观点。他们大多数可能都并没意识到自己是怎么渡过那些坑的,甚至有人会觉得你搞不明白那些“思想”是很奇怪的,或者简言之——“你不够聪明”。
我得承认,我的确是没那么聪明,但是我不能蠢一点吗?“笨”方法就不可以解决问题了吗?事实上,如果接触过了,你会发现并不是那样,还是可以有笨方法的(而且这和编程语言没有直接的绑定关系,就是一种方法论)。
Go就是在语言层面上提供了这样一种可能性,就是简化,甚至部分地“语言退化”,以便适应日趋复杂的未来。当然,简单的背后肯定也有复杂的工作要做,比如对语法的抽象、基础包的建设、对这种思想的传播等等。而且,我的意思也并不是必须学习Go才能解决问题,Go也有它适合和不适合的领域,但是总体上讲,一个面向当下和未来的工程师应该要理解这种保持简单和愚蠢的可贵和重要性。
天下皆知美之为美,斯恶已。皆知善之为善,斯不善已。
Golang还处于发展阶段,其“善”还没有到世人皆知的程度。因此,我觉得它还在「好用」的阶段。