推荐序一
很高兴听到谢孟军的《Go Web编程》要出版。当谢孟军找我写推荐序时,尽管工作非常繁忙,我还是一口应承下来了。原因很简单,作为国内首家完全采用Go语言开发的公司,七牛非常乐意见到Go语言社区的繁荣。去年在Google Trends上Golang关键字的搜索指数,中国排在全球首位(比美国多3倍),这是整个中国Go语言社区共同努力的结果。
远在2007年第2届ECUG大会,我讲了《我为什么选择了Erlang》的议题。其中提到了我对未来软件产业趋势的判断:
● 存储与计算向服务端转移
● 从“PC单机”到“强悍的服务器+多元化的终端”(手机、PC、PDA、电视机顶盒、车载终端)
这个趋势判断对我职业生涯的影响非常重大。它促使我放弃了近 10 年的桌面开发经验(包括大学时期),转向服务端开发。正如我在《我为什么选择了Erlang》中建议的那样:
● 要么就不写程序,要么就写服务器端的程序
● 当然,你也可以去撰写移动终端设备上的代码,在PC平台上做开发的空间很小
于是,我开始了长达四、五年之久的服务端开发最佳实践的探索。直到有一天,我遇到了Go语言。
我从来不认为自己是一个预言师,但关注过我的人可能都知道,我在新浪微博、《Go语言编程》一书中都非常高调地下了一个论断:Go 语言将超过 C 语言、Java,成为未来十年最流行的语言。
为什么我可以如此坚定地相信,选择Go语言不会有错,并且相信Go语言会成为未来十年最流行的语言?除了Go语言的并发编程模型深得我心外,Go语言的各种语法特性显得那么深思熟虑、卓绝不凡,其对软件系统架构的领悟,让我深觉无法望其项背,处处带给我惊喜。
Go语言给我的第一个惊喜,是大道至简的设计哲学。
Go语言是非常简约的语言。简约的意思是少而精,少就是指数级的多。Go语言极力追求语言特性的最小化,如果某个语法特性只是少写几行代码,但对解决实际问题的难度不会产生本质的影响,那么这样的语法特性就不会被加入。Go 语言更关心的是如何解决程序员开发上的心智负担。如何减少代码出错的机会,如何更容易写出高品质的代码,是Go语言设计时极度关心的问题。
Go 语言追求显式表达。任何封装都是有漏洞的,最佳的表达方式就是用最直白的表达方式。所以也有人称Go语言为“所写即所得”的语言。
Go 语言也是非常追求自然(nature)的语言。Go 不只是提供极少的语言特性,并极力追求语言特性最自然的表达,也就是这些语法特性被设计成恰如多少人期望的那样,尽量避免争议。事实上Go语言的语法特性上的争议非常少,这些也让Go语言的入门门槛变得非常低。
Go语言给我的第二个惊喜,是最对胃口的并行支持。
我对服务端开发的探索,始于 Erlang 语言,并且认为 Erlang 风格并发模型的精髓是轻量级进程模型。然而Erlang除了语言本身不容易被程序员接受外,其基于进程邮箱做消息传递的并发编程模型也小有瑕疵。我曾经在C++中实现了一个名为CERL的网络库,刚开始在C++中完全模仿Erlang风格的并发编程手法,然而在我拿CERL库做云存储服务的实践中,发现了该编程模型的问题所在并做了相应的调整,这就是后来的CERL 2.0版本。有意思的是,CERL 2.0与Go语言的并行编程思路不谋而合。某种程度上来说,这种默契也是我创办七牛时,Go 语言语法特性甚至都还没有完全稳定,我们技术选型就坚决地采纳了Go语言的重要原因。
Go语言给我的第三个惊喜,是interface。
Go语言的interface,并非是你在Java和C#中看到的interface,尽管看起来有点像。Go 语言的 interface 是非侵入式的接口,具体表现在实现一个接口不需要显式地进行声明。不过,让我意外的不是Go语言的非侵入式接口,非侵入式接口只是我接受Go语言的基础。在接口(或契约)的表达上,我一直认为Java和C#这些主流的静态类型语言都走错了方向。C++的模板尽管机制复杂,但是走在了正确的方向上。C++0x(后来的C++11)呼声很高的concept提案被否,着实让不少人伤了心。但Go语言的interface远不是非侵入式接口那么简单,它是Go语言类型系统的纲,这表现在:
1.只要某个类型实现了接口要的方法,那么我们说该类型实现了此接口。该类型的对象可赋值给该接口。
2.作为1的推论,任何Go语言的内置对象都可以赋值给空接口interface{}。
3.支持接口查询。如果你曾经是Windows程序员,你会发现COM思想在Go语言中通过interface优雅呈现。并且Go语言吸收了其中最精华部分,而COM中对象生命周期管理的负担,却因为 Go 语言基于 GC(垃圾回收机制)方式的内存管理而不复存在。
Go语言给我的第四个惊喜,是极度简化但完备的“面向对象编程(OOP)”方法。
Go语言废弃大量的OOP特性,如继承、构造/析构函数、虚函数、函数重载、默认参数等,简化的符号访问权限控制、将隐藏的this指针改为显式定义的receiver对象。Go语言让我看到了OOP编程核心价值原来如此简单——只是多数人都无法看透。
Go语言带给我的第五个惊喜,是它的错误处理规范。
Go语言引入了内置的error类型及defer关键字来编写异常安全代码,让人拍案叫绝。下面这个例子,我在多个场合都提过。
f, err := os.Open(file) if err != nil { ... // error processing return } deferf.Close() ... // process file data
Go语言带给我的第六个惊喜,是它功能的内聚。
一个最典型的案例是Go语言的组合功能。对于多数语言来说,组合只是形成复合类型的基本手段,这一点只要想想C语言的struct就清楚了。但Go语言引入了匿名组合的概念,它让其他语言原本需要引入继承这一新概念来完成事情,统一又到了组合这样的一个基础上。
在C++中,你需要这样定义一个派生类。
class Foo : public Base { ... };
在Go语言中你只要
type Foo struct { Base ... }
更有甚者,Go语言的匿名组合允许组合一个指针。
type Foo struct { *Base ... }
这个功能可以实现C++中一个无比晦涩难懂的特性,叫“虚拟继承”。但同样的问题,换从组合角度来表达,直达问题的本质,清晰易懂。
Go语言带给我的第七个惊喜,是消除了堆与栈的边界。
在Go语言之前,程序员是清楚地知道哪些变量在栈上,哪些变量在堆上。堆与栈是基于现代计算机系统的基础工作模型上形成的概念,Go 语言屏蔽了变量定义在堆还是栈上这样的物理结构,相当于封装了一个新的计算机工作模型。这一点看似与Go语言显式表达的设计哲学不太一致,但我个人认为这是一项了不起的工作,而且与Go语言的显式表达并不矛盾。Go 语言强调的是对开发者的程序逻辑(语义)的显式表达,而非对计算机硬件结构的显示表达。对计算机硬件结构的高度抽象,将更有助于Go语言适应未来计算机硬件发展的变化。
Go语言带给我的第八个惊喜,是Go语言对C语言的支持。
可以这么说,Go语言是除了Objective-C、C++这两门以兼容C为基础目标的语言之外的所有语言中,对 C 语言支持最友善的一个。什么语言可以直接嵌入 C 代码?没有,除了Go语言。什么语言可以无缝调用C函数?没有,除了Go语言。对C语言的完美支持,是Go语言快速崛起的关键支撑。还有比C语言更让人觊觎的社区财富么?那是一个取之不尽的金矿。
总而言之,Go语言是一门非常具变革性的语言。尽管这四十多年来(从20世纪七十年代C语言诞生开始算起)出现的语言非常多,各有各的特色,让人眼花缭乱。但是我个人固执地认为,谈得上突破了C语言思想,将编程理念提高到一个新高度的,仅有Go语言而已。
Go语言很简单,但是具备极强的表现力。从目前的状态来说,Go语言主要关注服务器领域的开发,但这不会是Go语言的完整使命。
我们说Go语言适合服务端开发,仅仅是因为它的标准库支持方面,目前是向服务端开发倾斜:
● 网络库(包括socket、http、rpc等)
● 编码库(包括json、xml、gob等)
● 加密库(各种加密算法、摘要算法,极其全面)
● Web(包括template、html支持)
而作为桌面开发的常规组件:GDI和UI系统与事件处理,基本没有涉及。
尽管Go还很年轻,Go语言1.0版本在2012年3月底发布,到现在才1年多,然而Go语言已经得到了非常普遍的认同。在国外,有人甚至提出“Go语言将制霸云计算领域”。在国内,几乎所有你听到过名字的大公司(腾讯、阿里巴巴、京东、360、网易、新浪、金山、豆瓣等等),都有团队对Go做服务端开发进行了小范围的实践。这是不能不说是一个奇迹。
与之相反的是,因为年轻,Go 语言的资料,尤其是中文资料极度匮乏。在这样的背景下,《Go Web编程》这样一本有非常强的实践背景的图书出版了,这绝对是雪中送炭。
《Go Web编程》围绕做一个Web服务相关的一个个问题域展开:表单处理、数据库、会话(Session)、安全、国际化和本地化、日志、部署与维护。最后,结合作者的实践,本书给出了一个参考的Web编程框架,以简化Web编程,提升开发效率。
无论是对那些只是听过 Go 语言而打算开始了解的朋友,还是对那些已经进行 Go语言开发的朋友,本书都极具参考价值。
另外值得一提的是,除了《Go Web编程》一书外,谢孟军也发起了Go语言标准库文档的翻译工作,这是一项艰苦的工作,但可以预期将对Go语言的发展起到重要作用,读者如果有意为开源贡献自己的一份力量,欢迎你能够积极参与其中。
七牛云存储CEO 许式伟
2013年4月