行为驱动开发(BDD)如何与领域驱动设计(DDD)结合?

12-08-03 banq
                   

行为驱动开发(Behaviour Driven-Development)与测试驱动开发(TDD)两者都强调敏捷迭代,BDD使用“用户故事”来描述需求,然后开发人员将这些故事带入具体应用,通过不断迭代添加入真正的业务本质,也就是说,在BDD中,领域模型是通过开发迭代过程不断取自于于用户故事,而一般人理解的DDD是指一个成熟的领域模型,而不是一个在不断发展中的领域模型。来自Stackoverflow的提问

How does Behaviour Driven Development (BDD) work with Domain Driven Design (DDD) - Stack Overflow试图解开其中的问题。

BDD的定义:Given在某种场景下 When发生了事件 Then导致了什么结果(简称Given, When, Then)。

(banq注:我曾经把四色原型总结为:某个角色对某个事情做了某个动作,导致了什么结果。这两种描述几乎相同,四色原型侧重动作活动,BDD侧重事件,事件和动作其实非常类似。)

在StackOverflow这篇回答中,首先肯定BDD并不是一次性产生成熟的领域模型,BDD是从三个角度来看待需求: 知道的the known, 能够知道的the knowable 和不知道的 the unknowable.

对于“知道的”,因为比较简单,大家都知道,就无需各种场景描述,比如谈到日志,大家都能明白日志是什么,怎么做日志。

对于“能够知道的”,BDD擅长于此,通过用户故事来表达,并且以Given, When, Then方式来表达,这实际是使用scenarios场景来表达领域模型(banq注:比较类似DCI分析)

对于“不知道的”,我们通过BDD这样敏捷迭代不断挖掘深入,能够不断发现深层次的领域模型,隐式模型显式化。(见复杂模型的循环化)

当我们结合BDD和DDD时,我们使用BDD来实现领域模型中和场景有关的那些部分。当然在一个大型项目中,如果我们已经有一些成熟大的领域模型,我们也可以使用BDD的Feature Injection,特征是提供了一种让用户能够使用程序系统提供能力的途径,一般这是由UI界面工程师来完成,所谓能力实际是一种服务,服务必须通过界面通过类似MVC方式来实现,这样用户操作界面才能实现我们提供给它的服务能力,当然这个界面可以是网页也可能是移动页面。

(banq注:我经常在一些网站网页上使用的按钮功能,转到其手机页面上就找不到了,比如新浪微博有那么多种客户端,但是更新都不是同步的,造成客户端使用体验完全不同,这实际没有重视Feature一种体现)

                   

28
banq
2012-08-03 14:53

BDD是从TDD发展过来的,也属于DDD中一种描述业务的无处不在的统一语言,它的描述格式是:

As a [Role]

I want [Feature]

so that [benefit]

用中文的意思来理解,我认为是:作为某个角色,我需要某些功能或权利,这样能得到相应利益。 正如职责驱动开发中奖职责责任作为分析突破口一样,这里好像是从这个方面作为切入点分析的。

这样一种描述方式能够帮助我们从用户故事中不断寻找到那种传递业务价值核心的信息。因为大部分我们的客户总是这样问:嗯,我希望有这样的功能....你看这样做可以吗?( . . . I want [some feature] so that [I just do, ok?].)

从以上用户故事中,我们能发现如果软件能够正确实施用户这些行为,我们可以将它们作为系统的测试方式和验收标准。

那么如何能保证软件正确实施用户这些需求行为呢?对于简单容易明白的,我们能一下子能知道掌握,但是复杂一点的怎么办?我们可以使用一种模板来套用截取。

这个模板是:

Given some initial context (the givens),

When an event occurs,

then ensure some outcomes.

给出某个场景,但事件发生时,将有什么结果发生。

我们以取款机ATM来举例这个模板的使用,假设用户故事是这样:

As a customer,

I want to withdraw cash from an ATM,

so that I don’t have to wait in line at the bank.

作为一个客户,我想从ATM机中提取现金,这样(好处结果是),我不用在银行排队等候。

那么我们是如何知道我们已经成功传递了这个用户故事呢?对于这个故事的理解我们需要考虑几种场景情况:该客户账户可能是一个信用卡账户,有可能存在余款不够需要透支,而透支有存在透支额的问题,取款多少或多于或少于透支额等等多个可能情况。

我们使用given-when-then模板变成如下:

+Scenario场景 1: Account is in credit+ 账户是信用卡

Given the account is in credit 给出账户是信用卡

And the card is valid 并且卡是有效的

And the dispenser contains cash 并且ATM机有现金

When the customer requests cash 当客户请求取出现金时

Then ensure the account is debited 那么确保账户余额被扣除

And ensure cash is dispensed 并且确保现金被吐出

And ensure the card is returned 并且确保信用卡能退还。

+Scenario场景 2: Account is overdrawn past the overdraft limit+

账户已经透支。

Given the account is overdrawn 给出账户已经透支场景

And the card is valid 并且这个卡是有效的

When the customer requests cash 但客户请求取出现金时

Then ensure a rejection message is displayed 那么确保拒绝信息显示

And ensure cash is not dispensed 并且确保现金不会吐出

And ensure the card is returned 并且确保信用卡能退还。

对于上面两种不同场景,我们发现相同的点:事件 给出given 结果。

也就是说,given-when-then模板能够充分表达这几种不同场景发生的情况。

banq
2012-08-03 15:30

场景的组成部分 the givens(给出), event(事件), and outcomes(结果) – 是一种细粒度能够直接在代码反映用户故事的方式。这样就可以直接写出其相应的Java类:

表达Givens(给出):

public class AccountIsInCredit implements Given {
    public void setup(World world) {
        ...
    }
}
public class CardIsValid implements Given {
    public void setup(World world) {
        ...
    }
}
<p>

event事件对应的代码:

public class CustomerRequestsCash implements Event {
    public void occurIn(World world) {
        ...
    }
}
<p>

对于结果,通过类似Junit的测试框架JBehave将这些组合在一起执行,将输出结果“world,”,它是保存在你对象中某个地方,然后传递到每个给出场景中,JBehave然后通过事件激活"occurIn"方法,也就是真正执行场景的行为,最后,将控制传递给我们故事中已经定义的任何成果。

banq
2012-08-03 15:57

Feature Injection功能特征注入是BDD另外一个主要内容。

BDD将软件分析设计开发分为如下几个阶段:

Vision视角

Goal目标

Capability能力

Featrue功能特征

Story故事

Scenario场景

Code

作为投资人,其战略眼光是赚钱 节约钱 保护钱;经营者的目标是能够活下去,系统分析师必须有是让用户通过系统能够完成业务并获利能力,而界面设计师的特点是用户界面组件能够代表其相应的功能,开发者则是不断迭代反馈的故事,对于场景来说,所有人员都要以一个具体案例让系统按照用户希望那样运行起来,到了编码阶段,由程序员将想法实现。

[该贴被banq于2012-08-03 15:58修改过]


banq
2012-08-03 16:09

下面谈谈复杂领域的Cynefin模型,如下图:

将业务分为四个领域:Simple简单 Complicated极其复杂 Complex比较复杂和Chaotic混沌。

如果业务领域只存在简单和极其复杂,我们可以设定目标下决心克服它们,尽管任务非常艰巨,但是这些复杂Complicated还是可以预料的,因为我们知道它艰巨。在这种情况下瀑布式开发也许用得上。

但是事实情况除了上面两种,还有Complex和混沌,所谓Complex是指那种无法预期的变化,比如用户突然修改需求,这是你无法控制,一旦修改撤销等等带来复杂和混乱。

混沌是类似你的房子着火等等紧急事故情况。混乱的是,在你发布的软件之日你的系统出现错误发生当机,这时你必须放下一切,立即修复。

我个人理解,Cynefin模型其实将世界划分为已知和未知两个边界,无论目标有多远,只要是已知其方向,也就是能够确定了方向,迟早会克服,只要坚持就可以。而这个世界更多是存在很多未知部分,与其说人人在上帝面前平等,不如说人人在未来面前平等,更确切地说:人人在未知因素面前平等,不管你是圣贤 还是白痴。

[该贴被banq于2012-08-03 16:21修改过]


2Go 1 2 下一页