以理性不断的崇敬 - 对DDD之后复杂业务软件系统设计的思考

有两样东西,我越思考就越觉得神奇,心中就越充满敬畏。那就是头顶上的星空与心里的道德准则。它们向我印证:上帝在我头上,亦在我心中。

 ——伊曼努尔·康德 《实践理性批判》

1968年秋,北大西洋公约组织(NATO)在当时的联邦德国召开了一场国际学术会议。会议上提出了两个新概念:“软件危机”(Software Crisis)以及用以应对软件危机的“软件工程”(Software Engineering)。从此,软件工程,作为一门工程学科,得以独立于传统的计算机科学而发展起来。而到了今天,软件工程已走过了50多个年头。50年,貌似很长时间,但跟别的工程学科相比,软件工程其实还是非常年轻,以至于时至今日,新的理论还是层出不穷。而现在工业界最热的一个理论莫过于领域驱动设计(Domain Driven Design, DDD)[1] 了。

1968年秋,NATO会议

这几年,因为微服务,也因为中台概念的被热炒,DDD俨然成为了复杂业务软件系统设计的标准方法。

不过, 我个人的看法是,在一个事物逐渐成为了标准的时候,往往意味着对新事物的探索就应该摆上桌面了。诚然,DDD是进步的,但是也是有不足的。在经历了多次给客户提供DDD咨询之后,我发现我还是不能对客户提出的一些非常简单的问题给出让人满意的答案。比如说,如何证明你的这个模型是正确的或者是合理的,又比如说为什么你把这两个聚合划在同一个限界上下文而不是两个单独的上下文?类似这些证明你妈是你妈的问题常常让人觉得很恼火沮丧,但又不能不面对。因为细想之下,你会发现这些问题往往可能触达了理论本身的局限性。

模型与结构化

在我看来,DDD对软件设计的最大贡献在于两点:

1.  理论层面,DDD把我们对软件设计的关注点从技术重新拉回到业务,从而专注于业务领域模型的构建,而不是一上来就说的需要多少台虚拟机服务器。

2.  实践层面,事件风暴(Event Storming)[2]等具体的实施方法提供了一种结构化/半结构化的协作式可操作的方法,使得我们的软件架构设计过程可以有章可循,结束了之前随意而为之的状况。对于软件工程来说,这确实是一种巨大的进步。因为对于工程学科来说,结构化应该是迈向成熟的第一步。

对模型的关注以及结构化的方法,单就这两点来说,DDD已经足够先进了。除此之外,DDD里面的很多概念性的东西其实基本上都可以从面向对象(Object-Oriented)里面找到对应的影子[3]。从这个点出发,你会发现DDD真的回答不了以下问题:如何证明得到的模型是正确的,或者至少是合理的。因为,模型验证的环节缺失了。而对模型的验证,恰恰是一个成熟的工程学科所必备的。现有的软件工程,对模型的验证需要依赖于测试,甚至是真实的投产。基于这点,你会发现软件工程跟别的成熟工程学科差距还是挺大的。“……因为可以在软件架构设计的基础上预测制品的属性,而不用去实现系统,这也是工程学科的核心特征之一。从这个角度看,‘软件工程’几乎还不能算是一门工程学科……”[4]

形式化

如何解答这些看似简单的问题呢?By Experience显然不是一个能让人觉得满意的回答,说多了自己也会感到心虚。站在DDD给我们打下的基础之上,我们不妨稍微把目光投向学术界。其实学术界一直在规范化软件工程的方向努力。其中一个比较大的成果是形式化方法(Formal Method)。我们知道,数学是一门形式科学(Formal Science),形式化方法就是借助数学的方法研究计算机科学中的有关问题[5]。那什么是数学的方法呢?举个稍微简单点的例子。相信我们高中时都做过数学证明题,在做数学证明题的时候,我们是基于一些公理以及推论,一步一步地推导出想要证明的题目。把数学方法应用于软件系统设计与此类似。用严格的数学语言对业务系统进行建模,然后基于一些公理对模型进行推理证明。与形式化方法对应的就是非形式化的方法。我们平常用自然语言书写需求规格说明书,就是一种非形式化的方法。可以说我们平常的软件开发工作基本上都是基于非形式化的方法。非形式化方法最大的问题就是自然语言它过于随意了,可能存在矛盾、二义性、含糊性、不完整性及抽象层次混乱等问题[6]  。说的直白点,非形式化的方法造成的不确定因素太多了,这些不确定因素往往都会严重影响后续软件的开发工作。而形式化方法,本质上是一种消灭不确定因素的方法。不确定的因素总是要被消灭的,因为构建出来的软件系统所具有的功能是确定的,传统的基于自然语言的方法把这一步留给了测试,甚至是投产,这是一种“昂贵且有风险的‘试错’周期”[4] 。形式化的方法把这种试错提前了。

这种提前既有好处也有坏处,好处是它能让我们尽可能早的发现软件的设计问题,并对问题进行修复。在设计阶段就能修复问题,带来的成本降低往往是巨大的。坏处是在软件开发的前期,我们将必须花费大量的时间与金钱成本来学习并使用数学语言构建一个严谨的模型。这个坏处极大的限制了形式化的方法在行业的推广。根据前景理论(Prospect Theory)[6],大多数人对损失比对获得更敏感。也就是说,大多数人在面临获得的时候是“风险规避”的;而在面临损失的时候是“风险偏好的” [7]。尤其是当好处带来的成本降低只是一个潜在估算的数字,而坏处带来的额外开销确是实实在在能感受到的情况下,这种对比会特别强烈。“……但经理们并不喜欢这种开支模式的改变,因为他们不相信在项目开始花更多的时间和金钱,将在最后节省大量时间和金钱。”[8]这也是为什么虽然形式化方法在20世纪60年代就诞生了,但是一直只在安全、交通、医疗、芯片设计等领域被小范围使用的原因。

虽然工业界没有大规模采用,但是学术界对形式化方法的研究可以说是百花齐放的,涌现出了很多不同的理论,如建立在谓词逻辑和集合论基础上的VDM[9]与Z语言[10],基于Zermelo-Frankel集合论的B语言[9]以及其扩展Event-B[11],适合分布式系统建模的Petri网以及其面向对象版本OPN(Object Petri Network),以及适合于并行系统一致性分析与验证的SPIN等。其中,我个人比较看好的是B语言的扩展Event-B,文献[11]对它进行了详细的介绍。它提供了与主流开发IDE Eclipse集成的工具Rodin,使得传统开发者可以较为容易地构建形式化的模型。

仿真

除了形式化方法之外,另外一个方向是仿真。仿真(Simulation)是一个很大的领域,且仿真本身也是一个横跨多个学科领域的术语,在不同的学科领域对仿真的定义都会有所差异。这里我们借用IEEE610.3 – 1989[12]标准对仿真的定义:

1.  对真实世界的过程、概念或系统的结构、行为、运行或其他特征中某些方面的近似、表示或理想化。

2.  采用数学或逻辑的方式,表示系统,或系统沿着时间的行为。

虽然此标准现在已经废止,但是我个人认为它对仿真的定义相当准确,且有意思。第一点说的其实是建模,而第二点引入了时间这个元素,使模型能在时间尺度上对所抽象的事物进行模拟,“……因为仿真就是模型在时间上的实现。所以,为了仿真,便需要模型在时间上‘具有生命力’”[13] 。 也就是说, 缺少了仿真的模型都是缺乏生命力的。所以,从这个意义上来说,没有仿真的建模都可以认为是不完整的。更进一步,在成熟的系统工程(System Engineering)领域,系统、模型、仿真三者基本上密不可分。“系统是研究的对象,模型是系统的抽象,仿真是通过对模型的实验以达到研究系统的目的。”[14] 因此,只要对系统建立了模型,就基本都会涉及到对模型的仿真。 如果我们确信计算机软件本身是一个复杂系统,尤其是现在微服务架构已经成为事实标准以至于现代的软件系统宛然就是一个由多个子系统组成的体系(system-of-systems,SoS)[15]的情况下,那么在DDD为我们构建了系统模型之后,利用仿真对模型进行进一步的验证也就是一件顺理成章的事情。

事实上,仿真在几乎所有涉及到复杂系统设计的工程领域都得到了成功应用,尤其是在航空、航天、生命、军事等试错成本非常高的领域,已经成为了验证与辅助决策的重要手段。但是挺遗憾的是,在软件工程行业,对软件自身的仿真,更准确来说,是软件架构仿真(Software Architecture Simulation),很大程度上还是停留在学术层面。文献[16] 也坦言,软件架构仿真虽然是开发早期阶段质量保障的主要手段之一,但也是比较难以落地的手段。因为,它遇到了上面提及的与形式化方法一样的问题(“……即使这些过程像所有形式化的质量控制过程那样,会带来相当的好处[13] ”)。

从现阶段学术界的成果来看,对软件的仿真更多的是关注软件质量属性[17],如软件系统的性能与可靠性等。文献[4]介绍的Palladio方法是我个人比较看好的基本上能落地实施的方法。它提供了完备的理论基础,能模拟计算出目标软件模型的响应时间、吞吐量、使用率等性能数据,更重要的是,它与Event-B一样在工具侧的支持比较给力。它也提供了一个基于主流开发IDE Eclipse的工具,使得传统的软件开发者能较为容易上手。

是时候再往前一步了

虽然推广的难度有点大,但我依然觉得形式化与仿真是将来的方向,而现在也是一个合适的时机把二者引进到更广泛的软件设计过程中去。因为DDD把我们拉回到对业务领域模型的讨论了,只是这种讨论还是基于非形式化方法的。结合DDD的核心理念,以形式化的方法,对业务中特别核心或复杂的部分构建严谨的领域模型,从而使得这部分模型得以验证,以保证模型能满足需求;同时利用仿真技术对模型进行模拟,以量化的质量属性数据作为模型优化的决策依据。我想,这可能离Jean-Raymond Abrial 院士所提及的“Faultless System”[18]还有很长的路要走,不过, 这或许能回答,至少能在一定程度上回答上面提到的那些问题。我个人也会在实际项目中不断地往这个方向探索。

玄外音

在去年的DDD大会上,我发表过一个名为《By Experience 的三个层次 - 领域驱动设计的经验之谈》的闪电演讲。在演讲里,我探讨的是经验因素对软件设计的影响。我当时没有意识到我的主题可能触及到了哲学里面所谓的认识论(Epistemology)的问题。直到最近重新看到了康德墓志铭里面那句著名的话,也就是本文开篇的那句话的时候,我才突然意识到,这或许牵涉到认识论里面那场著名的关于唯理论(Rationalism)与经验论(Empiricism)的论战。双方争论的焦点在于人类的知识究竟是来自于理性还是经验。上文提到的按照数学系统严格证明的形式化方法是属于唯理的;而仿真等“干中学(Learning By Doing)”方法是属于经验的。演讲里面提到的经验总结成规则也是属于经验的。这场论战到休谟那达到了高潮,他对因果律的怀疑直接动摇了科学的根基。最终,康德终结这场论战。沿着康德三大批判的足迹,你会发现,很多时候如果只依靠理性的演绎或者只依靠经验的归纳总结,都会出现问题,容易陷入独断论或者是不可知论的陷阱。于我心中的道德律令(自由意志,我更倾向于理解为理性)与为我上者的灿烂星空(刺激我们感觉器官的自然现象)同样重要。正如学者邓晓芒提醒:人们只看到康德的赞叹,往往忽略康德的警告:如果没有理性的参与,“头上的星空”很可能堕落为“占星术”;而“内心的道德律”会使你陷入狂热或迷信。


DDD China 2019

不过即使这样,理性与经验的结合是不是就能完美地解决问题呢?在DDD基础上,通过形式化的演绎与仿真数据的验证,是不是就能得到一个完美的软件架构呢?回答其实挺让人失望的。在演讲里面,我想表达的是其实我们很难得到一个完美的架构,因为那是属于康德所说的“自在之物(Ding an sich)”,是人类的理性所不能僭越的范畴。理性一旦对其僭越,将立马被二律背反(Antinomies)的阴霾笼罩。用现代科学哲学的话来说,存在完美的架构这个命题是不可证伪的[19] ,因为那是属于非科学的范畴。这也意味着,无论我们用于研究软件架构的理论如何完备,我们也无法非常完美的回答一些看似简单的问题。但是,这并不妨碍我们利用好手上理性与经验这两把利器,不断地迫近她。借用知乎的一句话,我们终将“以理性不断的崇敬”。

参考资料

[1] Eric Evans. 领域驱动设计: 软件核心复杂性应对之道. 赵俐等译.北京: 人民邮电出版社, 2016.

[2] http://www.eventstorming.com.

[3] http://www.developerfusion.com/article/9794/domain-driven-design-a-step-by-step-guide-part-1

[4] Ralf H.Reussner, Steffen Becker et al. Modeling and Simulating Software Architectures: The Palladio Approach. 李必信等译. 北京: 机械工业出版社, 2018.9

[5] 古天龙. 软件开发的形式化方法. 北京: 高等教育出版社, 2005.1

[6] Kahneman, D. , & Tversky, A. (1979). Prospecttheory: An analysis of decision under risk. Econometrica, 47, 263 - 291.

[7] 彭聃龄.普通心理学 第4版. 北京: 北京师范大学出版社, 2012.5

[8] Jean-Raymond Abrial. Formal Methods in Industry: Achievements, Problems,Future. 裘宗燕译. 上海: 国际软件工程大会, 2006

[9] 邹盛荣, 郑国梁. B语言和方法与Z、VDM的比较. 计算机科学Vol.29 No.10, 2002

[10] 夏建勋, 唐红武. 需求分析的Z语言形式化方法.科学技术与工程 Vol.8 No.8, 2008

[11] Jean-Raymond Abrial. Modeling in Event-B:System and Software Engineering. 裘宗燕译.北京: 人民邮件出版社, 2019.9

[12] IEEE 610.3-1989 - IEEE Standard Glossary of Modeling and Simulation Terminology.  https://standards.ieee.org/standard/610_3-1989.html

[13] Pascal Cantot, Dominique Luzeaux. Simulation and Modeling of Systems of Systems. 卜广志等译. 北京: 国防工业出版社,2017.3

[14] 肖田元. 系统仿真导论 第二版. 北京: 清华大学出版社, 2010.2

[15] Mo Jamshidi. System of Systems Engineering:Innovations for the 21th  Century.许建峰等译. 北京: 电子工业出版社, 2016.9

[16] 李必信等. 软件架构理论与实践. 北京: 机械工业出版社, 2019.1

[17] ISO/IEC 25010:2011 Systems and software engineering — Systems and software Quality Requirements and Evaluation (SQuaRE) — System and software quality models. https://www.iso.org/standard/35733.html

[18] Jean-Raymond Abrial. Faultless Systems: Yes WeCan!. Computer 42(9):30 – 36, 2009.10

[19] Karl Popper. The Logic of Scientific Discovery. 查汝强等译. 杭州: 中国美术学院出版社, 2008

你可能感兴趣的:(以理性不断的崇敬 - 对DDD之后复杂业务软件系统设计的思考)