今年是举办 ECUG Con 的第 11 年,之前我谈的基本都是服务端的开发实践。从去年起我开始不谈后端而是谈前端。当然,去年我没有说为什么我会关注前端。今天再谈 Go 语言在前端的应用之前,我先简单聊一下思路脉络,为什么我今天会关注前端。
前端的演进
最早的 PC 时期,常见的设备主要是台式机、笔记本。这两类设备是 PC 时代主流设备,用的操作系统主流的是三个,分别是 Mac 、 Linux、Windows。前两者市场占有率非常少,基本是 Windows 一统天下。浏览器早期因为 Windows 的流行,主要是 IE,但在今天 Chrome 市场占有率非常高。另外还有 Safari、Firefox,大家也都耳熟能详。
从苹果发布 iPhone 为标志,我们开始进入移动时期。这个时期的设备主要是手机和平板,以手机为主。操作系统基本是安卓和 iOS,像 Windows Mobile 之类的占比非常少。浏览器不是 Chrome 这类桌面浏览器,而是从微信小程序开始,有了移动时代的浏览器。在国内小程序的种类非常多,包括支付宝小程序、头条小程序等等。我认为这才真正是移动浏览器战争的开始。
比较奇怪的是,为什么移动浏览器之争没有在美国开始,而是在中国开始,这也是比较有意思的地方。小程序相关的技术,无论是谷歌还是其他公司,也都在琢磨,当然也可能是我孤陋寡闻,我没有看到国外出现移动浏览器的迹象。为什么我说 Chrome 这些不是移动下的浏览器,是因为操作手感差别非常大。微信小程序是试图让 BS 结构的应用和 Native 应用手感无差别,这是非常重要的尝试。
我也畅想了一下未来,移动时期设备还比较少,笔记本、手机、平板是最主流的设备。台式机今天不太见得到,但笔记本大家经常会用。ECUG 是在 2007 年,差不多苹果发布苹果手机时开始的。在那时候,我做了一个判断,未来是一个强悍的服务端加上多元化的终端,其实就是前端。但今天在我看来,前端多元化还没有真正意义上的出现。
在 ECUG 的第 11 年,可以看到这个多样化的趋势已经越来越趋向于现实,包括手机之后下一个前端战场,在我看来是汽车。汽车非常火爆。当然,会有更多设备,很多人都会认为下一个是所谓的物联网时代,我们不必谈这么抽象的名词,也能预测到未来前端的趋势会非常多元化。这个多元化和 PC 时期、移动时期都非常不一样,因为屏幕的尺寸在前端交互里占非常关键的因素。除了汽车,今天手表也蛮多,但普及率可能还不如手机和平板。手表是一个很特别的东西,它在这么小的屏幕上,要把前端玩出花来,其实是非常难的事情。未来操作系统到底会是怎么样的?今天还是未知状态。
前端的演进跟设备演进非常有关联。所以前端的演进是大起大落的,这和服务端非常不一样。服务端的发展非常稳健。操作系统偏 Unix 系为主,到今天仍然如此,不太剧烈变动。但前端由于终端变化,导致操作系统的演进非常剧烈。
云计算的演进
云计算的演进,我分三个阶段:一阶段,以亚马逊的 EC2 为典型代表的,我叫做机器计算阶段。虚拟机(VM)为基础构建了整个体系结构。虚拟机和物理机没什么区别,现在大家摸不到虚拟机,但从操作一台虚拟机手感来说和物理机区别不大。
今天看到很多不一样的地方,因为容器兴起了,从 2014 年开始兴起到今天典型的标志是 Kubernetes 一统了容器操作系统的天下。以这样的基础,能看到云计算演进到了第二阶段。容器计算时期和机器计算时期的计算不太一样,容器会越来越关注运维的自动化以及相关基础支撑,它最终要达到的目标是让服务端基本趋向于免运维。以后大家做业务时,基本不用太在意服务端的事情。
这也会带来另外一个问题,再下一阶段云计算会走向哪里?在我看来是应用计算。因为云已经随着容器技术的发展越来越标准,云计算下一阶段应该会偏向于业务,和业务做越来越强的融合,不再只是关注基础架构,而是关注应用本身的业务架构。应用业务架构里,端占非常大的成份。云计算和端并不是割裂的。
云+端的演进趋势
今天我为什么会谈前端?当下我们仍然在很努力地推进后端技术的标准化,但在我看来,在可以预期的几年内这个事情就会被解决,更远的未来一定会把精力花在前端。
很多人都知道七牛云跟 Go 语言非常有渊源,我自己大概在 2012 年也比较狂妄地做了一个预测,认为 Go 语言一定会进语言排行榜靠前,我设的时间是 10 年左右。2012 年到现在差不多进入第 7 个年头。Go 是很专注的语言,用 Go 的人基本都集中在后端的开发,而且是偏向于后端 API 层面的开发,Web 占比相对少很多。Go 的专注使得它今天基本占领整个云计算领域。很多云计算公司技术栈,Go 在里面的占比会越来越高。这样的专注也让 Go 语言在今年里程碑式地进入前十的排名。
Go 语言的演进
为什么 Go 语言适合做前端?
前端是开发人员最多,需求量最多的工种,对语言的要求一定是入门门槛比较低,心智负担最小。而这个非常适合 Go。我 2011 年推 Go 时,大部分人不太了解 Go,但今天 Go 语言的受众已经非常广,大家有很大共识的一点是,Go 语言的入门门槛非常低,心智负担比较少。基本程序写出来编译通过,大概率没有问题。这样的特性使得它非常适合前端。
前端需要工程化更强的语言
前端业务量非常大,所以前端代码量比后端多很多。前端是负责和用户打交道的,和人打交道的东西是最复杂也最容易发生变化的。今天可能这个知识更好,明天可能换了一种新的知识,尤其是我前面提到了端的变化。从 PC、笔记本到手机,屏幕尺寸不一样,以及过去以键盘为交互主体变成了触摸屏,再到未来手表或者汽车。为什么很多公司都关注语音交互,就因为像汽车、手表这样的设备,语音交互是一个比较好的手段。但这些都有很大的不确定性。前端的变化是很剧烈的,而交互的手感以及为了让用户舒服、爽,程序员要付出的努力也会是非常大的。前端的代码量一定是最多的。
前端非常需要有强工程化能力的语言。今天我们看到前端的代码量肯定是 JavaScript,但 JavaScript 几乎是没有工程化支持的。它之所以叫 Script,是因为小,类似于微信小程序。大家仔细想想,小程序一定不小。在这样一个不小的东西上,或者代码量更多的应用里,需要工程语言更强。JavaScript 为什么流行,是因为它的「垄断地位」。有个趋势已经发生了,但今天还不是特别强烈,就是会有越来越多语言进军前端,Go 只会是其中之一。这是由需求决定的,我也认为 Go 是最有希望的那几个之一。
前面谈为什么我会在 ECUG Con 谈前端,今天我讲的东西,也许对大家影响不会太大,因为 Go 做前端毕竟还非常初级,但 ECUG Con 我希望它是一个前瞻趋势探索的会议,我并不倾向于它一定是非常实用的,它不需要今天跟大家聊了,明天就把它用到工程上,我对它并不是这样的定义。我希望 ECUG 本身是一种对未来有预见的社区。
Go 在前端的进展
回顾 Go 在前端的进展,GopherJS 是真正产生了影响力的进展。在 GopherJS 之前有非常多人做前端相关的事情。谷歌也有人推出了一个框架叫做 GXUI,GXUI 今天已经不怎么维护了。
很多人会试图做跨平台的框架,但实际上跨平台的框架最有希望的一定是浏览器。因为浏览器就是跨平台框架。在我看来,像 QT 包括谷歌做的 GXUI,都相对比较局限。但 GopherJS,我认为它是在前端真正能立得住脚的尝试。他就是干我刚才说的事情,让 Go 语言的程序员能写前端。怎么写?它做了一个编译器,这个编译器把 Go 代码翻译成 JavaScript 代码,自然而然 Go 就能写前端了。它是把 JavaScript 作为前端的一个机器语言,因为 JavaScript 的位置是绕不过去的。
但也不见得真的绕不过去。前端的机器语言在今天的标准肯定是 JavaScript,但我们也看到了另外一个东西,叫 WebAssembly,顾名思义它将自己看做是 Web 的汇编语言。但其实这个 WebAssembly 是二进制的,我觉得说它是 Web 的汇编语言,不如说它是 Web 的机器语言。WebAssembly 的覆盖面比大家想象得要广,今天所有主流的浏览器都已经支持了。JavaScript 的「垄断位置」已经有一些变化了,它并不会一直这样垄断下去。大家可能也听过 Go 已经支持 WebAssembly,而且是语言内建支持,这对 Go 来说也是非常重要的。
Go 在前端的进展,第二个大里程碑事件是 Go 内建支持了 WebAssembly(https://github.com/golang/go/wiki/WebAssembly)。从 Go 的 1.11 版本开始。这是 Go 官方对 WebAssembly Go 支持的介绍,编译过程是把 GOOS 环境变量定义成 js,架构选 wasm,这样就可以编译出 wasm 文件,而不是本地的可执行程序。这里有一些 DEMO,是一些社区的人用 Go 写的 WebAssembly 样例。
DEMO 样例展示:
这展示的效果就是后面的源代码实现的。看起来好像也没有什么,但这个支持是非常关键的。Go 开始在语言内建就支持 Web 前端的开发。尽管今天它还是一个经验版的状态,但也是非常重要的里程碑。做这件事情的人和前面干 GopherJS 是同一波人。有那么一堆人他们在努力把 Go 推向前端。
前面两个如果大家关注 Go 语言应该比较多人知道,但接下来这件事情应该大部分人都不知道。有一个新东西叫做 TinyGo,它是在嵌入式设备上跑 Go,它是一个剪裁版的 Go(https://github.com/aykevl/tinygo)。因为 Go 主要是针对服务端开发,所以大家对 Go 编译出的可执行文件有多大一点都不在意,但如果留意过就知道它非常大。TinyGo 试图让编译出的文件足够小,因为在嵌入式设备上磁盘空间非常珍贵,内存也很珍贵。它居然也支持 WebAssembly,能够做 Web 开发,虽然裁掉了很多 Go 的特性。不知道它后面的演化怎么样,因为这个项目还非常新,不到一年。对于新出现的东西,我们只能关注,也没有办法真的用到什么工程上。
Go 2D 游戏开发引擎(https://github.com/hajimehoshi/ebiten),实际上 3D 已经出现了,今天没有列出来。这个游戏引擎是日本人做的,而且已经拿它做了多款的手游开发。它是一个已经商业化的引擎。支持的平台非常广,用这个游戏引擎做出的游戏能够支持 PC操作系统如 Windows、Mac、Linux、FreeBSD,也支持手机操作系统Android、iOS,还支持 Web 开发如 GopherJS、WebAssembly。它是一个生产级的引擎。我去年演示的 DEMO,用 Go 写了一个少儿编程语言 Scratch 的解析器,这个解析器就是用这个 2D 游戏开发引擎做的。
下一个有趣的东西是 Go 的前端代码托管(https://github.com/dave/jsgo)。JavaScript 有很多公开的前端代码托管,但这里出现了 Go 前端代码托管。直接往这里一扔就直接上云了。这看起来很小众,但有人干这些事情。
这也有一些 DEMO:
-
这是一个拼数字的游戏。
-
这是俄罗斯方块。
-
这是一个游戏,大家之前见过的版本是小鸟,不是土拨鼠。
-
这是一个 To do list 类的 Web 应用。加它只是为了展示 Go 也能做一个标准的前端开发。
Jsgo.io 既支持 GopherJS 也支持 WebAssembly。我们刚才看到的游戏,不是一个 js 文件,是很多个。源代码里,Go 会 import 一些 Go 标准库,比如字符串转换库 strconv。字符串转换 Go 标准库会直接被编译成一个单独的 js 文件。这个做法的好处是慢一点,但后面的加载会非常快(因为基本不用改)。大的前端应用这样被拆解之后,从长远来说加载速度会比较快。它支持分模块加载,而且我们不用为分模块加载付出什么努力,Go 的引用会变成一个模块引用,对应到 js 也是一个模块。这样编程会非常爽。前端 JavaScript 语言里,这种模块化编程并不是语言内建支持的。
Jsgo.io 对 WebAssembly 的支持目前还不体完善,跟刚才的 GopherJS 不一样,它目前不能做到分 package 引用,编译出来的是一个大的 wasm 文件。但这只是临时状态,因为这块的支持才刚开始做。
前面我也说过,Go 的通用卡平台 gui 库很多人在尝试,但无一不是失败告终。这并不是由于 Go 引起的,是因为像 QT 这类的跨平台方案本身并不是符合趋势的东西。最有希望的跨平台方案还是浏览器技术,基于 HTML5 和小程序,它们是真正的生产级的跨平台方案。尤其是小程序的出现,今天看到很多跨平台库,比如 React 做出的应用还是有生硬的地方,但微信小程序是试图让 Web 跟 Native 体验一致的。
Go 在前端的发展展望
Go 跨平台的游戏引擎,已经基本接近生产级,它是非常重要的突破口。
在我看来,Go 在前端的突破,一定是从游戏领域开始。它对 Go 的意义是 0 到 1 的历史性突破。如果没有商业公司用它,这个东西就是一个玩具。但 Go 的游戏引擎不会是玩具,因为会有越来越多商业公司用它。未必是这个游戏引擎,也许会有人做出更牛的,但这是个靠谱的方向。对于 Go 来说,就跟 Docker、Kubernetes 的流行代表 Go 占领了云一样。Go 在前端也需要一个杀手锏,它就是游戏引擎。