事件、契约设计与BDD

12-10-17 banq
                   

最近看到@gameboyLV一个讨论中提出将事件划分为嵌套事件,例如:

事件:客户提款(异步命令)

事件处理前:判断是否有足够的余额(同步命令)

事件处理: 扣款(同步命令)

事件处理后:发短信提醒客户。(异步命令)

让我联想起契约设计Design by contact,又与BDD行为驱动开发中的Given-When-Then模板类似,发这篇文章试图探究一下它们之间是否有必然的关系?

我曾经在契约设计中提出契约(合约)Contact和DDD中的聚合体同一个高度,不同点是前者侧重行为之间的关系,而聚合体是一种结构关系,我以前也曾经认为事件是一种行为关系,涉及到两个以上对象的行为是一种协调关系,可以用事件表达,而这种协调关系也是一种合约Contact,那么是否可以认为事件是合约的另外一种俗称呢?

在契约设计中,分为三种:前置条件, 后置条件和不变性。

前置条件是表达合约(事件)发生的前提条件,比如扣款这个事件或合约发生的前提是必须有足够的余额,那么前置条件是:是否有足够余额。

后置条件表达合约(事件)发生后的情况,比如扣款事件后,通知客户。

不变性是表示在事件发生后的一种状态,我们可以用值对象来表达状态的这种不变性。

当我们使用@gameboyLV 的嵌套事件用语来表达时,发现几乎是一致,而且比较通俗易懂:

事件处理前:判断是否有足够的余额(同步命令)

事件处理: 扣款(同步命令)

事件处理后:发短信提醒客户。(异步命令)

事件后的状态:聚合体内对象发生了改变,并且自此以后一直不变。

对于契约设计Design by contact表达还有使用义务和权利这样表达方式,这种表达方式更符合类似现实世界中合同的表达方式,甲乙双方签订合同,合同中规定甲乙双方的义务付出以及得到的利益分配。

其实这种义务付出是一种前置条件,得到的利益或权利是一种后置条件。

再看看契约细化定义:

1.一个契约负责管理多个实体之间的交互

2.一个契约包含权力(可以做什么)和义务(必须先做什么)

3.一个契约会辨识到在一个场景下实体之间交互的结果状态

我们如果转化为事件用语,可能会更明白简单:

1.一个事件代表多个实体之间的交互。

2.一个事件包括事件发生前后两个阶段。

3.一个事件发生后会改变实体状态。

下面一节谈谈,他们和BDD的关系。

[该贴被banq于2012-10-17 10:05修改过]

[该贴被admin于2012-10-17 10:53修改过]

[该贴被admin于2013-01-08 09:44修改过]

[该贴被admin于2013-01-08 09:44修改过]

                   

8
banq
2012-10-17 10:43

我曾经在Eric Evans关于技术如何影响DDD的会话中谈到统一语言,所谓统一语言就是让需求人员 开发人员和测试人员都能够明白的一种统一的表达方式,类似UML,当然UML可能不合适测试人员。

@wangcity 也提出了代表其观点的统一语言,我认为非常好,而我提出的统一语言比较简单,只有三个:场景 事件和状态(Context Event and State: CES)。

这三个元素统一元素其实也表达了契约设计DBC的精神:

“一个契约会辨识到在一个场景下实体之间交互的结果状态”

用统一语言表达:

“一个事件会辨识到在一个场景下实体之间交互的结果状态

下面讨论敏捷方法中的BDD行为驱动开发模板,Given-When-Then模板也是一种统一语言,面向需求人员 开发人员和测试人员,比如以cucumber的一个案例为例子:

功能:加法
  场景: 两个数相加
    假如(Given)我已经在计算器里输入6
    而且我已经在计算器里输入7
    当(When)我按相加按钮
    那么(Then)我应该在屏幕上看到的结果是13
<p>

cucumber可以将这种文本式的描述实现为Ruby Java等语言,其实Ruby 传统Java都不合适这种BDD实现,只有函数式语言或支持领域事件的框架才最合适。当然这是细节,不过多涉及,有兴趣者可以参考其主页:http://cukes.info/

这种Given-When-Then模板实质是:

假如存在什么前提条件,当发生什么事件,那么产生什么结果,导致了什么状态。

很显然,Given-When-Then模板是符合契约设计原则,假如(Given)是前置条件,Then是后置条件,When代表用户的命令出发了一种领域事件的发生,也就是契约的签订。

Given-When-Then模板也存在我提出的统一语言三要素:场景 事件和状态,其中场景可以看成是一种上下文,代表“来龙去脉”(“来龙”=前置条件,“去脉”=后置条件)

Given-When-Then模板可以推广到产品说明书的表达上,见梦工厂讨论

那么,“场景 事件和状态”这个统一语言比Given-When-Then模板或DCI数据 场景和交互或契约设计DBC的好处在哪里?

好处很简单:语境很中国化,普通中国人都能看懂都能表达。

[该贴被banq于2012-10-17 10:52修改过]

[该贴被banq于2012-10-17 11:27修改过]

[该贴被banq于2012-10-17 11:38修改过]

clonalman
2012-10-17 20:25

2012-10-17 10:43 "@banq"的内容
“一个事件会辨识到在一个场景下实体之间交互的结果状态” ...

同一场景下,实体间交互应该是同步直接发生,事件应该发生在不同场景下异步行为,实体的交互,最终表现为场景之间的交互,契约应该是高于领域层的,是应用服务的参数或返回结果。

banq
2012-10-17 20:36

你讲的有道理,事件有异步的特性,是不是交互应该分同步 异步两种,还是交互本身就是不讲究同步?

clonalman
2012-10-17 20:48

两个实体同属一个场景与分属不同的场景,同一场景下直接调用不产生事件,不同场景需要透过事件来相互调用,同步或着异步可能跟架构相关。

象前面提到的场景:扣款

余额检查、扣款是一个场景

发短信明显是另一个场景

我们谈论余额检查、扣款的场景的时候,

如果上述两个交互用数据库去实现的话,

其实隐含了一个数据库场景,这个场景下有CRUD这个动作,

考查数据库场景下的服务,就表现为QueryService与CommandService

[该贴被clonalman于2012-10-17 20:58修改过]

5Go 1 2 3 4 ... 5 下一页