阿里玄难:面向不确定性的软件设计几点思考
閱讀本文約花費: 19 (分鐘)
在纷繁复杂的业务发展中,变化已成为了唯一的不变。如何保障基础设施的安全、高可用性,同时提供高效的创新支持?今天,阿里副总裁、业务平台事业部掌门人玄难,结合阿里巴巴业务平台建设和个人多年大型软件设计经验,提炼成几点思考,希望对大家的软件架构设计有所启发。
玄难
阿里副总裁
业务平台事业部掌门人
特别说明:本文中所说的软件都指代面向最终用户的偏业务的软件,不包含操作系统、中间件等系统软件。
1、软件发展的几个阶段
- 软件工具和信息化阶段:软件最早是为了数值计算,以工具的形态出现的。包括PC时代我们非常熟悉的Excel,Word这些好东西。以及典型的企业内部管理的信息系统,例如:企业流程审批、进销存管理系统等等。
- 互联网服务阶段:随着PC互联网兴起,淘宝、QQ、Google、新浪这些全新的互联网服务逐步进入了我们的日常生活。
- 社会基础设施阶段:随着移动互联网、IOT、人工智能的出现和高速发展,各种各样的软件进入社会经济生活的方方面面,软件之间相互连接,构成了一个纷繁复杂的生态系统,变成了不可或缺的社会基础设施。
随着软件形态的变化,过去非常高效的系统架构和组织形态遇到了全面的挑战。因为我们所处的环境已经从量变到质变,突破临界点,产生了本质的不同。
阿里巴巴就是这个过程中的典型代表。从过去单一的电商业务演变成了复杂的经济体,没有了确定性的业务边界,蓬勃发展的业务不可预测。比较典型的特征就是:
- 从过去的一个淘宝演变成了几十个事业部和公司,新零售、云计算、文娱健康等等几百种业务,还在不断地快速演进;
- 从曾经的一个Denali系统,通过分布式架构演变成了上万个系统的群落,各种业务逻辑交织在一起横贯众多系统,说不清道不明;
- 从曾经几十个人的协同演变成了几万人的协同,每个人都像在原始热带雨林,不知业务全貌,盲人摸象;
- 从曾经的可停机发布演变成了不可中断,连续进化的社会基础设施,不仅要系统稳定性,更要业务连续性。如何确保这个基础设施的安全、高可用性,同时提供给业务方高效无障碍的创新支持,就是我们必须去解决的核心问题。
针对这些问题,我们对软件设计产生了几点基本思考。
2、传统软件设计:外延的确定性
作为程序员,我们都知道:软件要能符合预期,我们需要确定性。不确定性对程序设计来说是致命的。所以我们经常会听到抱怨“需求又变了”,网上很多段子都是程序员讨伐业务方和产品经理不停变更需求。
软件在“工具和信息化”时代,本质上是把原来的人工工作,用计算机软件来模拟,实现电子化,因此有个典型的特征:业务领域、软件职责和功能边界都相对清晰。因此最经典软件工程理论是瀑布模型:收集需求、画UserCase、确定功能集合、模型抽象、概要设计、详细设计、编码、单元测试、集成测试、用户测试、上线运行。然后投入下一个版本的迭代。传统的软件开发大多数都是这种模式。这种模式特别强调文档质量和变更的全流程一致。
在互联网服务时代,用计算机软件实现了靠人肉无法完成的能力,为人类社会提供了很多全新的服务能力。我们继承了传统的软件工程理论,也做了适度的改良。为了缩短版本迭代的时间,更快地验证产品想法获取用户,大多数团队采用敏捷模型。本质上是把需求批发模式变成了零售模式。这种模式最大的好处就是对产品需求的快速响应,但致命的是每次敏捷大多数情况下是在不断地打补丁,软件架构快速腐化。要不了两年,敏捷事实上变成了蜗牛。再熬两年,受不了了,就重构。但所谓的重构事实上是推倒重来。这种模式下几乎没有可用的文档了。
在前面这两个阶段的软件设计理论都有一个基本假设:软件边界是确定的,我们通过归纳总结和适度的预测(避免过度设计)来进行模型抽象。通过模型抽象,我们设计了各种可配置性来快速接入需求,提升效率,也就是我们常说的产品化。通过接口设计和模块化设计来进行组织分工协作。通过系统架构的开放性来应对不能配置的变化。变化一般来自两个方面:
首先是用户量增长,通常是用分布式来解决,分布式数据库,分布式缓存、分布式服务,多机房多单元,CDN等等。在这方面阿里巴巴应该是做的非常优秀。从五彩石开始至今,阿里巴巴的架构基本上都是这一指导思想的落地实施和优化完善,也仍是应对用户量快速增长的良方。
第二个方面业务功能的变化,我们通常说的系统可扩展性。通过传统数据库的大字段或者NoSQL,用“元数据+K-V存储”的方式来应对数据信息的不确定性;通过流程引擎来满足工作流程的快速响应;通过规则引擎来代替程序中的大量If-Else,实现界面配置来实现规则的变化。通过UI组件化,配合UI的编辑器来快速调整用户界面的变化。通过插件技术来将容易变化,且相对复杂的逻辑从主流程中剥离出来进行扩展。我们去看目前比较的套装优秀软件都大致如此。
截止目前,我们的软件研发,都是面向一个确定性的问题,类似一个圆圈,他是有需求边界的,我们从四周向内聚,做抽象,就是我们的业务抽象或者建模;它就是我们的房子,被四个边角承重墙划清了边界,里面的装修可以根据主人的爱好和阶段性诉求重构,但没法向外延展;它的特点是框架结构,业务领域模型抽象、组件化、版本化、外延向内;
3、思考角度的变化:内核的确定性
随着移动互联网,IOT,人工智能的发展,软件变成了社会的基础设施,我们每个人被软件牢牢地控制了,一天黏在手机和电脑上。人其实是作为终端接入软件网络。社会形态是没有边界的,是连续变化的,不可预测的。阿里目前的业务也是没有确定性边界的,不知道明天会变成什么样,它不是版本化的,是在不断在生长和变异。就没有确定性的软件外延。如果没有确定性的外延,而软件的运行又是需要确定性的,我们就只能去寻找确定性的内核。
如何理解这个变化。我们可以从机器学习的发展来类比。传统的机器学习有很多的算法模型,线性回归、决策树、随机森林算法、逻辑回归、SVM、朴素贝叶斯、K最近邻算法、K均值算法等等。我们要解决,首先要尝试分析问题领域,才能选择匹配的算法模型,才能得到好的结果。如果是个非线性问题,但错误的选择了线性模型,就拿不到结果。这种解决问题的思路,就是要先寻找一个确定性的问题边界,才能向内寻找参数。但深度学习的解决思路有个本质变化,不定义问题域,只定义稳定的结构,BP神经网络,有输入层,多个隐藏层和输出层。如果我们把图像数据输入进去,就构建图像分类和人脸识别的能力,语音输入进去,就构建出语音识别的能力(当然没有说的这么简单)。深度学习是由内而外的自我学习和生长的。
软件工程也遇到同样的问题,需要从外沿确定性转变为内核确定性。从逻辑推理的角度来说,传统软件工程是以归纳法为主,局部使用演绎法,而要面对外延不确定性的领域来看,需要找到稳定的内核基础,然后以演绎法为主,局部使用归纳法。我们先去寻找内核,内核向外生长和变异,原来的确定性是寻找外沿的确定,现在我们要寻找内核的确定。原来是归纳法,现在我们要演绎,找到不变的是什么,就像人由基因控制的一样。当然你也可以说这是一种跨业务领域的更高阶的抽象。
4、文档即代码
纵观计算机发展历史,软件研发效率提升就是弥合现实世界和计算机二进制世界的鸿沟。从二进制编码到汇编,到C语言,到面向对象的C++、JAVA。每一次升级都是用人类更容易理解的方式抽象描述现实世界,然后通过一个编译程序无差异的翻译成低阶,直到计算机能直接运行的二进制。每一次升级都带来软件研发效率的指数级提升,同时让能参与软件设计的人也是指数级增加,给整个社会带来巨大的进步。这其中最大的功臣毫无疑问是编译器。我们最核心的资产是编译前的源代码,而不是编译后可运行的二进制代码。因为我们编译后的代码不容易理解,也不可能通过逆向工程还原出源代码。丢掉了源代码,基本上就失去了所有。
回到当下的业务领域,我们都声称自己是做业务的,例如业务平台就声称支持了淘宝、天猫、拍卖、盒马生鲜、天猫超市、飞猪机票、火车票等等上百种业务。但我们的代码中完全寻觅不到这些核心业务概念。我们都知道电商最核心的交易模式担保交易、预售、团购、货到付款等等也不可能在代码中找到。我们也没有准确的文档来描述这些东西。这是传统的软件工程方法和技术局限导致的。
我们所做的需求分析,概要设计,详细设计到最后的Java代码,其实就是业务逻辑到计算机世界的一次编译过程。这其中最大的问题就是人肉编译,而不是机器无差别编译,这个编译过程因人而异。因为这种不确定性,导致所有的设计文档随着时间的推移,与实际运行的代码之间产生不可弥合的鸿沟。一个业务系统的文档越来越没有用处,也就越来越没人写了。如果不能实现文档即代码,我们就不能留下真实可用的文档。
我们需要把设计和实现融合在一起。我们看自然世界,所有的设计文档图纸其实就是DNA,而DNA是在生命体的每一个细胞中都存在的。DNA的传承就是生命的传承。所有外化的文档最后都容易消失。就像秦始皇一把火就把人类多少年的沉淀和传承毁掉了。但DNA里面的生物的本能传承是一代代的得到了传承和优化。
目标:不存在独立于可执行系统之外的文档。所有的信息都蕴含在系统之中,只是通过一些工具进行可视化,增强可读性。所有的信息都不能凭空存在,都必须属于一个业务对象。
5、面向功能的组件化设计到面向业务的对象化设计
我们的世界可以按熵变化的方向,分为熵增的无机体和熵减的生命体。
无机体是靠设计、图纸,自顶而下的层层分解细化设计,然后组件化拼装出来的。典型特征:标准组件化设计和批量生产来进行协同和提效。
生命体,是由内而外的生长和变异的。虽然看上去是组件化的,但因为基因不同,事实上不同生命体是不可替换,会产生排异反应的。所有组成部分是在基因的控制下同步生长的。生命体的生长和变异是连续的。
所有组件化构建出来的无机体,如果要有质变,都是推倒重来。就像我们的城市总在不断拆迁中膨胀一样。再如我们的7号楼,在设计结束,就决定了它只能是6楼,或许可以利用冗余盖到8楼,但如果增加到20楼,他一定会崩溃。要想盖20层,只能推倒重来。
因此按抽象归纳,组件化设计的软件系统,随着业务发展,补丁越来越多,运行几年就会被推倒重来是它的宿命。
有机体单个个体的复杂度也是有限的,是靠群体协作来形成巨大的规模和力量的。群体的进化是靠单体的变异和自然选择来演进的,生命的进化是不可预测的,正如父亲对儿子的成长和未来是不可预测的。
现在我们的业务系统都是由组件化系统,例如购物车、店铺、详情、库存、交易、营销、资金、支付、结算、财务体系构成。所有的业务实现,其实是数据在这些组件系统中流动来实现的。在这个运行系统中,我们看不到天猫、淘宝、盒马、天猫超市、担保交易、预售、团购这些我们耳闻目详的东西。都体现在一个个分散的数据字段和IfElse中。
我们的设计思路是,回归到业务本质,用对象化设计来让业务可生长、继承和变异。最基本的思路:整个系统的根基是业务。你将会看到一个实实在在的Class叫淘宝,天猫,他们有个父亲叫市场,天猫超市是独立存在的Class,它天猫的儿子。所有继承了他们父亲的基因,有独立的品牌心智的业务都会在运行期真实的存在。通过对象来去除兄弟之间的相互影响。核心控制性基因是不可变的,但新能力的创造就脱离父亲的影响能独立发展,也可以创造出新的子业务。
同时我们还要建立一套业务对象协作机制,天猫和淘宝互相协同,大麦和飞猪是可以协同的,让业务和业务之间产生连接,共同构成一个动态繁衍的生态体系。如果我们能把整个阿里巴巴商业体系图示化出来,买家卖家进入淘宝天猫就会像接入游戏,进入天猫超市就像真的进入一家超市,做拍卖真的要敲锤一样,做出虚拟世界的真实感觉。
阿里巴巴业务平台的演进:以功能为中心→以商业能力为中心→以业务为中心,我们在路上。