02.不确定的未来

不确定性原则

频繁、不符预期的需求变更几乎是每个开发人员职业生涯中都会经历的,初期我们可能会觉得这种变更是偶然现象,但是随着用户量的增长、业务功能的变化,不确定性才是恒久存在的事实。因此,当我们在进行架构设计时,要能够从现有的需求,以及未来潜在的需求中寻找到确定性内核,并由内向外设计弹性可扩展的系统。不确定性原则能够帮我们更好地面对技术负债,其在项目管理上的体现类似于敏捷开发,其在技术架构上的落地类似于测试与高可用保障中讨论的面向失败的设计原则。

本节的很多思想参考了阿里玄难:面向不确定性的软件设计几点思考这篇文章。

传统面向确定性的设计

在软件系统发展的早期,更多是提供各式各样的软件工具,帮助使用者进行信息化改造。其典型代表即 Excel,Word,以及典型的企业内部管理的信息系统,例如:企业流程审批、进销存管理系统等等。他们本质上是把原来的人工工作,用计算机软件来模拟,实现电子化,因此有个典型的特征:业务领域、软件职责和功能边界都相对清晰。因此最经典软件工程理论是瀑布模型:收集需求、画 UserCase、确定功能集合、模型抽象、概要设计、详细设计、编码、单元测试、集成测试、用户测试、上线运行。然后投入下一个版本的迭代。传统的软件开发大多数都是这种模式。这种模式特别强调文档质量和变更的全流程一致。

在互联网服务时代,用计算机软件实现了靠人肉无法完成的能力,为人类社会提供了很多全新的服务能力。我们继承了传统的软件工程理论,也做了适度的改良。为了缩短版本迭代的时间,更快地验证产品想法获取用户,大多数团队采用敏捷模型。本质上是把需求批发模式变成了零售模式。这种模式最大的好处就是对产品需求的快速响应,但致命的是每次敏捷大多数情况下是在不断地打补丁,软件架构快速腐化。

在前面这两个阶段的软件设计理论都有一个基本假设:软件边界是确定的,我们通过归纳总结和适度的预测(避免过度设计)来进行模型抽象。通过模型抽象,我们设计了各种可配置性来快速接入需求,提升效率,也就是我们常说的产品化。通过接口设计和模块化设计来进行组织分工协作。通过系统架构的开放性来应对不能配置的变化。

确定性的内卷

随着移动互联网,IOT,人工智能的发展,软件变成了社会的基础设施,也带来了更加剧烈的变化。我们所谓的变化往往来源于两个方面:用户量的爆发与业务功能的变更。用户量的爆发带来系统容量、可用性的挑战,通常是用分布式来解决,分布式数据库,分布式缓存、分布式服务,多机房多单元,CDN 等等。业务功能的变化,也即是通常说的系统可扩展性:

  • 通过传统数据库的大字段或者 NoSQL,用元数据结合 K-V 存储的方式来应对数据信息的不确定性;
  • 通过流程引擎来满足工作流程的快速响应;
  • 通过规则引擎来代替程序中的大量 If-Else,实现界面配置来实现规则的变化。
  • 通过 UI 组件化,配合 UI 的编辑器来快速调整用户界面的变化。
  • 通过插件技术来将容易变化,且相对复杂的逻辑从主流程中剥离出来进行扩展。

在这样的背景下,业务是没有确定性边界的,是在不断在生长和变异。这样就没有确定性的软件外延。如果没有确定性的外延,而软件的运行又是需要确定性的,我们就只能去寻找确定性的内核。

从逻辑推理的角度来说,传统软件工程是以归纳法为主,局部使用演绎法,而要面对外延不确定性的领域来看,需要找到稳定的内核基础,然后以演绎法为主,局部使用归纳法。我们先去寻找内核,内核向外生长和变异,原来的确定性是寻找外沿的确定,现在我们要寻找内核的确定。原来是归纳法,现在我们要演绎,找到不变的是什么,也可以说这是一种跨业务领域的更高阶的抽象。

面向业务的对象化设计

在不确定性的背景下,我们需要从面向功能的组件化设计到面向业务的对象化设计。我们的世界可以按熵变化的方向,分为熵增的无机体和熵减的生命体。无机体是靠设计、图纸,自顶而下的层层分解细化设计,然后组件化拼装出来的。典型特征是标准组件化设计和批量生产来进行协同和提效。生命体,是由内而外的生长和变异的。虽然看上去是组件化的,但因为基因不同,事实上不同生命体是不可替换,会产生排异反应的。所有组成部分是在基因的控制下同步生长的。生命体的生长和变异是连续的。因此按抽象归纳,组件化设计的软件系统,随着业务发展,补丁越来越多,运行几年就会被推倒重来是它的宿命。

典型的电商系统中,业务系统都是由组件化系统,例如购物车、店铺、详情、库存、交易、营销、资金、支付、结算、财务体系构成。所有的业务实现,其实是数据在这些组件系统中流动来实现的。在这个运行系统中,我们看不到天猫、淘宝、盒马、天猫超市、担保交易、预售、团购这些业务对象,反而是沉淀在了都体现在一个个分散的数据字段和 IfElse 中。

我们的设计思路是,回归到业务本质,用对象化设计来让业务可生长、继承和变异。最基本的思路:整个系统的根基是业务。通过对象来去除兄弟之间的相互影响。核心控制性基因是不可变的,但新能力的创造就脱离父亲的影响能独立发展,也可以创造出新的子业务。

同样地,在快速变化的背景下,我们很难用额外的文档去描述系统的设计、各层接口的实现。特别是对于软件开发人员,我们愈发地需要去遵循代码即文档的原则。在项目研发过程中所做的需求分析,概要设计,详细设计到最后的 Java 代码,其实就是业务逻辑到计算机世界的一次编译过程。这其中最大的问题就是人肉编译,而不是机器无差别编译,这个编译过程因人而异。因为这种不确定性,导致所有的设计文档随着时间的推移,与实际运行的代码之间产生不可弥合的鸿沟。一个业务系统的文档越来越没有用处,也就越来越没人写了。如果不能实现文档即代码,我们就不能留下真实可用的文档。

上一页
下一页