最近对围棋产生了一点兴趣。这个"兴趣"离"会下"还差得很远。我知道规则,知道怎么吃子,听过布局、定式、死活这些词,但真给我一盘稍微复杂点的棋,让我说哪里重要、哪边占优,我大概完全看不出来。最先让我困惑的倒不是围棋为什么值得研究,而是:亲自下棋到底有什么乐趣?如果下棋就是脑子里不停预测——我走这里,对方可能走那里,再往后推十步——那它更像一场纯脑力比赛。业余玩家在这件事上天然吃亏:别人每天做死活题、研究定式、复盘棋谱,算得自然比我深。我偶尔下一盘,投入量摆在那里,还没开始好像就已经输了。带着这个疑问查了点资料(也问了不少 AI),慢慢发现,投入练习固然重要,但是我仍把"计算"放到了太中心的位置。围棋当然很需要计算。但在展开一个局部之前,棋手其实已经做了很多别的判断:现在是什么局面,哪里重要,哪里更急,哪块棋弱,这一仗有没有必要打,这个定式放到今天的棋局里合不合适。计算只是整套决策里的一部分。更关键的是:面对一个根本不可能穷举的空间,先把它压缩成少数真正值得研究的问题,再把有限的计算花在那些地方。想到这儿,我很自然地想到了做设计——尤其是 AI 已经能把"展开方案"这件事变得很便宜之后。
我一开始把定式理解成"标准答案"。围棋研究了几百年,一个角走成这样,后面最正确的下法应该早就定了吧,照着下就行。后来才知道不是。定式更像长期实践后局部双方都能接受的变化:一边拿角上实地,一边得外势,谁也没明显吃亏,于是稳定下来。问题在于,棋盘不只有这个角。外面已经有什么棋,外势朝向哪边,附近有没有弱棋,这一盘更需要实地还是发展——都影响同一个局部到底值不值。更有意思的是,定式本身也不是一张永远正确的答案表。AI 出现以后,一些职业棋手用了很多年的变化被重新评价,以前看着有点奇怪的下法反而开始流行。所以我现在更愿意把定式理解成:被长期经验压缩出来的成熟方案。它告诉你这类局部以前的人通常怎么处理,却不会替你决定今天这盘棋需要哪种结果。软件工程里的成熟模式也一样。设计模式、架构模式、经典算法和协议值得学,是因为它们省掉了从头发明的成本。但"这是一个成熟方案"和"我的系统现在该用它",中间始终隔着具体上下文。这种感觉在大多数软件系统里应该都成立。不过要举例子,我更熟悉的是数据库。数据库领域尤其不缺"定式":B+ Tree、LSM Tree、WAL、MVCC、Buffer Pool、同步复制、Raft,都有大量成熟经验,论文、实现、最佳实践一应俱全。现在了解这些东西比以前容易太多了。想比较 B+ Tree 和 LSM,很快能拿到一份完整分析;想了解某种复制协议,也能马上得到几套不同实现。真正麻烦的反而是另一些问题:现在面对的到底是什么 workload?这个系统真正害怕什么?某部分复杂度值不值得承担?一个局部机制单独看收益不错,放进完整数据库以后还是不是这样?
中盘:哪里都能下,但不是哪里都该下
进入中盘,棋盘上的事一下子多了起来。门外汉最直观的感觉就是:哪里都有事。这边几颗棋正在接触,那边还有大片未确定的空间,中间某块棋似乎不太安全,另一侧又好像有机会攻击。如果每个地方都重要,下一手反而最难决定。围棋里讲"急场"和"大场",这个区分我特别有感触。一个地方大,说明最终价值高;另一个地方最终价值未必最大,但更急。朴素点理解就是:大场可以以后再抢,急场如果错过时机,棋本身可能马上受损。所以下一手并不总是去棋盘上"价值最大"的地方,而要同时判断大小和紧迫程度。价值和优先级,不是一回事。中盘还有一个概念叫"先手",我第一次听到这个名字时完全没意识到它有多重要。一个局部变化结束,如果对方必须回应,你还能继续掌握主动;如果对方可以不理,转身去别处,那你就算局部得了些利益,也可能失去下一步选择重要位置的机会。所以评价一段变化,不能只算各自拿了多少,还要看交换之后下一手重要棋轮到谁下。有时候宁可少拿一点眼前利益,也要保住主动权——"局部最优"一下子复杂了很多。做数据库项目久了,这两种感觉都非常熟悉。索引还能优化,Checkpoint 还能更平滑,缓存命中率还能提高,复制延迟还能降,恢复、监控、异常处理,几乎每个方向都还能往前走。这些事都不是"没价值",难的是决定现在先做什么。一个模块当然也可以继续打磨,把 API 做得更漂亮、性能再提一点,但为了把这一块做到最好,整个项目一直没有精力进入下一个真正重要的问题,那局部的最优也就没那么重要了。以前实现成本本身会挡住不少想法,一个优化要几周,大家自然会认真掂量。AI 让"先实现一个看看"越来越便宜之后,这层约束在减弱,排序反而比以前更重要了。
讲了这么多判断,很容易走到另一个极端:好像只需要大局观,计算不重要了。围棋显然不是这样。进入局部战斗,一块棋能不能活,这里能不能断,征子成不成立,双方对杀谁先没气,最后还是要把具体变化展开。认真学棋的人大量做死活题,大概就是练这个。只是我现在开始理解,局部计算和大局判断解决的是不同的问题。一个人可以局部算得很深,却在开头就为一个不值得打的地方投入了大量棋子;反过来,方向判断得再好,关键死活算错一步,整块棋死掉,前面的判断也全失去意义。所以围棋要的是两件事同时成立:先找到值得计算的地方,到了那里,又有能力真的把变化算清楚。这也是我觉得它和 AI 时代做设计最像的地方。AI 特别擅长展开后半段:搜代码、枚举方案、写 prototype、补测试,把过去很耗时的工作变得便宜。于是人的注意力很自然地往前移了一点:到底让 AI 算什么,为什么值得算这个,算出来的结果又怎么判断。