2019独角兽企业重金招聘Python工程师标准>>>
本文既不推销UML,也不推广DDD,更不涉及各种论战。-- 作者
某天又一次打开关于DDD(领域驱动设计)的PDF文档时,自己有了个疑问:什么是领域(Domain)?译文中是这样描述领域:银行业务被银行的内部人员和专家所熟知。他们知道所有的细节、所有的困难、所有可能 出现的问题、所有的业务规则。这些就是我们永远的起始点:领域。如果这就是领域,它似乎不是"起始点",而是“全部”--全部的业务规则、全部的细节、全部可能出现的问题。我的疑问正是始于此:Domain映射到软件,"全部"不就是整个系统?
这里有个概念漏洞,Domain是"全部",但不是全世界的"全部",那它是什么的全部?显然,译文中看到的"银行业务",其对应的Domain也不是指银行业务系统的全部,因此Domain的概念相对清晰--一个有清晰边界、内部的业务、规则、问题、细节都自成一派--你会问我,这是指对象(Object)吧!如果从低层次上讲,两者是有关系的。下一个疑问:Domain和Object有什么不同?
我思考的结果是封装的级别不同:Object封装的目标是调用其方法实现所承诺的功能,但系统中的对象是有依赖的;Domain封装的目标是"全部"都在这里,即不需要依赖其他的Object或者Domain。之所以这么想,主要的依据是从那个常用的例子:机场、航线、飞机,虽然我看的译文中把这三个定义为对象,使用UML画了聚合关系;我更倾向于把它们看成Domain,即我认为机场不会调用飞机的方法(或者人),两者只是相互关注了对方(的事件)。例如,飞机A1和机场B1通过无线电沟通(消息)。Object间的消息一般是带着发送者或者接受者的数据,也就是A1发送的是B1要处理的;而Domain间的消息是否处理,如何处理则是完全由接收者自己处理,发送者也不关心消息的处理。再一个疑问:如何达到"全部"封装?
上面的例子中,我使用了"事件"这个关键字。事件(消息)不是新鲜事物,在面向对象的系统中,其作为异构子系统、系统间异步调用的桥梁,起着重要的作用;所以我认为“事件通知”不是实现Domain的途径,因为它是同步调用的变种:消息的生产者和消费者仍然有业务逻辑上的天然联系。事件除了通知,还有一种模式是监听。这种事件是公共资源,是开放的标准,不论采用广播、总线、管道各种模式,Domain监听自己关注的事件,并对其进行响应,如果产生了新的("开放")事件,则将事件发布回(广播、总线、管道的)'通道'。以机场和飞机为例,机场广播的跑道天气信息,飞机的飞行员如果关心,则通过无线电接听,如果不关心,则完全可以关闭无线电。
以上基本展示了我思考的过程。其间,我回顾了自己使用过的各种(X)O,(X)O包含面向服务(架构)-SO(A),面向方面(编程)-AO(P),面向对象-OO,面向过程-PO。
粗略地得到了下图:
从上图中除了有关于Domain的思考,还想了关于如何更好的使用各种方法论。我有个观点:同步就是两次或者多次异步交互的集成。
画图的过程中,我又有了个疑问:服务间的异步通知类接口,是否是实现Domain的一种形态?通过与分布式服务系统的拆分,我认为:异步通知(接口)是一种补充,而不是Domain间交互的主要方式,它类似“塔台呼叫711,711听到请回答”;如果全程都是这样飞行,塔台需要为每个飞机配置一个导航员,且每个飞机独立使用一个频率,这不是一个好设计,尽管它在航空管制初期可能是可行的。
我的结论是:面向领域设计DDD中的领域是比对象、服务更加高度的封装,领域包含自己的数据、行为、控制等"全部",并对外部事件(或者消息)做出响应,按照自己的规则完成特定的功能。基于这样的特点,Domain间的通讯应该是异步事件监听模式。在Domain内部,可以利用面向对象、服务及各种方法论开发更耦合的功能--这可以解释为什么现在更多的系统是采用的同步调用方式运行。这也是另一个层面的“外松内紧”的耦合。