在一定的“人天”工作尺度上,一位开发者可以研发出一款简单的消息中间件,一个团队可以完成一个管理系统建设任务,数十个开发者可以组团实现类似TS的系统建设,数百个开发者可以团战一个复杂的列车调度系统或者飞控电子系统,成千上万人的工程师紧密合作才可能研发极其复杂的智慧城市所需的全部IT系统。EUA意图为在CWAP基础上为交易中心提供一个统一的事件驱动DDD业务领域框架,实现限界上下文之间自然解耦,从技术上为更细粒度的业务问题域拆分提供技术可能性,为解决软件自然增长和软件复杂性问题提供真正可能。
历史是要继承发展的,割裂的历史是一种强奸后的疼痛
IT软件技术超越一般的人类理解的范畴是迟早的事情,这里的关键技术或许是以神经网络为代表的AI技术和大规模分布式并行软件架构技术(包含GPU集群)。但是我们相信软件世界并非孤立的。开源和开放生态系统建设为软件的联合提供了可能。EUA技术从本质上与神经网络是相通的,EUA目标是建立“神经元”的新范式和底座,以期超越矩阵变换的数学范式,在软件的自然生长过程中,逐渐形成复杂的类似“神经网络”的业务“领域网络”(Domain Network),绝非仅仅解决分类和识别问题,更重要的是实现复杂的智能和业务功能,例如AI撮合交易,全自动集成、运维和监控以及智能化公司管理等。
本文是2018年Event Unified Architecture建设的纲领性指导文件。CFETS-EUA的定位是交易中心事件驱动的统一架构。事件驱动是DDD的动力,聚合包含聚合根、实体和值对象构成的领域模型是领域建设的灵魂。领域建设就是寻找业务灵魂的过程。解决软件复杂性的唯一之道正是将软件进行更深层次的抽象,更广泛的细化。
主要目标
- 建设一套软件开发范式,规范开发者开发行为(欲规范、必先技术上限制)。
- 实现真正的事件驱动框架(EDA),包含事件追踪和事件溯源以整合领域模型体系,EBS就是按照这套体系建设的。
- 通过EUA构建一套快速响应业务开发的后台业务体系。
- 构建一套集软件设计、开发与质量监控一体的以组件模块为核心的超越CI的“持续开发体系”。
主要工作
- 编程实现CFETS-EUA领域技术框架,为中汇公司提供快速化、标准化和规范化设计和开发DDD构件的能力。CFETS-EUA框架代码包含核心包、持久化扩展包和POC项目以及benchmark包。该框架采用真正的事件驱动框架技术(EDA),借鉴EBS的技术,借助AKKA技术开发该框架。
- 构建一套集软件需求、设计、开发与质量监控和自动部署为一体的“持续开发体系(CD)”。该体系以组件模块为核心,超越持续集成(CI)理念,更加符合中汇公司面临的主要开发问题。该体系主要通过设计与开发管理平台(软件系统)体现。包括支持项目组的需求和开发细化管理、组件与模块管理、数据管理、版本发布管理以及领域和业务设计信息管理等功能。
- 以CFETS-EUA为依托建设一套DDD软件开发新范式,规范开发者开发行为,以《开发即设计-领域开发设计与实践》(Markdown格式)书籍交付,并将全部内容以html文本形式展示在设计与开发管理平台中,主要内容包括,设计理念、开发理念、核心概念、设计细节以及应用教程等。
核心概念
Cell是EUA的基本组成单元。Cell是EUA的最小组成单位,也是义务处理的核心单位,由技术概念定义,包含Wall、Core、Support、EventHandler,Listener等组成。
Multiply定义了Cell 的扩张方式,在细胞层面进行扩张,以应对并发性任务,通过扩张性手段满足业务和性能需求。
领域模型:包含聚合、聚合根、实体和值对象。多个Cell组成一个领域模型,业务规则内化在领域模型中。
EventBus:事件总线,进行事件的激发,类似神经,通过事件(Event)触发一系列反应。
DataBus: 数据总线 ,完成数据的定向移动和存储,类似血管,通过运输行为将数据移动到最接近的数据处理中心也就是Cell中。
生命周期管理:领域模型离不开生命周期管理,因为它们天生必须是In-Memory的。
声明管理:将代码编写工作和设计工作统一起来,让开发结果直接反应成设计结果,以供设计团队和需求团队实时评估开发过程。
核心范式
新范式是一种反范式。北大俞孔坚教授提出“反规划理念”,获得美国艺术与科学院院士殊荣。至今印象深刻的是,它认为传统的城市规划强调人口规模、城市土地性质,功能分区和结构布局,而反规划以土地生命系统的内在联系为依据,优先进行非建设用地规划,包括生态景观、河网湿地、生物保护、历史文化遗产保护等。使规划路径建立在自然过程、生物过程和人文过程分析基础上,以维护这些过程的连续性和完整性为前提。新范式认为数据结构-过程算法在应对解决复杂业务问题时往往力不从心,算法在应对确定性问题时十分有效,但业务不确定性决定不同时期建设的业务功能容易产生冲突,导致应用开发建设过程缺乏连续性、一致性和稳定性。而基于应用场景的对象-事件-消息三位一体分析和设计方法,能够更好的适应业务需求的复杂变化,该方法天然内含了时间维度信息,非常适合事件溯源。新范式强调在设计开发过程中如何实现真正的OOP,对象包含了时间维度上的状态变化信息和基于事件消息的行为定义,数据结构和算法过程被内化于三位一体的分析框架中,为应用场景串联提供服务。
事件是一种行为、动作(或命令),对象自身具有所持的状态和行为能力、对象之间通过消息进行信息传递、不能够直接进行行为传递、行为和状态对于对象是私有的、对象只有自身根据相应的消息刺激做出对应的行为动作(应激性),并产生对应的状态结果,这一点很好理解,传统的领域模型在设计和开发时似乎有一只上帝的手,在白头鹰飞翔的场景中,白头鹰作为鸟类继承飞行的动作行为(天赋),一头实例化之后的白头鹰犹如提线木偶一样被它的应用主宰,只要应用调用飞的动作逻辑之后,白头鹰就犹如一道闪电翱翔于空,这一面向对象分析框架显然不够完整,似乎总有哪里不对。新范式针对某一具体的业务场景,从以下分析框架入手:
- given for object 假设特定的业务对象(一个或多个)处于某种特定的状态、具有某些特定的行为;
- when fired by event 当某一事件发生之时;
- then what changed 这些特定的业务对象发生了某些可观察到的状态变化,执行了某些可预见的行为;
- spread the event messages 发出消息,通知外界或特定对象,自己状态已发生变化。
领域分析离不开具体的业务场景,我们以聊天室应用为例进行具体分析。对于一个聊天室应用来说,主要场景有:
- 用户加入某一聊天室;
- 上线的用户可以在该聊天室里发布消息,所有该聊天室在线用户接收该消息;
- 用户离开该聊天室,该用户下线,不再接收该聊天室的新消息;
按照领域通用语言,我们来剖析建立领域模型。
业务对象:聊天室、用户和聊天消息(注意:这里的聊天消息是业务对象,而非范式)。业务对象的分析仍然遵循聚合根-实体-值对象的分析方法。聊天室作为聚合根,聊天消息和用户是实体。根据业务分析聊天室必然存在一个用户列表和消息发布列表两个子实体,用户必然存在一个已接收消息列表,并且有上线和离线两种状态,以及记录当前所处聊天室的位置信息,用户名对于用户来说是值对象。对于微信应用的场景,则该模型不能适用,无法满足需求。领域通用语言的建立不可能脱离具体业务需求和业务场景,虽然都是聊天业务,但却可能天差万别。
-
在用户加入聊天室场景中,given for object 聊天室中当前没有登录用户when fired by event聊天室收到一个用户加入请求then what changed用户加入该聊天室的用户列表spread the event messages 某个用户已经加入聊天室。
-
在用户发布消息场景中,given for object 发送用户已经在线when fired by event聊天室收到用户发布消息请求then what changed聊天室将该消息通知给所有在线用户spread the event messages 用户与某一时间向某一聊天室室成功或失败的发布了一条消息。
-
在用户主动离开该聊天室场景中,given for object 某聊天室中该用户在线when fired by event 用户离开聊天室请求 then what changed该聊天室从用户列表中将该用户置为离线spread the event messages 用户与某一时间已成功离开某一聊天室。
经过这一范式简单分析之后,我们通过建立是三个场景模型,帮助我们明确了设计应关注的重点信息,基于场景的分析,让设计和编写的代码具有内聚性,结构更加清晰,也方便TDD测试用例和测试程序的编写。等等我们似乎遗漏了什么。对,这些场景是如何串联在一起的,如果新需求加入,会否破坏原有模型的完整性和内聚性。消息机制为模型扩展提供了可能,也为领域模型之间、问题域之间解耦提供了真正的可能,领域模型之间通过消息实现弱的联系。在第一个场景中,发出用户已经加入某一聊天室的消息之后,设计者可能根据目前的应用需求可能并不需要关注是否有人订阅该消息。但是根据开发者的分析,存在潜在需求需要将用户的状态置为在线状态,如果用户之前没有已接收消息列表,需要为该用户初始化一个空的已接收消息列表。这一个逻辑过程完全可以在另一个业务场景中实现,并在另一问题域中进行解决,我们自此又通过分析识别建立起第四个业务场景。而需求可能没有提及。
- 在用户上线的场景中,given for object 某聊天室中该用户离线when fired by event 用户发出上线请求 then what changed 该聊天室从用户列表中将该用户置为上线,用户当前所处聊天室置为该聊天室spread the event messages 用户与某一时间已成功在某聊天室上线。
自此我们没有必要修改第一个场景对应的方案域。接下来如果一个监控需求需要追踪用户活动记录,我们也可以迎刃有余的通过订阅用户已经在线和离线消息来完成扩展支持工作,而不需要改动到原有模型的任何一行代码。在满足性能需求的前提下,开发者和设计者应该努力通过新范式设计领域模型,保持信息的完整性,通过信息的完整性保证模型的稳定性,例如在头寸现金流场景中,通过簿记原理在本方额度下扣掉对应贷记金额,增加借记金额,在对手方则增加借记金额,减少贷记金额,设计者和开发者很可能因为无需求和难以融入新过程的原因,而有意丢弃交易相关的时间信息、位置信息和交易前后的账户状态信息,如果后期新需求需要关联这些信息,必然涉及到代码逻辑的调整,但由于先前逻辑固化在多个关联类的内部,改动起来必然伤筋动骨。传统分析方法难以实现模型的完整性,数据和算法过程过于关注问题本身,新范式的优势在于它能通过针对对象-事件-消息分析,天然解决了状态问题和扩展问题,当然前提是只要你愿意在初始设计时把领域模型考虑的更完整和清晰。
通过新范式的实例分析之后,我们可以慢慢体会到新范式的威力。配合新范式必然需要新方法、新手段支撑这一美妙的大厦,使之勿要成为空中楼阁。最后我们简单分析一下TDD基于行为的测试,实际上只要我们在开发时稍加使点小技巧,在第一个场景的领域模块中针对用户和聊天室分别采用观察者模式,监听用户所在聊天室位置的改变,监听聊天室上线和下线用户的改变,并在单元测试中通过匿名函数实现这些监听器,在监听器中增加断言信息,断言输入行为与断言匹配,最后将监听器注册到用户和聊天室的扩展接口中,执行针对场景一的单元测试用例,我们就会得到是否断言是否匹配的结果,基于结果决定测试成败。这些单元测试用例总是保持在实现该模型的测试代码中,以方便代码演进过程中的回归测试。事实上令人更加兴奋的是,我们为测试实现的状态监听接口也为后期应用模型和业务扩展提供了想象空间。
核心技术
AKKA: EBS系统中绝大部分模块的底层技术基石,也是当前发展前景最好的分布式并行计算框架之一,EUA的底层技术基于AKKA开发。
Disruptor:一个近乎完美的消息总线,英国证券业开源技术框架。
AxonFramework:目前java界冉冉升起的一颗新星,其CQRS从读写分离层面为EUA架构设计提供参考。
网友评论