任何复杂系统都是由简单构建起来的——Factorio 和软件工程

2018年6月21日 · 6 years ago

任何复杂系统都是由简单构建起来的——Factorio 和软件工程

我很喜欢沙盘游戏,尤其是模拟建设类,不管是最近的 Rim World, Factorio 还是古老的《宙斯:众神之王》、《模拟城市 3000》,都能让我沉迷很长时间。

我的职业是程序员,很多同事喜欢自己的产品被很多人使用的感觉,但我却更喜欢“由自己从零开始创造东西”的体验。在办公室里敲出来的东西往往是多人合作的结果,是多方 trade off 的产出。所以相比于在大公司敲代码,作为个人开发者做出来的东西更能让我感到愉悦,尽管用户量级无法相提并论。

玩沙盘游戏本质上就是在从零创造。只是比起在现实世界写代码,游戏里的规则更加明确,反馈更及时,也少了大量干扰元素,使得玩家可以全力集中在“创造”这件事情上。2012 年在 Steam 上架的 Factorio 是我目前玩过的游戏里最接近“写代码”这件事情的,在游戏里你要解决的问题和在软件工程中要解决的非常相似,在逻辑上两者的思路是一致的。

零、都是工程

Factorio 中文译名为“异星工厂”,游戏的背景是在外太空的某个荒凉的星球上,玩家可以操控一个唯一的人物,用他来挖矿,采集资源,建造工厂,通过流水线把原始的简单手工劳作变成极度复杂的自动化作业。玩家在游戏过程中不断面临各种复杂工程带来的问题,如何设计合理的区域规划,如何搭建纵横交错的物流系统,如何应对污染带来的虫族袭击等等等等,这些问题是环环相扣,相互联动的。

在实际写代码的过程中,程序员也会面临项目变大以后带来的种种问题。以我熟悉的 iOS 客户端开发为例,在游戏中利用自动化替代重复低效的手工劳作就像在工程中把 Copy and Paste 的代码抽象成可复用的 Pure Function 从而一步步变成可重用的模块;在游戏中解决传送带规划问题就像保证数据传递在整个 App 里的可靠性(数据在流动过程中不被篡改)和及时性(性能)。还有很多类似的问题可以直接在软件工程中找到非常相近的映射,玩 Factorio 的过程就像在写代码一样。

一、新的游戏

游戏一开始人物出现在荒凉的星球上,周边有几种基础资源:

  • 可用作燃料的煤炭
  • 可制造其他东西的原料:铁矿、铜矿、石矿
  • 还有水池和森林

游戏初期我们只需要上述资源就可以开始动手建工厂了。游戏人物可以手动挖矿,效率非常低,玩家必须一直按住鼠标。挖到第一块煤之后就可以建造热力挖矿机,踏出生产力解放的第一步。但这个时期玩家还是要操作人物在地图上跑来跑去,从煤矿区拿煤到其他矿区补充给挖矿机,如果有自动添煤的东西就好了。

于是我们开始在水池边放上水泵,抽出来的水导入锅炉里加热产生蒸汽,再造个蒸汽机可以发电了,再把电线拉到矿区,修上传送带和机械爪,把煤矿产出的煤通过传送带运到其他矿区,机械爪就可以自动给挖矿机填煤。于是游戏中最简单的自动化挖矿流程就跑起来了,玩家不再需要操作人物跑来跑去,一切就自动运转起来了,多么美好!

这种从空地图开始构建新工厂的感觉和从零开始写一个新的项目是一样的。软件项目刚启动的时候,一切都是空白的,操作系统提供的能力就像游戏地图里提供的各类资源,我们根据这些资源构建出一个新的 App、网站、服务,就像在游戏里一步步修成一个巨大的工厂。

写下第一行代码 "Hello World!" 之后我们就要开始写函数,形成独立模块,慢慢演变成一个更加复杂的项目。一旦项目复杂起来,数据传递就成了一个复杂的问题。比如现在大家一个很常见“头像”这个东西,他本质上是一个图片,可以用一个 URL 表达。这个 URL 有可能会发生改变,一旦改变我就要在整个 App 刷新用到这个头像的所有图片。从知道 URL 改变的那个地方,把这个新的 URL 传递给 App 里的所有地方这件事情,就是数据传递,这样的数据传递在软件工程里比比皆是,像极了游戏里把煤炭传送到各个矿区这件事情。

头像

除了数据传递,还有封装(Encapsulation)。所谓封装就是把很多数据和对数据的操作放到一个黑盒子里,用的人不需要管里面具体长啥样,你只要丢一个数据进去,它就会变成另一个东西出来。我们还是以头像为例,头像的 URL 是一段很长的文本,光看文本鬼知道你长啥样,所以我们需要拿这个 URL 去下载对应图片然后显示到屏幕上。这样我们可以设计一个黑盒,他的输入是一个 URL 文本,输出就是一个图片。这就是非常简单的封装。

黑盒

在 Factorio 这个游戏里,我们通过传送带来实现输入输出。基础资源就那么几个,但是我们建造复杂产品需要用电路板,电路板需要铜线和齿轮,铜线需要铜片,铜片由铜矿石冶炼而成,齿轮则由铁矿石冶炼成铁片再加工而成。于是我们可以看到,负责产出电路板的流水线,他的输入是铁片和铜片(一般铁矿石都会冶炼完再上传送带),输出就是电路板。

Factorio 的玩家社区里有很多非常聪明的玩家给出了各种黑盒设计图,其他玩家可以学习他的布局方法来实现自己的黑盒。这种分享行为在软件开发里叫做开源。在软件开发过程中,很多问题是大多数都会遇到而操作系统没有提供完善的解决方案,于是就有人把这些公共解决方案做成组件开源给大家用,在 Factorio 里你可以通过复制粘贴其他玩家开源的“蓝图”来建造别的玩家的设计。

二、升级扩张

堵车-传送带

通过一段时间的建造,你在 Factorio 的工厂已经足够庞大,所生产的物品数量已经远远超过人物手搓生产的东西。但是你并不满足。在游戏里,玩家可以通过科学研究解锁更多可以制作的东西,科技越强生产效率就越高。于是玩家会试图用产量更大的铜炉来替代早期的石炉,从而更快生产出更多铁片。但是这时候就会发现老的传送带不够用了,因为传送带速度太慢,铜炉的单位产出量大于传送带的单位传送量,于是就会阻塞在那里,机械爪不动了,铜炉也不生产了。所以虽然铜炉的生产速度提高了,但是在整个冶炼区的生产速度却受限于传送带的速度,这就是典型的木桶短板了。这种时候玩家就应该考虑用更高速的传送带来替代老的慢速传送带了。但是一环扣一环,高速传送带又会让老的慢速机械爪错过物品抓不到东西,反而降低了生产区的实际产量。再加上以前规划传送带的时候很多地方错综复杂,是时候好好改建一把了!

这样的事情在软件工程有一个术语,叫做重构(Refactor)。一个软件项目,不管是前端后台客户端,一开始都是从零构建的,所有的东西都非常简单,为避免过度设计,初期代码并不会从一个大型复杂项目的角度去考虑,于是在后期成长为一个巨型项目时就会遇到类似游戏里的传送带问题。我在游戏里也经常会从主传送带分流多个子传送带给不同的产区,然后发现传送带太多导致很多地方无法布局新的传送带,或者因为分流太多导致流量太少无法发挥全部产能。这里的流量控制问题既像交通堵车问题,也像软件工程里的多线程调度问题。

一旦项目成长到复杂的地步,团队在人力和时间许可的情况下一般都会考虑重构(除非这个团队一直忙于应付业务成长,比如火速成长的互联网公司)。和在 Factorio 里升级建筑一样,软件工程的重构也会遇到牵一发动全身的问题。而且和游戏里的科技发展类似,现实世界的软件工程依然在高速发展中,尤其是前端,新技术号称半年过期,软件工程师可谓是最需要大量学习的职业了。玩家在游戏里得到了新的高效建筑想要升级,工程师们也会希望在自己的老项目里用上更高效的新工具。

但是苦于老代码的错综复杂,重构起来往往非常痛苦,于是也有很多人喜欢推倒重来。在游戏里相当于在地图里开一个新的地区,或者开一张新图。但是现实比游戏复杂,往往重来的软件项目并不一定比原来的更好,原因之一就是时间投入。大多数软件项目都是由利益驱动的,时间是非常大的成本,尤其是在今天中国互联网高速发展的情况下,如果不能快速推出自己的产品,很容易就死在沙滩上。在游戏里重来,顶多再花 10 小时,在软件工程里重来,hmm…

三、火箭升空

所有的软件都有其生命周期,今天中国互联网每年消失倒闭的大量服务大家有目共睹,即使是生命力顽强如操作系统也会有退出历史舞台的一天,类似的,Factorio 也有通关结束的时候。

在游戏里,我虽然知道最终通关条件是造出火箭离开这个星球,但游玩的过程目标感并不强烈。是“造出更高效的自动化系统”这件事情在驱动我不停去设计、修改自己的工厂,看着自己从零创造的流水线跑起来之后享受传送带轰鸣声带来的另一种宁静。在现实世界中,我们也更容易顶着自己的短期目标,更容易相信当下所看到、所体验的事物。但是总有一天这些都会被新的东西替代,是个不争的事实。

四、回到现实

LED

Factorio 尽管在很多方面与软件工程非常接近,而且在游戏里能造运算器之后就和写 if else 没差了,有人甚至利用运算器和灯光组成游戏里的 LED 屏幕。但游戏毕竟是游戏,生活比游戏要困难多了。

首先游戏的基础设计就是明确的反馈,有虫族入侵时系统会立刻告警,建一个工厂需要什么,能生产什么都一清二楚。但现实不是。即使有非常成熟的监控系统,某些故障依然很难被监控自动发现,隐藏在复杂系统里的某个大 Bug 可能得等到中招的那天才会有人知道。

其次游戏非常重视沉浸的体验,玩家在玩游戏的过程中精神高度集中,几乎没有干扰。但办公室里的程序员……网络上已经有很多吐槽漫画和视频在表达“求求你们放过程序员吧”、“我只想安安静静地写代码”这样的情绪。虽然娱乐成分比较多,但也在侧面反映了程序员经常被中断的事实。Context Switch 可是开销很大的。

这几年游戏开始被大众所接受,从以前的“洪水猛兽”慢慢变成“第九艺术”,虽然市面上流行的游戏有大量的粗制滥造和纯粹商业驱动的设计,但优秀的游戏也逐渐开始为大众所知。前段时间《头号玩家》(Ready Player One)也在传达游戏可以很优秀的概念。

前几天在知乎上看到一个问题,大意是如何防止自己的小孩沉迷游戏。我比较认可高票回答的意见,答者是一位游戏策划,他的做法是让自己的小孩接触高质量游戏,提高刺激阈值,从而不再对市面上粗制滥造的圈钱游戏感冒。答者说很多家长自己都不了解游戏却要从专业的游戏开发者手里把孩子抢回来,这基本等于白扯,这点我非常赞同。小时候玩游戏大抵是游戏在玩我,这两年接触了几个优秀游戏,再看了很多从业者的分析之后才发现这个世界的广袤无垠。如果读者朋友也喜欢玩游戏,但并不十分了解游戏世界,不妨试着接触业界公认的顶尖游戏,体会一下和捞钱游戏的区别,也许就此打开新世界的大门也不一定。XD

P.S.: 最近我开始玩起桌游,算是游戏的某个细分领域,很多游戏非常精彩,丝毫不亚于电子游戏。而且桌游可以和朋友们面对面玩,比起自己对屏幕鼠标又多了一层现实交互的乐趣。

2018.06.21/中午

于 T.i.T