- 浏览: 887842 次
- 性别:
- 来自: 北京
-
文章分类
最新评论
-
Junjing:
非常感谢楼主的分享,受益匪浅!我是一位从业务规划和运营转需求分 ...
我们应当怎样做需求确认:评审与签字确认会 -
kersky:
感谢楼主的辛苦输出,半天看完了整个系列。对于一个转从开发转需求 ...
我们应当怎样做需求确认:评审与签字确认会 -
DEMONU:
必须要顶
谈谈软件开发的那些事儿 之 软件开发的轮回 -
dripstone:
非常感谢楼主,用了大半天的时间,一口气读完了需求分析阶段。好多 ...
我们应当怎样做需求确认:评审与签字确认会 -
Codepoe:
做了一些开发,看了楼主的文章,我深有感触,为自己的做法找到了理 ...
我们应当改变我们的设计习惯
终于到了该说说领域驱动设计的时候了。我们在这场关于代码质量的讨论中,从代码可读性开始,讨论了代码复用性、设计模式,然后探讨了职责驱动设计。代码可读性是对代码质量最基本的要求,可惜我们仍有做得不够的(即使那些开发程序很多年的老程序员)。代码复用是提高代码质量的最初级阶段,但是在一个多人开发的项目团队中,围绕代码复用值得讨论的问题依然非常多,它依然是一个非常复杂的问题,甚至有时它不再仅仅是一个技术问题,而是一个管理问题。唉,提高代码质量的道理漫漫兮同志们要上下而求索。一个比较成功的保证代码质量的管理模式就是代码复查。让一些有经验的程序员定期去复查那些初级程序员的代码,指导他们的开发,被认为是成功的,但也代价巨大的。
然而,在这场关于代码质量的讨论中,我认为,最终的终极目标毫无疑问应当是“领域驱动设计”。领域驱动设计可以快速而根本地提高我们的代码质量,举一个最近发生的一件事情也许可以深刻地说明这一点。前不久,我将一个开发任务交给了我的一个手下。一周后,当我对他的代码进行复查的时候,我惊呆了。我甚至不能提出任何的建议来优化他的代码。随后,我花了半个小时的时间与他一起进行了一次领域模型分析,将他开发的这个模块用领域模型绘制了一个草图。随后的数日,他照着这个图纸重新进行了编码。当我再次复查他的代码时,我忍不住笑了。在短短的一周时间内能让一个人的代码质量判若两人,这不得不说是领域驱动设计带给我们的震撼。
但是,在领域驱动设计之前,我用大量篇幅讲解了职责驱动设计。职责驱动设计是领域驱动设计的理论基础,领域驱动设计是职责驱动设计的最佳实践。领域驱动设计要求我们以领域模型作为我们分析与开发的核心,为什么?因为我们的设计应当与现实世界保持“低表示差异”。领域驱动设计强调所有的领域对象应当以现实世界作为模板,为其定义和分配行为,为什么?因为我们的设计应当以职责为中心,按职责分配行为,分配行为的原则可以参照“信息专家”模式。领域驱动设计并不是横空出世的,而是在职责驱动设计的基础之上发展的。理解职责驱动设计可以促进我们对领域驱动设计的理解,然而非常遗憾的是,它却长期游离于我们的视线之外。
低表示差异与领域模型
我在前面的“职责驱动设计”部分已经讨论了“低表示差异”。用一句简短的话说,在我们的分析设计中,软件世界始终应当与现实世界保持“低表示差异”。如何保持低表示差异呢?答案就是领域模型分析。
领域驱动设计,其名称中,将“领域(Domain)”这个词放在了最显著的位置上,为什么呢?因为它的理论核心就是领域。在需求分析和设计阶段使用领域模型与客户进行软件需求的讨论。在这个阶段,领域模型是最重要的一个验收成果,没有完成领域模型分析,这个阶段就永远不算结束。在软件开发阶段采用领域模型作为核心设计图纸指导设计开发。领域模型怎样设计则我们的软件系统就怎样设计,软件系统中的最主要软件类都是源自领域模型中定义的领域对象。在运行维护及二次开发阶段,领域模型就如同房屋建筑中的设计图纸,它成为运行维护人员和二次开发人员熟悉和理解软件系统的核心线索。总之,在领域驱动设计中,领域模式成为最最核心的内容。所以我们应当首先理解什么是领域模型。
领域模型是对现实世界中某个业务领域的抽象。我们设计的软件不是对所有现实世界的模拟,而是对某个领域的模拟,譬如财务领域、税务领域、企业管理领域等等。这个领域我们称之为“业务领域”,而在这个领域里工作,并熟悉掌握这个领域中所有知识的人我们称之为“领域专家”。我们的分析和设计人员对业务领域的熟悉和理解的程度,往往决定我们的软件是否满足客户需求,也往往就决定了我们的软件是否成功。领域驱动设计理论要求我们在需求分析阶段必须非常深入地理解业务领域,采用的方式就是领域模型分析。同时,在这样一个过程中,应该有领域专家参与,甚至成为分析设计中的一个成员。
过去我们使用用例模型与领域专家交流,直到现在我们依然还在这样做。用例模型分析是我们分析设计的方法之一,但现在我们又有了一个新的强有力的工具,那就是领域模型分析。与用例模型比较,领域模型更加直观,可以更加立体地描述现实世界。如果说过去的需求设计文档是二维世界,用例模型只是二维半,领域模型才是真三维世界。领域模型是一大堆的类图,它描述的是业务领域中的各个事物,以及事物与事物之间的关系。
从业务领域中获取知识
说了这么多东西,现在让我们来点儿实在的东西吧:如何进行领域模型分析?建立领域模型需要从业务领域中获取素材。获取领域模型所需素材通常有两个途径:与领域专家的现场交流会中获得,和从用例模型的各个流程中提取名词或名词短语获得。我们将这些获取的素材经过加工,形成我们在领域模型中的一个又一个的类,这些类我们称之为概念类。现在的问题是,哪些应当成为领域模型中的概念类呢?如果我引用一堆定义和准则,并不能让你清楚明了,也许一个生动的比喻更能够让你理解深刻。需求分析有时候就像一部部动画剧,而那些枯燥乏味的概念,纷繁复杂的流程,在这些动画剧中似乎都突然活了,个个都有语言有性格。在这些动画剧中扮演的所有角色,就是我们需要的概念类。而他们做的所有动作,就是用例模型中的所有流程。
1)在业务讨论会中绘制领域模型
运用我曾经一篇文章中的实例来更加生动地描述这样一个过程吧:
在一个阳光明媚的下午,我们一个个西装革履、精神抖擞地来到了客户的办公现场。在一个明亮的会议室里,宽大深褐色的椭圆木桌旁已经聚集了十来个业务人员。看到我们进来,大家握手问候。相继就座后,互相介绍,往来寒暄,唠唠家常。共同的家乡,或熟或不怎么熟的某个人,都可能成为拉近彼此关系的理由。逐渐,一切开始进入正题。客户开始絮絮叨叨的描述自己的需求,而我们则在紧张的做着记录,时不时问一些问题,表明我们的立场,抒发我们的建议。在这样一个过程中,客户会描述他们的每一个业务,会讲解每个业务的流程,他们会讲出一些业务领域的专业词汇(尽管有些你当时还不太懂)。在这样一个过程中,作为需求分析员,你应当非常注意业务流程中的一些关键词汇,你应当(在当时或者过后)将它们提取出来,通过询问客户,弄清楚他们的定义,以及相互之间的关系。而这些词汇就是建立领域模型的开始。
这样的讨论会不可能是一次两次,而是数次。在这样的讨论会中,也许一支笔和一摞白纸会非常有用。在这样的讨论会中,你可以迅速将从客户那里理解的各种概念和知识,立即在白纸上画出一个又一个的草图。那些关键词汇被绘制成了一个个的概念类和它的属性(如果确实需要),用线条迅速标注出相互之间的关系。在你绘制的时候,客户会在不断地给你指正,或者说出了更多的业务知识。一张张的草图成为了你与客户交流的工具,也是最初始的领域模型。
这是一个财务软件的业务讨论会,一个业务人员正在跟我讲付款单是怎样制作成凭证的。“每张付款单都有一个商品明细,每个商品明细都有它的价格、数量和金额。”他指着一张付款单向我解释着。从这句话,我可以提出一些关键信息:付款单、商品明细、价格、数量和金额。付款单与商品明细是一对多关系,并且商品明细聚合在付款单中。每个商品明细都有价格、数量和金额,也就是说,价格、数量和金额是商品明细的属性,这都很清楚。紧接着,他下面的讲解就不是那么清楚容易了。“如果按照一张单据生成一张凭证,那么每张付款单生成一张凭证。单据中的每个明细在凭证中生成一条借方分录和一条贷方分录。将付款单中的付款科目作为借方科目,将付款单结算方式对应的结算方式科目作为贷方科目。现结的付款单在采购发 票中已制作凭证了,因此不再单独制作凭证。非预付的付款单不制作凭证,而是其执行付款核销以后,在核销单中制作凭证。”经过对以上语言的分析,我们可以绘制以下关系:一张凭证包含多个分录,是内聚关系。分录分为借方分录和贷方分录两种。一条商品明细对应一条借方分录和一条贷方分录。借方分录中包含“借方科目”属性,对应付款单中的付款科目;贷方分录中包含“贷方科目”属性,对应的是付款单中的一个什么科目。在这里,你可能对客户的某些描述不明白,因此要他做出解释。原来客户预先制订了一个规则,付款单中的结算方式分布对应了一个结算方式科目。OK,你在绘制的图形中,把结算方式科目作为关联类,将结算方式和贷方科目进行了一个关联。这样,“付款单生成凭证”这样一个场景的领域模型就绘制出来。
2)归纳和整理领域模型
在现场讨论会中,可能一些关键的概念被你忽略掉了。也可能一些关键性的关系被你忽略,或者在草图上并没有很好地表达,甚至存在谬误和矛盾。随着你事后的分析和整理,你从用例模型的流程描述中提取出了更多的概念。同时,随着你对问题的一步一步深入理解,你开始重构你起初的领域模型。在Evans的《领域驱动设计》中,他用大量的篇幅和实例描述和讲解了这样一个过程。另外一个重要的概念是,深入理解和重构领域模型不仅仅是在软件需求分析的阶段完成,它贯穿了整个软件开发的周期。按照迭代软件开发的思想,我们绝不能企图在需求分析阶段完成所有的分析(那是瀑布的思想)。随着我们对业务领域的深入理解,重构和精化领域模型贯穿整个“开发—维护—再开发”的过程中。而这也正符合了现代软件开发业的发展需求(我参与的项目已经经历了快5个年头,每年都在经历着新的开发)。
经过了这样的、有领域专家参与的、反复讨论与整理的过程,我们对业务领域理解将越来越深入,而我们设计的领域模型将越来越贴近现实世界中事物的本质。运用这样的领域模型图纸去开发我们的软件,毫无疑问我们已经成功了一半。(制作领域模型的更多细节见我的相关博客,我也会写更多的文章讨论)
运用领域模型开发软件
曾经有个笑话是这样说的:大师们站的高度都是非常高的,高到什么程度?他们都是生活在太空中的。追随大师是一个高风险的职业,为什么?一不小心就能让我们因缺氧而死掉。这个笑话非常深刻的道出了追随大师的关键,那就是怎样“着陆”,也就是如何“落地”。一个高深的理论,如果不能指导我们的实际工作,那么这个理论是没有价值的,领域驱动设计也是一样。下面我们来讨论一下如何运用领域模型指导我们的软件开发。
1)领域模型在我们的软件框架中扮演的是什么角色
首先第一个要解决的问题是,领域模型在我们的软件框架中,特别是时下最常见的Spring+Hibernate框架中扮演的是什么角色。我们不妨先看看Evans是怎样分层的。在书中,Evans将系统分为用户界面层(表示层)、应用层、领域层(模型层)和基础结构层。从他对各个层的表述我们不难看出,用户界面层(表示层)就是前端界面,应用层即是Service层,基础结构层即是DAO、工具类,以及其它的技术支持类。从这个角度来说,Evans在他的书中所说的领域层,在我们的框架中就应当是业务逻辑层(BUS),但事实并不是这样简单。在我们现在的框架中,数据与业务逻辑处理被分离了,举例说吧:
在一个员工信息管理系统中,领域模型可能包含了一个员工类,并且在该类中包含了那些诸如员工编号、姓名、性别、职务等属性。除此以外,一个员工类肯定也包含了诸如“新增员工”、“修改员工资料”之类的行为。领域模型如此,那么软件设计时会是怎样呢?
在设计一个员工信息管理系统时,它必然包含一个“员工BUS”的类,用于执行诸如“新增员工”、“修改员工资料”之类的行为。那么,那些员工的相关属性被放在哪里呢?它们并没有放在“员工BUS”类中,而是“员工”值对象中(注意:这里的值对象不是DDD中的那个值对象,而是ORM,或者说hibernate中的那个值对象)。领域模型的员工类,在软件系统中被分离为了“员工BUS”类和“员工”值对象类。
正是因为这种数据与业务逻辑处理的分离,令一些人产生了误解,错将领域类对应成了Hibernate对象(希望他正在看这里)。没错,领域模型对应的是BUS层,但部分内容被分离到了值对象中。
记得数年前还有PO和VO的争论,但现在再也没有了。按照现在软件设计的思想,从UI一直到数据库,数据格式变得合成一体了。什么意思呢?页面上的表单是什么样子,提交到后台的值对象就是什么样子,最后持久化成数据库表就是什么样子。按照这样的设计思想,页面上表单中的控件ID、值对象中的属性、数据库表中的字段,都命名成了一致的名称。这样的设计大大简化了程序代码,但因为表单与值对象长得一个模样,也使得一些人误以为领域类对应的是UI。
2)运用领域模型开发的软件系统应当是这样的
不论怎样,我认为,运用领域模型开发软件,应当是以领域模型为中心,即以领域模型为蓝本进行开发,就如同建筑图纸与盖楼一样。领域模型中的某个概念类,在软件设计时应当映射成对应的BUS和值对象。同时,为了让开发人员更加专注地去思考那些领域问题,而不为其它技术细节所分析,也许以下方式不失为一个最佳实践之一:
a. 领域模型被映射到了软件框架的BUS层中。领域模型中的每个概念类,在BUS层中都有对应的XxxBus,并且包含了这个概念类中的所有行为(函数)。
b. 领域模型中的每个概念类都映射成了软件系统中的一个值对象。这个值对象包含了概念类的所有数据(即那些属性),以及各概念类之间的关系。但是一个值对象不一定完全对应一个数据库中的表(比如具有继承关系的值对象)。特别注意,《领域驱动设计》中提到的值对象与ORM中的值对象并不是一个概念,书中的实体也与这里的实体不完全是一个概念。
c. 软件系统中的UI尽量与值对象保持一致,即,页面上表单中的控件ID尽量与值对象中的属性保持对应,并通过诸如DWR的技术,将UI与BUS能够直接交互,简化过去繁杂的service层操作。
d. 使用BasicDao这样的通用代码来处理数据库持久化操作,将值对象直接扔给insert()、update()、delete()、load()函数,摒弃了过去为每个业务设计DAO的设计;采用hql配置文件的方式,将系统需要查询的语句全部放在配置文件中,然后使用统一的find()函数执行查询,满足各种各样的查询要求。
采用这样一个设计框架好处多多。首先它大大简化了软件开发的内容,过去繁杂的service层和DAO层统统被砍掉,仅仅保留下BUS层和UI层(当然必须有诸如DWR的强大框架和诸如BasicDao自开发的超轻量平台的支持)。我始终认为,每增加一段代码,就增加了一份程序出错的机会。因此我总是不遗余力地试图简化代码,甚至到了发指的地步。
其次,系统的层次划分会非常清晰。UI层就是前端的一堆jsp、html和js,BUS就是一堆业务逻辑操作程序(不包含任何诸如hql的数据持久化代码),hql配置文件可以支持多配置文件,因此被分为了“员工管理”配置文件、“部门管理”配置文件、“薪金管理”配置文件。。。。。。
此外,我不得不说,世界终于变得清静了。因为这样一个框架,程序员从那么多羁绊中解脱出来了,他们终于可以全心全意地、以领域模型为中心、仔仔细细地开始考虑那些领域问题了。
在这样一个框架中,每个BUS都有它们自己的职责,这种职责被清清楚楚地标注在各自的注释中。从此,系统开始以职责为中心设计系统了。
3)运用领域模型开发的一个简短实例
也许一个实例是最说明问题的,让我们来举一个项目评审系统的例子吧。
在进行一次评审前首先要制定一个评审计划。在这份计划中,要详细定义此次评审的评审人、评审材料。显然,在领域模型中,评审计划是一个重要的概念,而评审人与评审材料是聚合在评审计划下的。随后是在评审过程中制作评审表。每个评审人都要对评审材料制作评审表。最后,评审组织者根据评审人的意见制作评审报告。
在这样一个需求下,我们应当怎样设计“制作评审表”的业务呢?在领域模型中,“制作评审表”应当是“评审表”的职责,也就是它所拥有的行为。因此,我们创建一个“评审表BUS”,并包含“制作评审表”的函数。随后,我们开始编写“制作评审表”的代码。在这里,我们首先要获取“评审者”和“评审材料”。由于这两部分是聚会在评审计划下的,毫无疑问我们应当调用“评审计划”获取“评审者”和“评审材料”(这里的“评审计划”即可以设计成“评审计划BUS”,也可以设计成“评审计划”配置文件)。然后,我们通过前端与用户交互,最终从前端获得用户填写的评审表,利用dwr直接形成“评审表”值对象,在“保存评审表”中调用通用DAO,持久化“评审表”。
在这样的设计过程中,首先当然是设计领域模型了。在完成了领域模型的设计以后,应当是按照领域模型设计BUS和生成值对象(实际工作中可以先生成数据库再生成值对象)。随后开始编写BUS中的各个方法。在编写过程中,应当将某个方法合理地进行分解,根据职责去调用其它类中的方法(正如评审表去调用评审计划获取评审人和评审材料一样)。通过这样,功能被合理地分配到BUS的各个类中,保证了功能组织的高度内聚。
另一个开发中可能出现的问题这里不得不提。按照理想的领域驱动设计的流程,首先应当是需求分析人员分析和设计出领域模型,然后由开发人员照着领域模型设计开发。但是,由于各种各样的原因,实际情况可能并不总是这样。很多时候,开发人员可能没有得到领域模型而仅仅只有需求文档。这样的情况并不意味着开发人员可以摒弃领域模型而直接开始编码。在编码前,一个简短的领域模型分析和绘制领域草图,就是如同砍柴前的磨刀,是一个必不可少的步骤(这也是领域驱动设计与以往开发模式重要的不同点之一)。
领域模型维护与二次开发
前面,我分别讲述了分析人员运用领域模型分析和开发人员运用领域模型设计。在这两部分,我不断强调运用草图快速进行领域模型分析。开发过程总是忙碌而紧凑的,运用草图快速进行领域模型分析可以大大简化我们分析的过程,提高设计开发的效率。但是,这并不意味着我们可以随意处理这些分析草图。正如建筑设计图是建筑设施运行维护的重要资料,领域模型以及其它资料也是软件系统运行维护的重要资料。因此,我认为,这些分析设计草图应当妥善保管,并且在设计开发完成以后,应当专门进行归纳整理,为今后的运行维护和二次开发提供帮助。
另外,前面我提到,Evans的领域驱动设计,一个非常重要的思想就是持续地精化。Evans认为,我们对业务领域的认识是一个逐渐深刻的过程。随着认识的逐渐深刻,我们应该在一些合适的时机去重构我们的设计,甚至软件系统已经设计完成并交付使用以后。这当然要求我们拿出我们的勇气与魄力。在完成一次重构以后,相应的设计文档也应当同步更新。
当我们完成了以上这些领域模型的维护工作,一旦有新的开发工作,有新人参与项目的时候,快速熟悉系统并适应工作就应当是顺理成章的事情了。而我在《软件开发的轮回》中提到的那些痛苦的经历就将不再会出现。
也许以上的描述还不够直观,表述得还不够清晰。后面我会通过一个实例详细阐释这样的一个开发过程。
评论
2、DDD中的领域模型是应该有强烈的边界,通常边界的周围都是聚合根,这些才是真正的DDD的重要概念,楼主似乎没有注意到。
3、楼主崇尚贫血模型的DDD?我的感觉是贫血模型的DDD连现在的SSH都不如。
如果有代码说明可能就更容易看明白了。
有很多DDD的实现,opensource的,但是每个是一个样子,每个有自己的理解。如果在一个简单项目里面做了DDD,或者是所谓的DDD,没有多少参考价值。 也尝试着DDD,但是越做到最后越是迷茫。难道充血了,难道加上了factory,换成了Repository就是DDD了吗?这样的DDD跟其他的又有什么本质的区别呢?
请有经验的多分享。

呵呵,我正准备在下一个项目中实施目前所了解的DDD方面的知识,现在纯属纸上谈兵。
有DDD实战经验的大佬们能否站出来给各位同学讲讲心得体会啊。
1,怎样抽取领域模型。
业务是复杂的,建立Domain model对很多人来说比较困难,这实际上阻碍了DDD的普及。建一个好的Model就像作家写一部成功的小说。
DDD是建立在OO的基础上。OO的炒作已经30年了,提起OO似乎都有落伍的嫌疑,但是又有多少人在真正在用OO呢?多少人和机构是在挂羊头卖狗肉呢?从另一方面我也在反思,不能普及的技术是好技术么?很多人不也是用过程八项目做出来了么?
Application是Transaction边界。这个消息也可以称之为Domain Event。
这个消息框架的设计,有2种方案:(1)观察者模式(2)JMS 。
利用JMS处理信息的时候,可以采用同期和非同期,根据自己的业务要求来定。
Domain Event研究的不多,能否分享一下经验
2,怎样基于领域模型进行框架设计。
各位同学如果有兴趣的话,请看看这份框架设计http://dddsample.sourceforge.net/
dddsample提供了一个很好的例子,不过自己在借鉴的过程中要区别使用。
BigBlue的一些疑惑也是我看这份代码的疑惑。如果大家有兴趣的话,我们再开一贴,专门讨论怎样借鉴dddsample来进行领域驱动设计,呵呵。
暂时先借一个地方说说,从dddsample里我的疑惑:
(1)事务的一致性处理
要保持事务的一致性,在跨多个领域模型更新操作的时候,必须是同期处理。如果采用非同期处理,要保持事务的一致性,就要采用分布式事务。
有没有折衷的办法呢?dddsample里用的是非同期处理,没有采用分布式事务处理。dddsample为了提高可用性,而牺牲了一致性。
没有仔细研究过dddsample的这个方面。分布式事务很麻烦,特别是异构的系统,有时候不得不牺牲一致性。
想听听你的看法。
(2)增删改和查询统计的区别处理
在目前还是以关系型数据库为主流的持久化时代中,查询统计一般都是通过存储过程来实现的。这样一来业务逻辑就很有可能分散在领域模型和存储过程两个地方了,不方便维护。各位同学有没有好的方案?http://code.google.com/p/cqrs4j/提供了一种方案,有谁在开发中实践过这个框架吗?
如果不是性能问题,我一直不赞同使用存储过程,这个问题我一般是这么考虑的:
.NET领域可以选择Linq来解决查询问题,
JPA可以通过JPQL或者Criteria API来解决
总之,业务层采用Domain + DomainEvent + Cache,表现层适当采用Ajax,应该能够构建一个灵活的,柔软的框架,代码质量也会有所提高。
把这些内容整理一下就可以新开一贴了
DDD可行,很好,没有在大型项目中系统的用过。小项目的DDD不能体现出其中的魅力。
DDD有点阳春白雪的意思.
:)
我这个人崇尚大胆地改造,我希望将领域驱动设计实实在在地运用到我们的开发中,并大胆地改造我们的开发模式。但这依然是一个艰巨的工作。希望这里能作为一个我们探索和探讨的场所吧:)
其实你的前几部分我都看了,说实话还不错,但是最后这一部分在吊足了大家胃口的同时没有看到预期的东西.
你确实是在做大胆的改造

你给的这篇文章谈的是贫血与富血的讨论。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的东西差异很大,已经不适合在同一个名号下来讨论了.
我这个人崇尚大胆地改造,我希望将领域驱动设计实实在在地运用到我们的开发中,并大胆地改造我们的开发模式。但这依然是一个艰巨的工作。希望这里能作为一个我们探索和探讨的场所吧:)
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,应该能够构建一个灵活的,柔软的框架,代码质量也会有所提高。
开发建立在某个模式之上,然后复查自己的某个领域的程序设计,总结.这样可以提升自己.
DDD可行,很好,没有在大型项目中系统的用过。小项目的DDD不能体现出其中的魅力。
你给的这篇文章谈的是贫血与富血的讨论。Robbin似乎一直倾向于富血,但我毫无疑问是倾向于贫血而质疑富血的。
Service可以省,因为有dwr支持,DAO可以省,因为有hibernate的支持。在我看来,值对象就只应当包含要持久化的数据,和表间的关系(值对象的建立应当基本上与领域模型中的概念类(不包含行为)保持一致,注意这里的值对象概念是hibernate中的值对象概念,而不是DDD中的值对象概念)。而领域模型中的那些行为,应当全部放到BUS中,即领域层。这个意思就是我所说的数据与业务逻辑分离。
这篇文章可能理论概述多了一点儿,很难把我的意思表达清楚。我正在策划写一篇新的文章,用一个实例来讲述我怎样用领域驱动设计去分析和设计一个系统的。
发表评论
-
谈谈领域模型的那些事儿 之 从领域获取知识
2012-01-04 12:40 7470前言:你写过用例模型 ... -
如何提高代码质量(管理篇):代码复查
2010-02-22 12:09 9310也许你是一位项目经理,也许你是一位项目骨干成员,或者开发小组长 ... -
一堂如何提高代码质量的培训课(3)
2010-01-07 13:37 26463)职责驱动设计和领域 ... -
一堂如何提高代码质量的培训课(2)
2010-01-07 13:32 23573.可变更性 前面我提到了,软件的变更性是所有软件理论的 ... -
一堂如何提高代码质量的培训课
2010-01-07 13:02 5737今天这堂培训课讲什么 ... -
谈谈分析模型的那些事儿 之 职责驱动设计
2009-10-16 11:14 3880前面讲了为什么我们要 ... -
谈谈分析模型的那些事儿 之 开始分析
2009-10-16 11:08 3960——对分析模型的一点 ... -
谈谈领域模型的那些事儿 之 注意什么
2009-10-13 01:35 6364前面我们讲了如何从业 ... -
谈谈用例模型的那些事儿 之 注意什么
2009-10-13 00:13 4460前面我们讲了如何建立用例模型,那么建立用例模型应当注意什么呢? ... -
谈谈用例模型的那些事儿 之 用例图
2009-10-12 21:50 5985——对用例模型及其应 ... -
谈谈软件开发的那些事儿 之 解决之道
2009-10-12 21:25 3445前面提出了软件开发的 ... -
谈谈软件开发的那些事儿 之 软件开发的轮回
2009-10-12 21:18 3749——对软件分析设计的一次深刻反思与探讨 前言: ... -
使用软件开发平台的一点儿建议(续)
2008-11-06 10:23 23462. 复用性 (上接)在软件开发过程中,其实很多要实现的功 ... -
设计模式GRASP和GoF是怎样解决耦合的问题
2007-05-14 09:34 5766最近网友Uranus问我了 ... -
一个对象撕心裂肺的怒吼:谁来创建我! GRAPS(4)创建者模式
2007-01-30 14:58 5577当我们分析清楚客户需求设计出用例模型以后,当我们分析清楚客 ... -
(原创)一个优秀软件开发人员的必修课:GRASP(3)高内聚
2007-01-23 14:26 5411在上一章《(原创)一 ... -
(原创)一个优秀软件开发人员的必修课:GRASP(2)低耦合
2007-01-22 14:51 8738我偶然在google或yahoo这样的搜索引擎搜索GRASP发 ... -
(原创)一个优秀软件开发人员的必修课:GRASP软件开发模式浅析
2007-01-19 14:11 14105你是一个优秀软件开发人员吗?你知道GRASP吗?GRASP ...
相关推荐
终于到了该说说领域驱动设计的时候了。我们在这场关于代码质量的讨论中,从代码可读性开始,讨论了代码复用性、设计模式,然后探讨了职责驱动设计。代码可读性是对代码质量最基本的要求,可惜我们仍有做得不够的...
【提高代码质量】是软件开发领域中至关重要的议题。代码质量不仅影响软件的稳定性和可靠性,还直接影响到项目的维护成本和团队的效率。本篇主要探讨如何提升代码的可读性、可维护性和可变更性这三个关键因素。 首先...
在第八届全国高校嵌入式系统教学研讨会上,各高校专家和教师们聚集一堂,共同探讨了如何在教育环境中更有效地传授这门重要的技术。本次研讨会的PPT资料为我们提供了丰富的教学理念、实践经验和未来趋势。 嵌入式...
内容概要:0欧姆电阻在电路设计中有多种重要作用。它不仅可以在PCB上为调试提供便利,还能用于跳线、替代不确定参数的元件以及测量电路的耗电流。此外,在布线困难时可作为应急解决方案。在高频信号环境下,它能充当电感或电容,有助于解决EMC问题。对于地线处理,0欧姆电阻可用于实现单点接地,避免模拟地和数字地直接大面积相连带来的互相干扰问题。在跨接电流回路方面,它可以提供较短的回流路径,减少干扰。同时,0欧姆电阻还适用于配置电路,防止用户误操作跳线或拨码开关,并且在布线、调试、测试、温度补偿等方面有着广泛应用,尤其在EMC对策中表现突出。; 适合人群:电子工程师、硬件设计师以及对电路设计感兴趣的爱好者。; 使用场景及目标:①在PCB设计阶段,利用0欧姆电阻进行灵活的电路调试与优化;②解决高频信号下的EMC问题,确保电路稳定性和抗干扰能力;③实现单点接地,避免不同地线间的相互干扰;④提高电路的可维护性和可靠性,降低生产成本。; 阅读建议:本文详细介绍了0欧姆电阻在电路设计中的多种应用场景,读者应结合具体项目需求来理解和运用这些知识,特别是在面对复杂的电路布局和电磁兼容性问题时,要充分考虑0欧姆电阻的独特优势。
mysql安装教程 一个基于SpringBoot+Mybatis+Mysql+Html实现的页面登录案例.
在探索智慧旅游的新纪元中,一个集科技、创新与服务于一体的整体解决方案正悄然改变着我们的旅行方式。智慧旅游,作为智慧城市的重要分支,旨在通过新一代信息技术,如云计算、大数据、物联网等,为游客、旅游企业及政府部门提供无缝对接、高效互动的旅游体验与管理模式。这一方案不仅重新定义了旅游行业的服务标准,更开启了旅游业数字化转型的新篇章。 智慧旅游的核心在于“以人为本”,它不仅仅关注技术的革新,更注重游客体验的提升。从游前的行程规划、信息查询,到游中的智能导航、个性化导览,再到游后的心情分享、服务评价,智慧旅游通过构建“一云多屏”的服务平台,让游客在旅游的全过程中都能享受到便捷、个性化的服务。例如,游客可以通过手机APP轻松定制专属行程,利用智能语音导览深入了解景点背后的故事,甚至通过三维GIS地图实现虚拟漫游,提前感受目的地的魅力。这些创新服务不仅增强了游客的参与感和满意度,也让旅游变得更加智能化、趣味化。 此外,智慧旅游还为旅游企业和政府部门带来了前所未有的管理变革。通过大数据分析,旅游企业能够精准把握市场动态,实现旅游产品的精准营销和个性化推荐,从而提升市场竞争力。而政府部门则能利用智慧旅游平台实现对旅游资源的科学规划和精细管理,提高监管效率和质量。例如,通过实时监控和数据分析,政府可以迅速应对旅游高峰期的客流压力,有效预防景区超载,保障游客安全。同时,智慧旅游还促进了跨行业、跨部门的数据共享与协同合作,为旅游业的可持续发展奠定了坚实基础。总之,智慧旅游以其独特的魅力和无限潜力,正引领着旅游业迈向一个更加智慧、便捷、高效的新时代。
内容概要:本文详细介绍了如何通过PLC程序实现模拟量滤波防抖,确保电流、电压和热电阻等信号的准确采集。核心算法采用掐头去尾平均法,即去掉一组数据中的最大值和最小值后取剩余数据的平均值,以消除因环境干扰导致的异常值。文中提供了详细的代码实现步骤,包括数据结构定义、主程序逻辑、间接寻址方法以及参数配置。此外,还讨论了如何通过死区判断和上升率限制进一步优化滤波效果,提高系统的稳定性和响应速度。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是熟悉PLC编程和模拟量信号处理的专业人士。 使用场景及目标:适用于需要高精度模拟量信号采集的工业控制系统,如电力、化工、制造业等领域。主要目标是提升数据采集的准确性和稳定性,减少外部干扰带来的误差。 其他说明:文中提供的代码示例基于西门子S7-1200/1500系列PLC,但相关原理和方法同样适用于其他品牌的PLC。建议在实际应用中根据具体情况调整参数设置,以达到最佳效果。
内容概要:本文详细介绍了大模型的发展现状与未来趋势,尤其聚焦于DeepSeek这一创新应用。文章首先回顾了人工智能的定义、分类及其发展历程,指出从摩尔定律到知识密度提升的转变,强调了大模型知识密度的重要性。随后,文章深入探讨了DeepSeek的发展路径及其核心价值,包括其推理模型、思维链技术的应用及局限性。此外,文章展示了DeepSeek在多个行业的应用场景,如智能客服、医疗、金融等,并分析了DeepSeek如何赋能个人发展,具体体现在公文写作、文档处理、知识搜索、论文写作等方面。最后,文章展望了大模型的发展趋势,如通用大模型与垂域大模型的协同发展,以及本地部署小模型成为主流应用渠道的趋势。 适合人群:对人工智能和大模型技术感兴趣的从业者、研究人员及希望利用DeepSeek提升工作效率的个人用户。 使用场景及目标:①了解大模型技术的最新进展和发展趋势;②掌握DeepSeek在不同领域的具体应用场景和操作方法;③学习如何通过DeepSeek提升个人在公文写作、文档处理、知识搜索、论文写作等方面的工作效率;④探索大模型在特定行业的应用潜力,如医疗、金融等领域。 其他说明:本文不仅提供了理论知识,还结合实际案例,详细介绍了DeepSeek在各个场景下的应用方式,帮助读者更好地理解和应用大模型技术。同时,文章也指出了当前大模型技术面临的挑战,如模型的局限性和数据安全问题,鼓励读者关注技术的持续改进和发展。
内容概要:本文详细比较了四种基于最小二乘支持向量机(LSSVM)的短期电力负荷预测算法:原始LSSVM、SSA-LSSVM、VMD-LSSVM以及VMD-SSA-LSSVM。通过对这些算法的具体实现和性能评估,展示了每种方法的优势和局限性。实验结果显示,随着算法复杂度的增加,预测精度显著提高,特别是VMD-SSA-LSSVM在RMSE和MAPE等评价指标上表现出色,达到了接近真实值的预测效果。然而,这也伴随着计算成本的大幅上升。 适合人群:从事电力系统调度、数据分析、机器学习领域的研究人员和技术人员。 使用场景及目标:适用于需要进行短期电力负荷预测的研究项目或实际应用,旨在提高预测准确性,减少因天气变化、节假日等因素带来的不确定性影响。 其他说明:文中提供了详细的Python代码片段,帮助读者理解和复现相关算法。同时提醒,在选择模型时需综合考虑预测精度与计算效率之间的平衡。
内容概要:本文详细介绍了一种基于Python和Django框架构建的电影推荐系统。该系统不仅涵盖了用户端的基本功能(如登录、搜索、浏览、评论、评分、收藏),还包括管理端的增删改查操作。后端使用Python和Django框架,结合MySQL数据库,前端采用HTML、CSS和JavaScript实现交互界面。推荐算法方面,利用机器学习和深度学习技术,特别是协同过滤和内容过滤相结合的方式,确保推荐结果的多样性和精准性。此外,文中还讨论了一些常见的技术挑战及其解决方案,如用户冷启动问题、前端交互效果优化、数据库配置错误等。 适合人群:具有一定编程经验的Web开发者和技术爱好者,尤其是对Django框架、机器学习和深度学习感兴趣的读者。 使用场景及目标:适用于希望深入了解并实现一个完整的电影推荐系统的个人或团队。主要目标是掌握如何整合前后端技术,运用机器学习和深度学习算法提升用户体验。 其他说明:文中提供了大量代码片段和实践经验,帮助读者更好地理解和实施各个技术细节。同时强调了系统优化的重要性,如通过Redis缓存提高查询效率,使用AJAX实现无缝加载等。
内容概要:本文探讨了基于MATLAB平台的V2G(车辆到电网)光储充一体化微网多目标优化调度策略。该策略旨在通过建立光伏微网中以经济性和并网负荷波动率为双目标的蓄电池和V2G协同调度模型,利用粒子群优化(PSO)算法求解模型。文中详细介绍了模型搭建、核心算法实现、运行模式对比以及算例分析。结果显示,V2G模式能够显著提高系统的经济性和稳定性,减少蓄电池的需求量,优化三方(电网、微网调度中心、电动汽车用户)的利益。 适合人群:从事电力系统优化、智能电网研究的专业人士,尤其是对MATLAB编程有一定基础的研究人员和技术人员。 使用场景及目标:适用于需要优化光储充一体化微网调度策略的研究机构和企业。目标是在保证系统经济运行的同时,稳定并网负荷,减少波动,从而提升整体性能。 其他说明:代码注释详尽,包含并行计算框架、电池寿命模型和可视化模块等多个亮点。通过实际案例验证,证明了V2G模式的有效性。
内容概要:本文详细介绍了三菱FX3U五轴钻孔机的PLC程序和威纶通触摸屏配置,涵盖梯形图编程、IO分配表、参数设置、自动补偿机制以及异常处理等方面。文章通过具体的代码实例展示了如何实现加工循环、参数动态调整、安全防护等功能,并分享了调试过程中遇到的问题及解决方案。此外,还提供了完整的工程文件,便于读者快速理解和应用。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是对三菱PLC和威纶通触摸屏有一定了解的人群。 使用场景及目标:帮助读者掌握五轴钻孔机的控制系统设计方法,提高编程效率和设备稳定性,适用于类似机床控制系统的开发和维护。 其他说明:文中提到的许多技巧和注意事项来源于作者的实际工作经验,对于初学者来说非常有价值。同时,提供的完整工程文件可以作为参考模板,节省开发时间和成本。
matlab开发相关资源
a383d-main.zip
智慧小区解决方案.pptx
Seafile 基于 Qt 的 GUI 客户端
内容概要:本文详细介绍了无人驾驶车辆在局部路径规划中的两种经典算法——Astar和RRT的Matlab实现及其优化。首先,文章解释了Astar算法的核心思想,即通过启发函数进行路径搜索,并针对U型障碍等问题提出了双向搜索策略和动态权重调节。接着,文章探讨了RRT算法的特点,如随机生长特性和路径平滑处理,解决了路径过于曲折的问题。此外,还提出了一种混合算法HRA*,通过改进OPEN集的维护方式,提高了算法效率。最后,通过对不同场景的仿真测试,展示了两种算法在复杂环境中的性能差异,并提供了详细的调参经验和优化建议。 适合人群:对无人驾驶技术和路径规划感兴趣的科研人员、工程师以及有一定编程基础的学习者。 使用场景及目标:适用于研究无人驾驶车辆在复杂环境中的路径规划问题,帮助研究人员理解和优化Astar和RRT算法,提高路径规划的效率和准确性。 其他说明:文中附有大量Matlab代码片段和仿真结果图表,便于读者理解和复现实验。同时,提供了关于栅格地图分辨率、车辆动力学参数等方面的实用建议,有助于实际系统的部署和优化。
选择
内容概要:本文详细介绍了西门子200Smart PLC与维纶触摸屏在某疫苗车间控制系统的具体应用,涵盖配液、发酵、纯化及CIP清洗四个主要工艺环节。文中不仅展示了具体的编程代码和技术细节,还分享了许多实战经验和调试技巧。例如,在配液罐中,通过模拟量处理确保温度和液位的精确控制;发酵罐部分,着重讨论了PID参数整定和USS通讯控制变频器的方法;纯化过程中,强调了双PID串级控制的应用;CIP清洗环节,则涉及复杂的定时器逻辑和阀门联锁机制。此外,文章还提到了一些常见的陷阱及其解决方案,如通讯干扰、状态机切换等问题。 适合人群:具有一定PLC编程基础的技术人员,尤其是从事工业自动化领域的工程师。 使用场景及目标:适用于需要深入了解PLC与触摸屏集成控制系统的工程师,帮助他们在实际项目中更好地理解和应用相关技术和方法,提高系统的稳定性和可靠性。 其他说明:文章提供了大量实战经验和代码片段,有助于读者快速掌握关键技术点,并避免常见错误。同时,文中提到的一些优化措施和调试技巧对提升系统性能非常有帮助。
Prosemirror 是一个基于 ContentEditable 的所见即所得 HTML 编辑器,功能强大,支持协作编辑和自定义文档模式Prosemirror 库由多个单独的模块