个人想法:
这几天AAOSConf 真正召开,DDD和CQRS成为热门。
关于对象和关系数据库阻抗,本站一直在讨论,我在使用DDD开发Jivejdon开始时就坚持使用SQL,而当时ORM框架包括Hibernate很火,我也不是出于远见,而是让领域模型更加简单些,不要被ORM等配置给牵涉。如今大家都已经承认Hibernate代表的那段适合火红的岁月其实是一场越战。
Martin Fowler厌倦ORM了
对象应该生存在内存中,这是我当初开发JdonFramework的基本特点之一。
DDD最大特点是统一语言,统一语言其实也是统一思想,比如敏捷方法行为驱动开发BDD也是一种统一语言:行为驱动开发(BDD)如何与领域驱动设计(DDD)结合?,我觉得它的Given When Then模板非常实用,能够分解复杂的业务场景。
最近也讨论了:业务模型统一描述,我个人使用三个元素来表达统一语言:场景 事件和状态。
这三个元素每个后面都有一段隐式的定义:
场景:Context,可以理解为DDD的bounded context,也可以理解为DCI的Context,也对应于用例的Context,属于BDD中的Given。从逻辑上说,这是一段“假设”。
事件:表达对象之间交互的行为,对应于DCI的交互,也可以认为是BDD的When。我在业务建模:上下文(场景)还是服务?中提到,对象行为分为两种,一种是维护内部状态,一种是对外交互。前者通过DDD的聚合根这个结构角色确定下来;后者通过DCI中角色确定下来,虽然这两种行为分离,实际上是区分了不变和可变,可变的对外交互和场景角色有关,隔离了对实体对象的影响。
在这篇Event Sourcing + DDD带来的模型重构问题如何解决?,我认为正是忽视了这种分离,才导致实体的重构会影响交互性质的事件。
状态:状态和对象的内部行为有关,也是由DDD聚合根这个角色实施,如果实体之间没有从属关系,各自对自己负责,它们就可以称为聚合根。
状态是实体的状态,表达了实体参与了各种场景业务以后的结果。如果我们要还原某个业务场景发生前的状态和发生后的状态,只有实体状态是无法做到的,实体状态只能表达当前最新状态,历史状态基本不会记录,如果记录历史状态,不如记录历史事件更加精简,这样的事件可以实现重放和回放,这也是Event Sourcing意义所在。
总之:通过场景 事件和状态这三个关键词,我们可以抓住需求到架构代码实现的主要脉络,不至于错误表达需求,也不会无法灵活跟随需求,更不会因为代码自身重构带来架构变动。因为我们已经确定了建筑的钢架结构。
当然,实践中最难的是分辨出哪些是场景 哪些是对象的对外交互行为,哪些是维护状态的内部行为。