`
fangang
  • 浏览: 860222 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
311c4c32-b171-3767-b974-d26acf661fb2
谈谈用例模型的那些事儿
浏览量:37620
767c50c5-189c-3525-a93f-5884d146ee78
一次迭代式开发的研究
浏览量:67633
03a3e133-6080-3bc8-a960-9d915ed9eabc
我们应当怎样做需求分析
浏览量:405587
753f3c56-c831-3add-ba41-b3b70d6d913f
重构,是这样干的
浏览量:85370
社区版块
存档分类
最新评论

一堂如何提高代码质量的培训课 之 领域驱动设计

阅读更多

终于到了该说说领域驱动设计的时候了。我们在这场关于代码质量的讨论中,从代码可读性开始,讨论了代码复用性、设计模式,然后探讨了职责驱动设计。代码可读性是对代码质量最基本的要求,可惜我们仍有做得不够的(即使那些开发程序很多年的老程序员)。代码复用是提高代码质量的最初级阶段,但是在一个多人开发的项目团队中,围绕代码复用值得讨论的问题依然非常多,它依然是一个非常复杂的问题,甚至有时它不再仅仅是一个技术问题,而是一个管理问题。唉,提高代码质量的道理漫漫兮同志们要上下而求索。一个比较成功的保证代码质量的管理模式就是代码复查。让一些有经验的程序员定期去复查那些初级程序员的代码,指导他们的开发,被认为是成功的,但也代价巨大的。

然而,在这场关于代码质量的讨论中,我认为,最终的终极目标毫无疑问应当是“领域驱动设计”。领域驱动设计可以快速而根本地提高我们的代码质量,举一个最近发生的一件事情也许可以深刻地说明这一点。前不久,我将一个开发任务交给了我的一个手下。一周后,当我对他的代码进行复查的时候,我惊呆了。我甚至不能提出任何的建议来优化他的代码。随后,我花了半个小时的时间与他一起进行了一次领域模型分析,将他开发的这个模块用领域模型绘制了一个草图。随后的数日,他照着这个图纸重新进行了编码。当我再次复查他的代码时,我忍不住笑了。在短短的一周时间内能让一个人的代码质量判若两人,这不得不说是领域驱动设计带给我们的震撼。

但是,在领域驱动设计之前,我用大量篇幅讲解了职责驱动设计。职责驱动设计是领域驱动设计的理论基础,领域驱动设计是职责驱动设计的最佳实践。领域驱动设计要求我们以领域模型作为我们分析与开发的核心,为什么?因为我们的设计应当与现实世界保持“低表示差异”。领域驱动设计强调所有的领域对象应当以现实世界作为模板,为其定义和分配行为,为什么?因为我们的设计应当以职责为中心,按职责分配行为,分配行为的原则可以参照“信息专家”模式。领域驱动设计并不是横空出世的,而是在职责驱动设计的基础之上发展的。理解职责驱动设计可以促进我们对领域驱动设计的理解,然而非常遗憾的是,它却长期游离于我们的视线之外。

 

低表示差异与领域模型

我在前面的“职责驱动设计”部分已经讨论了“低表示差异”。用一句简短的话说,在我们的分析设计中,软件世界始终应当与现实世界保持“低表示差异”。如何保持低表示差异呢?答案就是领域模型分析。

领域驱动设计,其名称中,将“领域(Domain)”这个词放在了最显著的位置上,为什么呢?因为它的理论核心就是领域。在需求分析和设计阶段使用领域模型与客户进行软件需求的讨论。在这个阶段,领域模型是最重要的一个验收成果,没有完成领域模型分析,这个阶段就永远不算结束。在软件开发阶段采用领域模型作为核心设计图纸指导设计开发。领域模型怎样设计则我们的软件系统就怎样设计,软件系统中的最主要软件类都是源自领域模型中定义的领域对象。在运行维护及二次开发阶段,领域模型就如同房屋建筑中的设计图纸,它成为运行维护人员和二次开发人员熟悉和理解软件系统的核心线索。总之,在领域驱动设计中,领域模式成为最最核心的内容。所以我们应当首先理解什么是领域模型。

领域模型是对现实世界中某个业务领域的抽象。我们设计的软件不是对所有现实世界的模拟,而是对某个领域的模拟,譬如财务领域、税务领域、企业管理领域等等。这个领域我们称之为“业务领域”,而在这个领域里工作,并熟悉掌握这个领域中所有知识的人我们称之为“领域专家”。我们的分析和设计人员对业务领域的熟悉和理解的程度,往往决定我们的软件是否满足客户需求,也往往就决定了我们的软件是否成功。领域驱动设计理论要求我们在需求分析阶段必须非常深入地理解业务领域,采用的方式就是领域模型分析。同时,在这样一个过程中,应该有领域专家参与,甚至成为分析设计中的一个成员。

过去我们使用用例模型与领域专家交流,直到现在我们依然还在这样做。用例模型分析是我们分析设计的方法之一,但现在我们又有了一个新的强有力的工具,那就是领域模型分析。与用例模型比较,领域模型更加直观,可以更加立体地描述现实世界。如果说过去的需求设计文档是二维世界,用例模型只是二维半,领域模型才是真三维世界。领域模型是一大堆的类图,它描述的是业务领域中的各个事物,以及事物与事物之间的关系。

从业务领域中获取知识

说了这么多东西,现在让我们来点儿实在的东西吧:如何进行领域模型分析?建立领域模型需要从业务领域中获取素材。获取领域模型所需素材通常有两个途径:与领域专家的现场交流会中获得,和从用例模型的各个流程中提取名词或名词短语获得。我们将这些获取的素材经过加工,形成我们在领域模型中的一个又一个的类,这些类我们称之为概念类。现在的问题是,哪些应当成为领域模型中的概念类呢?如果我引用一堆定义和准则,并不能让你清楚明了,也许一个生动的比喻更能够让你理解深刻。需求分析有时候就像一部部动画剧,而那些枯燥乏味的概念,纷繁复杂的流程,在这些动画剧中似乎都突然活了,个个都有语言有性格。在这些动画剧中扮演的所有角色,就是我们需要的概念类。而他们做的所有动作,就是用例模型中的所有流程。

1)在业务讨论会中绘制领域模型

运用我曾经一篇文章中的实例来更加生动地描述这样一个过程吧:

在一个阳光明媚的下午,我们一个个西装革履、精神抖擞地来到了客户的办公现场。在一个明亮的会议室里,宽大深褐色的椭圆木桌旁已经聚集了十来个业务人员。看到我们进来,大家握手问候。相继就座后,互相介绍,往来寒暄,唠唠家常。共同的家乡,或熟或不怎么熟的某个人,都可能成为拉近彼此关系的理由。逐渐,一切开始进入正题。客户开始絮絮叨叨的描述自己的需求,而我们则在紧张的做着记录,时不时问一些问题,表明我们的立场,抒发我们的建议。在这样一个过程中,客户会描述他们的每一个业务,会讲解每个业务的流程,他们会讲出一些业务领域的专业词汇(尽管有些你当时还不太懂)。在这样一个过程中,作为需求分析员,你应当非常注意业务流程中的一些关键词汇,你应当(在当时或者过后)将它们提取出来,通过询问客户,弄清楚他们的定义,以及相互之间的关系。而这些词汇就是建立领域模型的开始。

这样的讨论会不可能是一次两次,而是数次。在这样的讨论会中,也许一支笔和一摞白纸会非常有用。在这样的讨论会中,你可以迅速将从客户那里理解的各种概念和知识,立即在白纸上画出一个又一个的草图。那些关键词汇被绘制成了一个个的概念类和它的属性(如果确实需要),用线条迅速标注出相互之间的关系。在你绘制的时候,客户会在不断地给你指正,或者说出了更多的业务知识。一张张的草图成为了你与客户交流的工具,也是最初始的领域模型。

这是一个财务软件的业务讨论会,一个业务人员正在跟我讲付款单是怎样制作成凭证的。每张付款单都有一个商品明细,每个商品明细都有它的价格、数量和金额。他指着一张付款单向我解释着。从这句话,我可以提出一些关键信息:付款单、商品明细、价格、数量和金额。付款单与商品明细是一对多关系,并且商品明细聚合在付款单中。每个商品明细都有价格、数量和金额,也就是说,价格、数量和金额是商品明细的属性,这都很清楚。紧接着,他下面的讲解就不是那么清楚容易了。如果按照一张单据生成一张凭证,那么每张付款单生成一张凭证。单据中的每个明细在凭证中生成一条借方分录和一条贷方分录。将付款单中的付款科目作为借方科目,将付款单结算方式对应的结算方式科目作为贷方科目。现结的付款单在采购发 票中已制作凭证了,因此不再单独制作凭证。非预付的付款单不制作凭证,而是其执行付款核销以后,在核销单中制作凭证。经过对以上语言的分析,我们可以绘制以下关系:一张凭证包含多个分录,是内聚关系。分录分为借方分录和贷方分录两种。一条商品明细对应一条借方分录和一条贷方分录。借方分录中包含“借方科目”属性,对应付款单中的付款科目;贷方分录中包含“贷方科目”属性,对应的是付款单中的一个什么科目。在这里,你可能对客户的某些描述不明白,因此要他做出解释。原来客户预先制订了一个规则,付款单中的结算方式分布对应了一个结算方式科目。OK,你在绘制的图形中,把结算方式科目作为关联类,将结算方式和贷方科目进行了一个关联。这样,付款单生成凭证这样一个场景的领域模型就绘制出来。

 

2)归纳和整理领域模型

在现场讨论会中,可能一些关键的概念被你忽略掉了。也可能一些关键性的关系被你忽略,或者在草图上并没有很好地表达,甚至存在谬误和矛盾。随着你事后的分析和整理,你从用例模型的流程描述中提取出了更多的概念。同时,随着你对问题的一步一步深入理解,你开始重构你起初的领域模型。在Evans的《领域驱动设计》中,他用大量的篇幅和实例描述和讲解了这样一个过程。另外一个重要的概念是,深入理解和重构领域模型不仅仅是在软件需求分析的阶段完成,它贯穿了整个软件开发的周期。按照迭代软件开发的思想,我们绝不能企图在需求分析阶段完成所有的分析(那是瀑布的思想)。随着我们对业务领域的深入理解,重构和精化领域模型贯穿整个“开发—维护—再开发”的过程中。而这也正符合了现代软件开发业的发展需求(我参与的项目已经经历了快5个年头,每年都在经历着新的开发)。

经过了这样的、有领域专家参与的、反复讨论与整理的过程,我们对业务领域理解将越来越深入,而我们设计的领域模型将越来越贴近现实世界中事物的本质。运用这样的领域模型图纸去开发我们的软件,毫无疑问我们已经成功了一半。(制作领域模型的更多细节见我的相关博客,我也会写更多的文章讨论)

运用领域模型开发软件

曾经有个笑话是这样说的:大师们站的高度都是非常高的,高到什么程度?他们都是生活在太空中的。追随大师是一个高风险的职业,为什么?一不小心就能让我们因缺氧而死掉。这个笑话非常深刻的道出了追随大师的关键,那就是怎样“着陆”,也就是如何“落地”。一个高深的理论,如果不能指导我们的实际工作,那么这个理论是没有价值的,领域驱动设计也是一样。下面我们来讨论一下如何运用领域模型指导我们的软件开发。

1)领域模型在我们的软件框架中扮演的是什么角色

首先第一个要解决的问题是,领域模型在我们的软件框架中,特别是时下最常见的Spring+Hibernate框架中扮演的是什么角色。我们不妨先看看Evans是怎样分层的。在书中,Evans将系统分为用户界面层(表示层)、应用层、领域层(模型层)和基础结构层。从他对各个层的表述我们不难看出,用户界面层(表示层)就是前端界面,应用层即是Service层,基础结构层即是DAO、工具类,以及其它的技术支持类。从这个角度来说,Evans在他的书中所说的领域层,在我们的框架中就应当是业务逻辑层(BUS),但事实并不是这样简单。在我们现在的框架中,数据与业务逻辑处理被分离了,举例说吧:

在一个员工信息管理系统中,领域模型可能包含了一个员工类,并且在该类中包含了那些诸如员工编号、姓名、性别、职务等属性。除此以外,一个员工类肯定也包含了诸如“新增员工”、“修改员工资料”之类的行为。领域模型如此,那么软件设计时会是怎样呢?

 

 



  

在设计一个员工信息管理系统时,它必然包含一个“员工BUS”的类,用于执行诸如“新增员工”、“修改员工资料”之类的行为。那么,那些员工的相关属性被放在哪里呢?它们并没有放在“员工BUS”类中,而是“员工”值对象中(注意:这里的值对象不是DDD中的那个值对象,而是ORM,或者说hibernate中的那个值对象)。领域模型的员工类,在软件系统中被分离为了“员工BUS”类和“员工”值对象类。

正是因为这种数据与业务逻辑处理的分离,令一些人产生了误解,错将领域类对应成了Hibernate对象(希望他正在看这里)。没错,领域模型对应的是BUS层,但部分内容被分离到了值对象中。

记得数年前还有POVO的争论,但现在再也没有了。按照现在软件设计的思想,从UI一直到数据库,数据格式变得合成一体了。什么意思呢?页面上的表单是什么样子,提交到后台的值对象就是什么样子,最后持久化成数据库表就是什么样子。按照这样的设计思想,页面上表单中的控件ID、值对象中的属性、数据库表中的字段,都命名成了一致的名称。这样的设计大大简化了程序代码,但因为表单与值对象长得一个模样,也使得一些人误以为领域类对应的是UI

2)运用领域模型开发的软件系统应当是这样的

不论怎样,我认为,运用领域模型开发软件,应当是以领域模型为中心,即以领域模型为蓝本进行开发,就如同建筑图纸与盖楼一样。领域模型中的某个概念类,在软件设计时应当映射成对应的BUS和值对象。同时,为了让开发人员更加专注地去思考那些领域问题,而不为其它技术细节所分析,也许以下方式不失为一个最佳实践之一:

a.       领域模型被映射到了软件框架的BUS层中。领域模型中的每个概念类,在BUS层中都有对应的XxxBus,并且包含了这个概念类中的所有行为(函数)。

b.       领域模型中的每个概念类都映射成了软件系统中的一个值对象。这个值对象包含了概念类的所有数据(即那些属性),以及各概念类之间的关系。但是一个值对象不一定完全对应一个数据库中的表(比如具有继承关系的值对象)。特别注意,《领域驱动设计》中提到的值对象与ORM中的值对象并不是一个概念,书中的实体也与这里的实体不完全是一个概念。

c.       软件系统中的UI尽量与值对象保持一致,即,页面上表单中的控件ID尽量与值对象中的属性保持对应,并通过诸如DWR的技术,将UIBUS能够直接交互,简化过去繁杂的service层操作。

d.       使用BasicDao这样的通用代码来处理数据库持久化操作,将值对象直接扔给insert()update()delete()load()函数,摒弃了过去为每个业务设计DAO的设计;采用hql配置文件的方式,将系统需要查询的语句全部放在配置文件中,然后使用统一的find()函数执行查询,满足各种各样的查询要求。

采用这样一个设计框架好处多多。首先它大大简化了软件开发的内容,过去繁杂的service层和DAO层统统被砍掉,仅仅保留下BUS层和UI层(当然必须有诸如DWR的强大框架和诸如BasicDao自开发的超轻量平台的支持)。我始终认为,每增加一段代码,就增加了一份程序出错的机会。因此我总是不遗余力地试图简化代码,甚至到了发指的地步。

其次,系统的层次划分会非常清晰。UI层就是前端的一堆jsphtmljsBUS就是一堆业务逻辑操作程序(不包含任何诸如hql的数据持久化代码),hql配置文件可以支持多配置文件,因此被分为了“员工管理”配置文件、“部门管理”配置文件、“薪金管理”配置文件。。。。。。

此外,我不得不说,世界终于变得清静了。因为这样一个框架,程序员从那么多羁绊中解脱出来了,他们终于可以全心全意地、以领域模型为中心、仔仔细细地开始考虑那些领域问题了。

在这样一个框架中,每个BUS都有它们自己的职责,这种职责被清清楚楚地标注在各自的注释中。从此,系统开始以职责为中心设计系统了。

 

3)运用领域模型开发的一个简短实例

也许一个实例是最说明问题的,让我们来举一个项目评审系统的例子吧。

在进行一次评审前首先要制定一个评审计划。在这份计划中,要详细定义此次评审的评审人、评审材料。显然,在领域模型中,评审计划是一个重要的概念,而评审人与评审材料是聚合在评审计划下的。随后是在评审过程中制作评审表。每个评审人都要对评审材料制作评审表。最后,评审组织者根据评审人的意见制作评审报告。

在这样一个需求下,我们应当怎样设计“制作评审表”的业务呢?在领域模型中,“制作评审表”应当是“评审表”的职责,也就是它所拥有的行为。因此,我们创建一个“评审表BUS”,并包含“制作评审表”的函数。随后,我们开始编写“制作评审表”的代码。在这里,我们首先要获取“评审者”和“评审材料”。由于这两部分是聚会在评审计划下的,毫无疑问我们应当调用“评审计划”获取“评审者”和“评审材料”(这里的“评审计划”即可以设计成“评审计划BUS”,也可以设计成“评审计划”配置文件)。然后,我们通过前端与用户交互,最终从前端获得用户填写的评审表,利用dwr直接形成“评审表”值对象,在“保存评审表”中调用通用DAO,持久化“评审表”。

在这样的设计过程中,首先当然是设计领域模型了。在完成了领域模型的设计以后,应当是按照领域模型设计BUS和生成值对象(实际工作中可以先生成数据库再生成值对象)。随后开始编写BUS中的各个方法。在编写过程中,应当将某个方法合理地进行分解,根据职责去调用其它类中的方法(正如评审表去调用评审计划获取评审人和评审材料一样)。通过这样,功能被合理地分配到BUS的各个类中,保证了功能组织的高度内聚。

另一个开发中可能出现的问题这里不得不提。按照理想的领域驱动设计的流程,首先应当是需求分析人员分析和设计出领域模型,然后由开发人员照着领域模型设计开发。但是,由于各种各样的原因,实际情况可能并不总是这样。很多时候,开发人员可能没有得到领域模型而仅仅只有需求文档。这样的情况并不意味着开发人员可以摒弃领域模型而直接开始编码。在编码前,一个简短的领域模型分析和绘制领域草图,就是如同砍柴前的磨刀,是一个必不可少的步骤(这也是领域驱动设计与以往开发模式重要的不同点之一)。

领域模型维护与二次开发

前面,我分别讲述了分析人员运用领域模型分析和开发人员运用领域模型设计。在这两部分,我不断强调运用草图快速进行领域模型分析。开发过程总是忙碌而紧凑的,运用草图快速进行领域模型分析可以大大简化我们分析的过程,提高设计开发的效率。但是,这并不意味着我们可以随意处理这些分析草图。正如建筑设计图是建筑设施运行维护的重要资料,领域模型以及其它资料也是软件系统运行维护的重要资料。因此,我认为,这些分析设计草图应当妥善保管,并且在设计开发完成以后,应当专门进行归纳整理,为今后的运行维护和二次开发提供帮助。

另外,前面我提到,Evans的领域驱动设计,一个非常重要的思想就是持续地精化。Evans认为,我们对业务领域的认识是一个逐渐深刻的过程。随着认识的逐渐深刻,我们应该在一些合适的时机去重构我们的设计,甚至软件系统已经设计完成并交付使用以后。这当然要求我们拿出我们的勇气与魄力。在完成一次重构以后,相应的设计文档也应当同步更新。

当我们完成了以上这些领域模型的维护工作,一旦有新的开发工作,有新人参与项目的时候,快速熟悉系统并适应工作就应当是顺理成章的事情了。而我在《软件开发的轮回》中提到的那些痛苦的经历就将不再会出现。

 

也许以上的描述还不够直观,表述得还不够清晰。后面我会通过一个实例详细阐释这样的一个开发过程。

  • 大小: 36.3 KB
分享到:
评论
32 楼 brucehu 2011-01-11  
感觉楼主对DDD的理解还不够,当然这种模式只要适合你的项目就可以,自己觉得能掌控会扩展就行,实际应用的多了,慢慢按照自己的思路设计,然后逐步修改,这个是一个好的习惯。
31 楼 abiandbel 2011-01-05  
1、楼主既然知道实体和值对象在Ecric DDD中的意思,为何在文章中还说Employee是值对象,真是匪夷所思!还是严谨一点改过来吧。

2、DDD中的领域模型是应该有强烈的边界,通常边界的周围都是聚合根,这些才是真正的DDD的重要概念,楼主似乎没有注意到。

3、楼主崇尚贫血模型的DDD?我的感觉是贫血模型的DDD连现在的SSH都不如。
30 楼 xu_zh_h 2010-12-10  
楼主对领域模型的理解我很赞同,但是楼主对领域模型的实施我没有搞懂,而且去掉service和dao我是反对的。
29 楼 nighthawk 2010-03-08  
每个人心中都有个自己的DDD,即使他自认为得到了eric的真传。
28 楼 tobato 2010-03-07  
楼主好像有些概念不是很明确,最好能辅以代码来说明。看了以后也感觉有一些与BigBlue提出的类似的疑惑,尤其是值对象啥的。

如果有代码说明可能就更容易看明白了。
27 楼 mwmw 2010-01-20  
DDD这方面的东西,一直在发展,半年前还没有听说过传说中的CQRS呢,最近开始有人准备做了,如前面的一位同学说的,DDD,特别是Eric说的DDD,有点阳春白雪的样子,永远都是那个例子。 DDD方向的实践,什么是真正的DDD,这样的问题才是最重要的。

有很多DDD的实现,opensource的,但是每个是一个样子,每个有自己的理解。如果在一个简单项目里面做了DDD,或者是所谓的DDD,没有多少参考价值。 也尝试着DDD,但是越做到最后越是迷茫。难道充血了,难道加上了factory,换成了Repository就是DDD了吗?这样的DDD跟其他的又有什么本质的区别呢?

请有经验的多分享。
26 楼 61234865 2010-01-20  
如果我是在一个月以前看楼主这文章的话,绝对是觉得看不懂,全是空谈,但现在不一样,公司 来了个牛人,在这一个月的时间里,我以前一直理解的java面向对象完全有了一个新人认识,再次感谢楼主提供这么好的东西
25 楼 chen422520 2010-01-19  
飘过,飘过
24 楼 kevinyao 2010-01-14  
TO BIgBlue
呵呵,我正准备在下一个项目中实施目前所了解的DDD方面的知识,现在纯属纸上谈兵。
有DDD实战经验的大佬们能否站出来给各位同学讲讲心得体会啊。
23 楼 BigBlue 2010-01-13  
kevinyao 写道

1,怎样抽取领域模型。


业务是复杂的,建立Domain model对很多人来说比较困难,这实际上阻碍了DDD的普及。建一个好的Model就像作家写一部成功的小说。
DDD是建立在OO的基础上。OO的炒作已经30年了,提起OO似乎都有落伍的嫌疑,但是又有多少人在真正在用OO呢?多少人和机构是在挂羊头卖狗肉呢?从另一方面我也在反思,不能普及的技术是好技术么?很多人不也是用过程八项目做出来了么?

kevinyao 写道

Application是Transaction边界。这个消息也可以称之为Domain Event。
这个消息框架的设计,有2种方案:(1)观察者模式(2)JMS 。
利用JMS处理信息的时候,可以采用同期和非同期,根据自己的业务要求来定。


Domain Event研究的不多,能否分享一下经验

kevinyao 写道


2,怎样基于领域模型进行框架设计。
各位同学如果有兴趣的话,请看看这份框架设计http://dddsample.sourceforge.net/
dddsample提供了一个很好的例子,不过自己在借鉴的过程中要区别使用。
BigBlue的一些疑惑也是我看这份代码的疑惑。如果大家有兴趣的话,我们再开一贴,专门讨论怎样借鉴dddsample来进行领域驱动设计,呵呵。
暂时先借一个地方说说,从dddsample里我的疑惑:
(1)事务的一致性处理
要保持事务的一致性,在跨多个领域模型更新操作的时候,必须是同期处理。如果采用非同期处理,要保持事务的一致性,就要采用分布式事务。
有没有折衷的办法呢?dddsample里用的是非同期处理,没有采用分布式事务处理。dddsample为了提高可用性,而牺牲了一致性。

   没有仔细研究过dddsample的这个方面。分布式事务很麻烦,特别是异构的系统,有时候不得不牺牲一致性。
    想听听你的看法。

kevinyao 写道

(2)增删改和查询统计的区别处理
在目前还是以关系型数据库为主流的持久化时代中,查询统计一般都是通过存储过程来实现的。这样一来业务逻辑就很有可能分散在领域模型和存储过程两个地方了,不方便维护。各位同学有没有好的方案?http://code.google.com/p/cqrs4j/提供了一种方案,有谁在开发中实践过这个框架吗?

    如果不是性能问题,我一直不赞同使用存储过程,这个问题我一般是这么考虑的:
    .NET领域可以选择Linq来解决查询问题,
     JPA可以通过JPQL或者Criteria API来解决

kevinyao 写道


总之,业务层采用Domain + DomainEvent + Cache,表现层适当采用Ajax,应该能够构建一个灵活的,柔软的框架,代码质量也会有所提高。

把这些内容整理一下就可以新开一贴了
22 楼 BigBlue 2010-01-13  
mwmw 写道
现在又多少大型项目用了真正的DDD,DDD虽然已经出来了这么多年了,但是用起来还是蛮麻烦的,也是蛮复杂的。概念上是好的,Repository,Domain Event,Factory,Bus很多东西都是换了一个名字。

DDD可行,很好,没有在大型项目中系统的用过。小项目的DDD不能体现出其中的魅力。


DDD有点阳春白雪的意思.
:)
21 楼 BigBlue 2010-01-13  
fangang 写道
这篇文章我犹豫了数天,最后还是贴上来了,但不得不承认比较失败,即有许多地方没有描述清楚,也有许多地方认识还不深刻,但也许可以提出来作为一次有益的尝试吧。

我这个人崇尚大胆地改造,我希望将领域驱动设计实实在在地运用到我们的开发中,并大胆地改造我们的开发模式。但这依然是一个艰巨的工作。希望这里能作为一个我们探索和探讨的场所吧:)


其实你的前几部分我都看了,说实话还不错,但是最后这一部分在吊足了大家胃口的同时没有看到预期的东西.
你确实是在做大胆的改造
20 楼 BigBlue 2010-01-13  
fangang 写道
当你在质疑我的文章的时候,我首先想到的是,我的文章是否把我的思想表述清楚,也许我真应当重构一下我的文章了。

你给的这篇文章谈的是贫血与富血的讨论。Robbin似乎一直倾向于富血,但我毫无疑问是倾向于贫血而质疑富血的。

Service可以省,因为有dwr支持,DAO可以省,因为有hibernate的支持。在我看来,值对象就只应当包含要持久化的数据,和表间的关系(值对象的建立应当基本上与领域模型中的概念类(不包含行为)保持一致,注意这里的值对象概念是hibernate中的值对象概念,而不是DDD中的值对象概念)。而领域模型中的那些行为,应当全部放到BUS中,即领域层。这个意思就是我所说的数据与业务逻辑分离。

这篇文章可能理论概述多了一点儿,很难把我的意思表达清楚。我正在策划写一篇新的文章,用一个实例来讲述我怎样用领域驱动设计去分析和设计一个系统的。


1.我并不是要进行对与错的质疑,而是质疑是面向对象还是面向过程,是Eric的DDD,还是其它的.我并不认为你的方式是Eric的DDD的一个落地,因此才建议你改名字,以免引起混淆和无谓的争议;

2.我要说的Service是指Eric所谓的中等粒度,无状态的分割领域和应用的那一层次.你通过DWR实现了将BUS暴露出去(这只是个技术实现),但是你的Entity(Bus)如果每个都映射到一个领域概念,那么肯定是细粒度的.除非在你的BUS中分割出来一部分类不映射到失体,承担粗粒度的职责.因此不是Service可以省略的问题.而是你的应用中省略了Eric的Service;

3.Eric的DDD中不提倡DAO,而是根据实体的聚合关系划分不同的仓库.

4.看过DDD的人,会对你所说的值对象感到不知所措;

最后,我并不是要表达我多么崇拜DDD,你要是不符合Eric的DDD就是多么的谬误,说了这么多核心要表达的就是,楼主的东西和Eric的东西差异很大,已经不适合在同一个名号下来讨论了.
19 楼 fangang 2010-01-13  
这篇文章我犹豫了数天,最后还是贴上来了,但不得不承认比较失败,即有许多地方没有描述清楚,也有许多地方认识还不深刻,但也许可以提出来作为一次有益的尝试吧。

我这个人崇尚大胆地改造,我希望将领域驱动设计实实在在地运用到我们的开发中,并大胆地改造我们的开发模式。但这依然是一个艰巨的工作。希望这里能作为一个我们探索和探讨的场所吧:)
18 楼 kevinyao 2010-01-13  
关于领域驱动设计,一直想在项目中实施,但是一直没有发现成型的方案。如果仅仅划分几个层次,限于贫血模型和充血模型的讨论,那么我们还是老一套开发,那就是结构化的,刚性的框架设计。就以上讨论,大家主要集中于两点:
1,怎样抽取领域模型。
   楼主重点说明了领域模型的重要性和大致概念,并举了“付款单生成凭证”实例。
   楼主又提到在一个员工信息管理系统中,员工领域模型映射成了2个类,Employee, EmployeeBUS。Employee类包括各个属性,EmployeeBUS类包括行为。个人觉得和普通意义上的领域模型驱动不一致。普遍来讲,领域模型包括聚合根,值对象,服务,仓储等等概念。
如果能给一个完整的实例可以更加深入讨论。

我来举一个例子,
比如物流系统中,客户要下一个订单(Order),可以设计一个关于订单的领域模型,Order是聚合根,包括很多商品(Product),做订单时候要查询这个客户的余额,那么需要设计一个服务类(OrderService),与早期的Service 类不一样,仅仅是业务规则而已。OrderService 向Application发出消息“需要某帐户余额”,由Application来调用Account类提供余额信息。
Application是Transaction边界。这个消息也可以称之为Domain Event。
这个消息框架的设计,有2种方案:(1)观察者模式(2)JMS 。
利用JMS处理信息的时候,可以采用同期和非同期,根据自己的业务要求来定。

2,怎样基于领域模型进行框架设计。
各位同学如果有兴趣的话,请看看这份框架设计http://dddsample.sourceforge.net/
dddsample提供了一个很好的例子,不过自己在借鉴的过程中要区别使用。
BigBlue的一些疑惑也是我看这份代码的疑惑。如果大家有兴趣的话,我们再开一贴,专门讨论怎样借鉴dddsample来进行领域驱动设计,呵呵。
暂时先借一个地方说说,从dddsample里我的疑惑:
(1)事务的一致性处理
要保持事务的一致性,在跨多个领域模型更新操作的时候,必须是同期处理。如果采用非同期处理,要保持事务的一致性,就要采用分布式事务。
有没有折衷的办法呢?dddsample里用的是非同期处理,没有采用分布式事务处理。dddsample为了提高可用性,而牺牲了一致性。

(2)增删改和查询统计的区别处理
在目前还是以关系型数据库为主流的持久化时代中,查询统计一般都是通过存储过程来实现的。这样一来业务逻辑就很有可能分散在领域模型和存储过程两个地方了,不方便维护。各位同学有没有好的方案?http://code.google.com/p/cqrs4j/提供了一种方案,有谁在开发中实践过这个框架吗?

总之,业务层采用Domain + DomainEvent + Cache,表现层适当采用Ajax,应该能够构建一个灵活的,柔软的框架,代码质量也会有所提高。
17 楼 梦回下花园 2010-01-13  
功力有限,越往后看越看不懂。回头好好补课,就从DDD开始吧。
16 楼 lishuanglin52130 2010-01-13  
  前面讲的几章节我都很仔细看了,对我映像非常深刻。绝大初级程序员,完成一个功能,就敷衍了事了,就知道大概流程,就我公司一位女程序员,我们经理跟她说需求的时候,话没说完,就说:“这个我懂了”。当时老板很高兴,招了人才,到真实开发的时候,我就问她的说懂的那个流程,她一句:“我也不知道”,叫我问经理.我无语.
  开发建立在某个模式之上,然后复查自己的某个领域的程序设计,总结.这样可以提升自己.
  
  
15 楼 mwmw 2010-01-12  
现在又多少大型项目用了真正的DDD,DDD虽然已经出来了这么多年了,但是用起来还是蛮麻烦的,也是蛮复杂的。概念上是好的,Repository,Domain Event,Factory,Bus很多东西都是换了一个名字。

DDD可行,很好,没有在大型项目中系统的用过。小项目的DDD不能体现出其中的魅力。
14 楼 fangang 2010-01-12  
当你在质疑我的文章的时候,我首先想到的是,我的文章是否把我的思想表述清楚,也许我真应当重构一下我的文章了。

你给的这篇文章谈的是贫血与富血的讨论。Robbin似乎一直倾向于富血,但我毫无疑问是倾向于贫血而质疑富血的。

Service可以省,因为有dwr支持,DAO可以省,因为有hibernate的支持。在我看来,值对象就只应当包含要持久化的数据,和表间的关系(值对象的建立应当基本上与领域模型中的概念类(不包含行为)保持一致,注意这里的值对象概念是hibernate中的值对象概念,而不是DDD中的值对象概念)。而领域模型中的那些行为,应当全部放到BUS中,即领域层。这个意思就是我所说的数据与业务逻辑分离。

这篇文章可能理论概述多了一点儿,很难把我的意思表达清楚。我正在策划写一篇新的文章,用一个实例来讲述我怎样用领域驱动设计去分析和设计一个系统的。
13 楼 BigBlue 2010-01-12  
恕我愚钝,楼主的例子中除了CRUD,没有看到什么复杂的业务逻辑.

楼主不妨用你的框架实现一下这个例子
http://www.iteye.com/topic/57075

相关推荐

Global site tag (gtag.js) - Google Analytics