内 容 简 介领域建模已被业界普遍认为是软件设计成败的关键。通过领域建模,软件开发人员能够展示丰富的功能并将这些功能实现为真正满足用户需要的软件。尽管领域建模非常重要,但市面上介绍如何将有效的领域建模结合到软件开发过程中的著作却非常少。 本书就是为此目的而编写的。它向读者系统地讲述了领域驱动设计的方法,介绍了大量优秀的设计示例、技术经验以及用于处理复杂领域软件工程的基本原则。本书做到了设计和开发实践相结合,在介绍领域驱动设计的同时,还提供了大量的Java示例。 通过本书,读者将获得对领域驱动设计的总体认识,了解领域驱动设计中涉及的关键原则和术语。 面向对象的开发人员、系统分析师以及设计师在深入思考领域问题时,能够从本书中获得一定的指导,从而建立丰富而有用的领域模型,并将这些模型转化为高质量和持久的软件实现。
前言 从领先的软件设计人员开始将领域建模及设计视为关键性课题到现在至少已经有20年的时间了,然而令人惊讶的是,几乎没有相关的文献来告诉大家应该做什么和如何做。尽管领域建模和设计并没有被明确地形式化,然而在对象领域中出现了一种潜在的哲学体系,它就是我所说的领域驱动设计(domain-driven design)。 我花费10年时间开发了几个商业和技术领域的复杂系统。在工作过程中,我尝试了几种已经出现在面向对象开发前沿领域的设计与开发程序。这些项目中有一些非常成功,也有少数几个最终失败。成功项目的共同特征是在迭代的设计中不断地完善领域模型并将它作为项目的骨干结构的一部分。 本书提供了进行设计决策的框架和讨论领域设计时使用的技术,集中了被广泛接受的优秀实践,这些案例都是在我自己的领域与工作中的经验积累。需要面对复杂领域的软件开发团队可以使用这个框架来系统地进行领域驱动设计。 比较3个项目 在我的记忆中,有3个项目能够作为说明动态领域建模设计如何影响开发结果的生动示例。尽管这3个项目都交付了实用的软件,然而只有一个达到了优秀的目标,并且生成了能够根据组织不断发展的要求进行持续完善的复杂软件。 我注意到一个非常迅速地提交了简单实用的基于Web的贸易系统的项目。开发人员们任凭自己的感觉进行开发,但这种态度并没有对他们的工作造成阻碍,因为一个简单软件的编写并不需要注意设计问题。初始成功的结果是,对于未来继续开发的要求极高。这时我被要求进入第2版本的开发工作。仔细地研究了这个项目后,我发现他们缺少一个领域模型,甚至连项目通用的语言都没有,整个设计处于无结构状态。项目的领导者不同意我的论断,于是我拒绝了这个工作。一年后,这个开发团队陷入困境,无法交付第2个版本。尽管他们对技术的使用方式并无什么错误,从业务逻辑来看,我们还是应该克服这种情况。他们的第1个版本过早地固化导致了高额的维护代价。 处理这种高度复杂的问题要求对领域逻辑的设计采用更加认真的方法。在我事业的早期,非常幸运地能够完成一项格外重视领域设计的项目。该项目的复杂性不小于前面提到的第一个任务,也同样是一开始向贸易商提交了一个简单的应用软件,适度地完成初始工作。但是这次情况有所不同,初始交付的版本不断地加速开发。每一次迭代都会对前一个版本功能的整合与细化提出令人兴奋的新意见。开发团队能够灵活地进行扩展以反馈贸易商的要求。这种向上的良好发展轨迹直接归功于一个明确的领域模型,迭代地改进并快速地编码。随着团队对领域更进一步的洞察,模型也随之进一步深化。开发人员之间甚至开发人员与领域专家之间的交流得以改善,项目的设计也不像以前那样带来艰巨的维护任务,而变得易于修改和扩展了。 遗憾的是,项目并不会仅仅因为认真进行建模而进入一个良性循环。我过去接触过一个项目,开始时基于领域模型是要建立一个全球企业系统,但是经过几年屡屡受挫,不得不降低目标而落入俗套。这个团队有良好的工具与对业务的深入理解,并且对于建模也格外重视。然而拙劣的开发角色划分使得模型与实现相互分离,因此设计并没有反映出分析的深度。在任何情况下,详细的业务对象设计并不是保证它们在复杂精细项目中完美结合的充分条件。再三的迭代并不能够提高编码质量,因为开发人员之间技术水平不均衡,而他们又不了解面向实际的运行软件而建立基于模型的对象的技术与其本身的风格。时间一点点过去,开发工作陷入复杂的泥潭,团队也丧失了对系统的整体把握。经过几年的工作,该项目并没有生产出有用的软件,该团队却不得不放弃其初始时建模的目标。 复杂度的难题 很多原因会导致一个项目偏离正确轨道:官僚主义、不明确的目标、资源的匮乏以及其他诸多因素。但是设计能够在很大程度上决定软件的复杂度。当复杂度变得难以控制时,开发人员便不再能够很好地理解软件,从而也不能够方便和安全地对它进行改变与扩展。另一方面,一个优秀的设计会为开发这些复杂特性带来机会。 一些设计因素是技术上的,在网络、数据库和其他软件技术方面的设计已经有了很多研究,这些问题的解决方法也有许多书籍专门论述。开发人员们不断提升自己的技能并紧跟着每一次的技术进步。 然而许多应用程序最大的复杂性不在技术方面,而是在领域本身,用户的活动或业务方面。如果在设计中没有处理好领域复杂性,那么基础设施技术再好也不管用。一个成功的设计必须系统地处理软件的这个核心方面。 本书的前提有两个: ● 对于多数软件项目,主要的焦点应该在领域及领域逻辑方面。 ● 复杂的领域设计应该基于一个模型来进行。 领域驱动的设计既是一种思考的方式也是一系列的要优先考虑的事情,目的在于加速处理复杂领域的软件项目。为了达到这个目标,本书提供了大量的设计实践、技巧和原则。 设计与开发过程 设计方面的书籍与过程方面的书籍很少相互提及,其中每个主题本身就是一个很复杂的问题。本书是一本关于设计方面的著作,但是我认为设计与过程是不可分割的。设计理念必须得以成功实现,否则它们将仅仅止步于学术讨论。 在人们学习设计技术时,常常会为各种可能性感到兴奋不已。接着他们会遇到实际项目的杂乱现状,他们无法将新的设计思路应用在必须使用的技术上。或者是他们不知道何时应该抛开设计方面的局限,何时又应该严格地遵循设计,寻找一个正确的解决方案。开发人员们相互讨论抽象的应用程序设计原则,但更为实际的是讨论现实的项目如何完成。因此,尽管这是一本设计书籍,在需要时我仍然会涉及到过程领域的知识。这样做更有助于在合适的上下文中讨论设计原则。 本书并不局限于某一特定的方法学,然而它是面向新的“敏捷开发过程”系列的。它假设项目实践中有几个约定俗成的惯例。下面两个惯例是本书所采用方法的先决条件。 ● 开发工作是迭代的。迭代开发过程已经被提倡并实践了几十年,它是敏捷开发方法的基础。关于敏捷开发和极限编程(或XP)的文献有很多讨论,如Surviving Object-Oriented Projects(Cockburn 1998)和Extreme Programming Explained(Beck 1999)。 ● 开发人员与领域专家之间关系密切。领域驱动设计需要大量深入的领域知识以及对于其中关键概念的关注。这是一项了解领域与了解如何建立软件的人们之间的合作。因为开发工作是迭代进行的,因此这种合作要始终贯穿于项目的生命周期。 Kent Beck、Ward Cunningham和其他人认为(参见Extreme Programming Explained [Beck 2000])最后的编程实现是敏捷开发过程中最重要的,也是我最经常需要处理的工作。在本书中,为了更加具体地阐述,我使用XP作为设计与过程交互讨论的基础。举例所用的原则可以方便地适用于其他的敏捷开发过程。 最近几年,人们开始质疑精细开发方法学,认为它们产生了无用的、静态的文档以及强制性的前置计划和设计。相反,敏捷开发过程,例如XP,则强调对变化和不确定性的应对。 极限编程承认设计决策的重要性,但是它极力反对前置设计。它花费大量精力进行交流和提高项目的迅速转向能力。有了这样的反应能力,开发人员可以在项目的每个阶段使用“可运行的最简单事物”,然后进行持续重构,进行许多小的设计改善,最后完成符合用户需求的设计。 这种极保守行为对于一些过度的设计狂热者是一种非常必要的解药。那些使得项目举步维艰的大量文档并没有什么价值。由于开发团队害怕所做的设计不完善,使这些项目深受“分析瘫痪”之苦。这种情况必须要有所改变。 遗憾的是,这些开发过程的观念常常被曲解。每个人对于“简单”都有不同的定义。持续的重构是一系列小型的再设计;那些缺乏一致的设计原则的开发人员将编写出难以理解或修改的代码——而这恰恰与敏捷背道而驰。尽管由于对各种无法预料的需求的担心常常导致过度工程(overengineering),然而试图避免过度工程却可能导致另一种担心:不敢进行任何深入的设计思考。 实际上,XP最适合具有敏锐设计感知的开发人员。XP过程假设您能够通过重构完善一个设计,并且您会频繁而迅速地进行重构。但是前面的设计选择会使得重构本身变得更容易或更困难。XP过程尝试增加团队交流,然而不同的模型和设计选择会使交流变得明确或混淆。 本书将设计与开发实践结合在一起,并且举例说明领域驱动设计与敏捷开发如何相互补充。在敏捷开发过程环境中精细的领域建模方法能够加速开发。与领域开发过程之间的相互关系使得这种方法比其他凭空考虑的“纯”设计方法更加实际。 本书结构 本书分为4个主要部分: 第Ⅰ部分:让领域模型发挥作用。介绍了领域驱动开发的基本目标;这些目标推动后面几章的实践。由于软件开发有很多方法,第1章定义了一些术语并说明了对使用领域模型驱动交流和设计的总的看法。 第Ⅱ部分:模型驱动设计的构建块。将面向对象领域建模实践的核心浓缩为一些基本的构建块。这部分着力于在模型与实际之间搭建桥梁并运行软件。这些标准模式的共享使得设计得以有序进行,团队成员更加容易了解彼此的工作。使用标准模式更有助于使用通用语言的术语,这样所有的团队成员便可以使用它们来讨论模型和设计决策。 但是本部分主要关注的是保持模型与实现之间相互协调以及提高效率的决策种类。这种协调需要注意到单个元素的细节。在这种小规模上的工作为开发人员采用第Ⅲ和第Ⅳ部分的建模方法提供了稳定的平台。 第Ⅲ部分:面向更深层理解的重构。超越了构建块范围而着力于将它们装配成可见结果的实际模型。本部分并没有直接介绍深奥的设计原则,而是着重讨论发现过程。有价值的模型通常不会立刻产生,它们需要对领域进行深入理解。基于幼稚的模型实现初始的设计,然后一次又一次地改变它。团队每次增加对领域的理解后,模型将被改变以反映进一步获得的知识,代码也随之重构来反映更深层次的模型,使其更接近可用的应用程序。因此,偶尔的困难可能正是突破到一个更加深入的模型,获得更完美设计的机会。 探索与生俱来就是可扩展的,然而它并不是随机的。第Ⅲ部分主要研究能够在探索过程中指导决策的原则和帮助引导研究的技术。 第Ⅳ部分:战略性设计。处理复杂系统、较大型组织以及外部系统与老式系统交互中发生的各种情况。这部分提出了作为整体应用于系统的3个原则:上下文、精炼和大比例结构。战略性设计决策由团队制定,它们使得第Ⅰ部分的目标大体实现,可能是适合企业范围网络的大型系统或应用程序。 本书自始至终都使用来自实际项目的真实例子进行论述,而不是采用过于简单的“玩具”问题。 补充的材料可以通过站点找到,其中包括附加的示例代码和相关讨论。 本书读者对象 本书主要针对面向对象的软件开发人员。一个软件项目团队的大多数成员都能够从本书的某些部分中得到收获。对于现在设计一个项目并尝试着做一些工作的人们,以及对于这些项目有很多经验的人们来说,本书都有很重要的意义。 从本书中会得到一些面向对象建模的知识,例如UML图和Java代码,因此阅读这些语言的基本能力是很重要的,但是并不需要掌握它们的细节问题。极限编程的知识能够增加开发过程讨论的角度[n1],但是其内容应该能被不具备这些知识的人们所理解。 对于中级软件开发人员—— 那些已经了解一些面向对象设计并可能已经阅读过一两本软件设计书籍的读者——本书将介绍在一个软件项目中对象建模如何适应现实生活。本书将帮助中级开发人员学会在实际问题中采用精妙的建模和设计技巧。 高级或专门的软件开发人员会对书中涉及领域的全面框架感兴趣。系统的设计方法会帮助项目领导者带领团队沿着正确的方向工作。本书始终使用的相关术语对于高级开发人员与同伴交流也很有帮助。 本书采用叙述形式,可以从头到尾也可以从任何一章开始阅读。具有不同背景的读者会希望采用不同的方法阅读本书,但是我建议所有的读者从第Ⅰ部分的介绍以及第1章开始。除了这些,核心内容大部分集中在第2章、第3章、第9章和第14章。已经掌握了一些主题的读者可以通过阅读标题和粗体字来得到内容的要点。已有基础的读者可能希望跳过第Ⅰ部分和第Ⅱ部分,第Ⅲ和第Ⅳ部分的内容可能会让他们更感兴趣。 除了这些主要的读者群外,相关的技术项目经理及分析人员也可通过阅读此书而受益。分析人员运用模型与设计的联系,获得在敏捷项目环境中更有效的成果。他们也可使用战略性设计的原则去更好地专注和组织他们的工作。 项目经理关注如何使一个团队更有效率以及如何设计对于业务专家和用户更有意义的软件。因为战略性设计决策与团队结构和工作方式有关,这些设计决策必定会涉及到项目领导者并对项目的发展产生重要的影响。 领域驱动开发团队 尽管一个理解领域驱动设计的单独开发人员能够获得有价值的设计技术和观点,然而当团队团结在一起使用领域驱动设计方法并在项目中心会谈上讨论领域模型时会得到最大的收获。通过这样做,团队成员能够进行比较多的交流,并保持这种交流与软件相关联。他们会依据模型逐步产生明晰的实现产品,得到应用程序开发的方法。他们将共享不同团队的设计工作如何相互关联的示意图,并系统地将注意力聚焦于对于团体最有价值和有特色的特征上。 当大多数的软件项目开始在僵化中死去时,领域驱动设计是一个困难的技术挑战,但它可以带来巨大的、开放的机会。