关于领域建模时考虑用户需求的出发点的理解

11-10-03 tangxuehua
最近又重温了领域驱动设计的原著,有了一些新的理解。现在我觉得我能更好地理解jdon007之前说的下面这段话了。

“用户需求”不能等同于“用户”,捕捉“用户心中的模型”也不能等同于“以用户为核心设计领域模型”。 《老子》书中有个观点:有之以为利,无之以为用。在这里,有之利,即建立领域模型;无之用,即包容用户需求。举些例子,一个杯子要装满一杯水,我们在制作杯子时,制作的是空杯子,即要把水倒出来,之后才能装下水;再比如,一座房子要住人,我们在建造房子时,建造的房子是空的,唯有空的才能容纳人的居住。因此,建立领域模型时也要将用户置于模型之外,这样才能包容用户的需求。

所以,我的理解是:我们设计领域模型时不能以用户为中心为出发点去思考问题,不能老是想着用户会对系统做什么;而应该从一个客观的角度,根据用户需求挖掘出领域内的相关事物,思考这些事物的本质关联及其变化规律为出发点去思考问题。

下面以Eric Evans(DDD之父)在他的书中的一个货物运输系统为例子简单说明一下。

在经过一些用户需求讨论之后,在用户需求相对明朗之后,Eric这样描述领域模型:

1. 一个Cargo(货物)涉及多个Customer(客户,如托运人、收货人、付款人),每个Customer承担不同的角色;

2. Cargo的运送目标已指定,即Cargo有一个运送目标;

3. 由一系列满足Specification(规格)的Carrier Movement(运输动作)来完成运输目标;

从上面的描述我们可以看出,他完全没有从用户的角度去描述领域模型,而是以领域内的相关事物为出发点,考虑这些事物的本质关联及其变化规律的。比如第1点,如果是以用户为中心的话,就变成了:一个托运人可以托运货物,即具有托运货物的行为,一个收货人可以收货物,一个付款人需要付款;而他的描述中完全以货物为中心,把客户看成是货物在某个场景中可能会涉及到的关联“事物”,如货物会涉及多个客户,货物有一个确定的目标,货物会经过一系列列的运输动作到达目的地;其实,我觉得以用户为中心来思考领域模型的思维只是停留在需求的表面,而没有挖掘出真正的需求的本质;我们在做领域建模时需要努力挖掘用户需求的本质,这样才能真正实现用户需求;

这让我想到了我之前思考图书借阅系统时的出发点也是错误的,因为我之前总是在以用户为中心思考问题。比如借书者借书,借书者还书,管理员对书本入库,等等;经过上面的分析后,我觉得我应该以书本为核心出发点思考领域模型。如:

1. 一本书在某个时刻最多只能被一个人借,或者没有被借走留在图书馆;

2. 书本在被归还时需要检查归还时间,如果有超期则需要做罚款处理;

3. 一本书有库存信息,如书本存放位置,库存数量;

4. ……

大家觉得我的理解如何呢?

[该贴被tangxuehua于2011-10-03 18:09修改过]

              

11
banq
2011-10-10 11:59
2011年10月03日 18:09 "@tangxuehua"的内容
没有从用户的角度去描述领域模型,而是以领域内的相关事物为出发点。

看来认识识分析需求有两种线索,一个是以人为核心的需求分析;还有一个与人无关,事物领域自身的内在规律,或者称为“道”。

至于以哪个为主要为侧重点,还是要看人和事物在不同场景中扮演戏份的多少与否,比如在货运系统中,从这个名字我们也可以看出以货为主的一个运输系统,因此,人应该处于次要地位。

但是图书馆借书这个案例中,我个人认为好像不是以书为主的自主运动,而是以人为主,书为辅助的这样一个系统,如果以书为主,就发生“书被借”这样奇幻事情发生,呵呵。

写得不错,大概 @jdon007 没有看到,我使用前面加 at符合提醒他一下。

[该贴被banq于2011-10-10 12:00修改过]

jdon007
2011-10-10 19:13
人 != 用户

比如,人口档案管理系统,系统中应有记录人的信息或者说存在关于人的模型,但这个人的模型并不表示用户。

图书馆管理系统,用户群若是“读者”,那么应该将“读者”(用户)至于模型之外;如果用户群是图书馆管理员,那么“读者”(不再是用户,哪怕命名为用户),可以置于模型之内(比如要挖掘用户兴趣模型,发现什么的人群喜欢阅读什么样的书)。

物流系统,如果用户群是“顾客”,那么应该将“顾客”至于模型之外;如果用户群是“管理者”,那么可以将“顾客”(此时已不是系统的用户)放在模型之内。

将“用户”至于“模型”之外,用户群单一时,比较容易做到;若存在多种性质截然不同的用户群时,要注意到不同用户群将有不同的心智模型,尽管它们之间可能有交集。

但是,即便将不同性质的用户群的心智模型聚集在一起,也应遵循这个原则,并需要清醒地意识到视角潜在的变化(这可能被忽略或遗忘, 从而引起混淆)。

从整体上而言,“书”、“账号”、“书库”是模型(包括其结构/状态与功能/行为上的特征),可理解为系统的结构组成;“借阅规则”是场景规约或业务规则,可理解为系统的运作规则。

用户(读者)的心智模型不仅仅包含书,还应包含账号(图书卡)、书库(图书馆)等,模型有状态有行为,但其在参与场景进行交互时的受到场景规约的约束。

一种可以尝试的思路,是从业务规则(感知场景,从中提炼出的场景规约)中发现模型,并将业务规则与模型进行整体上的分离,让模型更自由,从而可能复用于不同的业务规则,或适应业务规则的变化。

至于模型的组织可以借鉴四色原型的PPT, 如图书馆的例子:Place(Library)、Party(Account)、Thing(Book), 或借鉴OO的message-based的思路,将模型分类为object+message或event+handler/dispatcher;当然,还有别的分类或组织模型的方法。

tangxuehua
2011-10-10 22:07
jdon007说的很多,我上面所说的人就是指用户,模型的使用者。我也强调的意思也是模型的用户,模型的使用者不应该被包含在模型内部。

banq
2011-10-11 08:25
2011年10月10日 22:07 "@tangxuehua"的内容
模型的使用者不应该被包含在模型内部。 ...

当你确定书是核心领域模型了,那么模型的使用者是不应该包含进来进行分析,通过借书这样一个事件或场景的发生,模型的使用者与模型发生了关系,这时模型书还是需要一个使用者的记录的。

模型:

Class Book{

String id;

String name;

}

用户操作借书事件激活借书服务,从而发生借书场景:

Class BookContext{

boolean borrow(Book book);

}

当borrow(Book book)事件被调用以后,拉了一泡屎,留下状态,这个书被借了,借阅者是某个用户,在数据表中我们可能有这样的记录:

book{

String id;

String borrowedUserId;

}

至于,这个borrowedUserId字段是否应该出现在Book模型中,则是另外一种设计考虑,比如我们认为borrowedUserId字段应该属于Book的状态,那么出现在BookState中比较合适,那么Book类有了一个新引用BookState:

Class Book{

String id;

String name;

BookState bookState;

}

Class BookState{

Book book;

User borrowedUser;

Date returnDate;//归还日期等

}

完毕。

我把整个过程列出来,是为了理清我们的思绪,不要让模型的状态去影响我们的分析。

以上这个分析的唯一前提是:假设这个系统是以书为核心,跟踪围绕书发生的各种事件。

所以,我们在描述时不能以“书被借”这样去描述需求,会产生误导,因为“借书”是一个事件,而“书被借”是一个状态,状态是事件的结果,事件是状态的因,而模型是事件的核心,没有模型,事件就无法发生,就象没有电话,就没有电话铃这个事件,没有书,就不会有借书这样的事件。

由以上倒退,我们知道,分析一个需求,核心模型是第一步,这一步是不应该考虑用户,前提是如果这个用户是在事件发生时介入的话;但是如果这个用户不是事件介入发生,而是属于模型一部分,如书的作者,那么就应该考虑用户。

希望以上思路对大家有用。

猜你喜欢
2Go 1 2 下一页