往事
2014年3月,Martin Fowler和James Lewis率先提出了微服务架构这一武功秘籍,各路豪杰纷纷研习,一时大热。然而不到一年,有人不得要领,有人走火入魔。Martin不得不再次出面,告诫人们要单体先行,切忌急功近利。不足七日,便有人在Martin的门户中公然唱反调,指责单体先行万不可取。后有曾为微服务秘籍做注的Sam Newman不置可否地说,只待时机成熟,方可修炼。一时间众说纷纭,江湖大乱。有诗为证:
分析企架皆模式,代码重构精益精。
纵横软件四十载,江湖人称老马丁。
一朝创立微服务,却劝君单体先行。
莫问风雪何时了,你若欢喜便是晴。
新生
三体星上的和平爱好者对人类的忠告是:不要回答,不要回答,不要回答。
而人类面对软件业诸多悬而未解的问题则是:无法回答,无法回答,无法回答。
时间永远不会因为人类愚蠢的纷争而停止她的脚步,转眼间坐标来到了2019年。两位分别来自英国和比利时的多才多艺的年轻人机缘巧合地聚在了一起。他们在前人特立独行的思想基础上,结合了认知心理学,提出了一个颇为大胆的假设:单体还是微服务并不重要,重要的是团队的认知负载。
初看这一理论似乎并无太多新意,但细品之后简直如醍醐灌顶。Martin Fowler和Sam Newman们无法用语言表达出来的模棱两可,被如此轻描淡写地化解。就仿佛一个置身四维空间的神,在低头嘲笑三维空间中渺小的人类。这是一个彻彻底底的降维打击。
不仅微服务架构如是,你甚至可以就此发散开去:
- 敏捷开发取代瀑布式开发是为哪般?
- DevOps怎么会突然兴起?
- 云计算为何如此火热?为什么我们现在构建的软件都最好是云原生的?
你会发现,团队认知负载理论,或者说整个团队拓扑学,并不仅仅是一个方法论,而是一个全新的世界观。
什么是认知负载?
认知负载理论由认知心理学家John Sweller于1988年首次提出,它是指从事一件工作所要使用的脑力劳动的总和。Sweller在研究Problem Solving的时候发现,不同的教学方式会对学习者产生不同的效果,造成不同效果的根本原因就是认知负载。
信息要想存储在长期记忆中,就必须先被工作记忆(working memory)关注并处理。然而工作记忆的容量和持续时间都十分有限。在某些情况下,这些限制会阻碍学习进程,影响学习效果。沉重的认知负载会对学习产生负面影响。
Sweller将认知负载分为以下三类:
- 内在(instrinsic)认知负载,是指与特定主题相关的脑力劳动。
- 外在(extraneous)认知负载,是指向学习者呈现信息或任务的方式。
- 相关(germane)认知负载,是指为创建永久的知识存储而付出的努力。
团队认知负载与软件开发
Matthew Skelton和Manuel Pais(刚才提到的那两位“年轻人”)在他们提出的团队拓扑学中,倡导团队优先的思维方式,以降低团队认知负载为宗旨,避免工作内容(架构、运维等)超出团队的最大认知负载。这样,整个团队就可以处于一个非常舒服的状态,去有效地应对软件的复杂性,而不是疲于奔命。这种“以人为本”的思考方式,远远优于单体或微服务那种只关注技术本身的视角。
Matthew和Manuel不但把认知负载的概念引入到了软件开发领域,同时给出了他们对于不同分类的解读。
- 内在认知负载是指开发所需要的知识,如Java知识、前端知识等,也就是技术。
- 外在认知负载是指如何部署、如何调试以及如何配置等,也就是机制。
- 相关认知负载是指软件要解决的问题,也就是与业务、领域相关的知识。
其中,内在认知负载是固定不变的,它是我们开发软件所必备的知识;外在认知负载是需要尽量减少的,尽量避免与开发本身无关的脑力劳动;相关认知负载是要尽可能最大化的,因为这是我们在开发软件时必须了解的业务知识。
为什么要尽可能减少外在认知负载呢?比如一个线上bug,修复它的内在认知负载可能很低,只需要修改一行代码。但我们在修复之前,搭环境、准备数据、调试、测试……可能一两天的时间就这么过去了。这就是外在认知负载过高(环境不好搭、数据不好准备、不好调试、不好测试等)带来的问题。
又比如每一个开发人员都遭受过的来自业务方或需求方的灵魂拷问:为什么这个需求这么简单,却要开发这么多天?其实需求看似简单,但这里要改,那里要改,零零碎碎加起来就是需要好几天。你可能也很委屈,但你是否想过哪里出了问题呢?为什么简单的需求不能快速地上线?你也许会想到霰弹式修改,但这些都是表象。根本原因就是不合理的架构和代码结构,增加了团队的外在认知负载。
唯一的答案
回到最开始的那些问题,你是否有了答案?
人们为什么不愿意去碰动辄几百页的需求文档,而更愿意阅读只有一两页的故事卡?因为外在认知负载:以厚而全的文档向人们呈现需求的方式,大大增加了外在认知负载。
人们为什么不愿意去管理长长的维护清单,而更喜欢基础设施即代码?因为外在认知负载:以代码的形式来管理基础设施,显然要比手动运维具有更低的外在认知负载。
人们为什么不愿意自己控制软件的弹性、韧性,而更希望将软件部署到云上?因为外在认知负载:把专业的事情交给专业的团队去做,开发人员只专注业务代码,将与己无关的外在认知负载抛在身后轻装上阵。
从这个角度来看,单体微服务之争是否显得过于低级了呢?答案是如此显而易见。你只需要评估一下什么样的架构更能减轻当前团队的认知负载(确切地说是外在认知负载)就可以了。
软件行业过往一切悬而未决的问题、似是而非的论断,似乎都有了答案,唯一的答案。
是谁出的题这么的难?到处全都是正确答案。