Fifteen. Distillation
—James Clerk Maxwell, A Treatise on Electricity and Magnetism, 1873
These four equations, along with the definitions of their terms and the body of mathematics they rest on, express the entirety of classical nineteenth-century electromagnetism.
上面这 4 个方程式,再加上其中的术语定义,以及它们所依赖的数学体系,表达了 19 世纪经典电磁学的全部内涵。
How do you focus on your central problem and keep from drowning in a sea of side issues? A LAYERED ARCHITECTURE separates domain concepts from the technical logic that makes a computer system run, but in a large system, even the isolated domain may be unmanageably complex.
如何才能专注于核心问题而不被大量的次要问题淹没呢?LAYERED ARCHITECTURE 可以把领域概念从技术逻辑中(技术逻辑确保了计算机系统能够运转)分离出来,但在大型系统中,即使领域被分离出来,它的复杂性也可能仍然难以管理。
Distillation is the process of separating the components of a mixture to extract the essence in a form that makes it more valuable and useful. A model is a distillation of knowledge. With every refactoring to deeper insight, we abstract some crucial aspect of domain knowledge and priorities. Now, stepping back for a strategic view, this chapter looks at ways to distinguish broad swaths of the model and distill the domain model as a whole.
精炼是把一堆混杂在一起的组件分开的过程,以便通过某种形式从中提取出最重要的内容,而这种形式将使它更有价值,也更有用。模型就是知识的精炼。通过每次重构所得到的更深层的理解,我们得以把关键的领域知识和优先级提取出来。现在,让我们回过头来从战略角度看一下精炼,本章将介绍对模型进行粗线条划分的各种方式,并把领域模型作为一个整体进行精炼。
As with many chemical distillations, the separated by-products are themselves made more valuable by the distillation process (as GENERIC SUBDOMAINS and COHERENT MECHANISMS), but the effort is motivated by the desire to extract that one particularly valuable part, the part that distinguishes our software and makes it worth building: the “CORE DOMAIN.”
像很多化学蒸馏过程一样,精炼过程所分离出来的副产品(如 GENERIC SUBDOMAIN 和 COHERENT MECHANISM)本身也很有价值,但精炼的主要动机是把最有价值的那部分提取出来,正是这个部分使我们的软件区别于其他软件并让整个软件的构建物有所值,这个部分就是 CORE DOMAIN。
Strategic distillation of a domain model does all of the following:
领域模型的战略精炼包括以下部分:
- Aids all team members in grasping the overall design of the system and how it fits together
- Facilitates communication by identifying a core model of manageable size to enter the UBIQUITOUS LANGUAGE
- Guides refactoring
- Focuses work on areas of the model with the most value
- Guides outsourcing, use of off-the-shelf components, and decisions about assignments
- 帮助所有团队成员掌握系统的总体设计以及各部分如何协调工作;
- 找到一个具有适度规模的核心模型并把它添加到通用语言中,从而促进沟通;
- 指导重构;
- 专注于模型中最有价值的那部分;
- 指导外包、现成组件的使用以及任务委派。
This chapter lays out a systematic approach to strategic distillation of the CORE DOMAIN, and it explains how to effectively share a view of it within the team and provides the language to talk about what we are doing.
本章将展示对 CORE DOMAIN 进行战略精炼的系统性方法,解释如何在团队中有效地统一认识,并提供一种用于讨论工作的语言。
A navigation map for strategic distillation
Like a gardener pruning a tree, clearing the way for the growth of the main branches, we are going to apply a suite of techniques to hew away distractions in the model and focus our attention on the part that matters most. . . .
像那些园丁为了让树干快速生长而修剪树苗一样,我们将使用一整套技术把模型中那些细枝末节砍掉,从而把注意力集中在最重要的部分上……
In designing a large system, there are so many contributing components, all complicated and all absolutely necessary to success, that the essence of the domain model, the real business asset, can be obscured and neglected.
在设计大型系统时,有非常多的组成部分——它们都很复杂而且对开发的成功也至关重要,但这导致真正的业务资产——领域模型最为精华的部分——被掩盖和忽略了。
A system that is hard to understand is hard to change. The effect of a change is hard to foresee. A developer who wanders outside his or her own area of familiarity gets lost. (This is particularly true when bringing new people into a team, but even an established member of the team will struggle unless code is very expressive and organized.) This forces people to specialize. When developers confine their work to specific modules, it further reduces knowledge transfer. With the compartmentalization of work, smooth integration of the system suffers, and flexibility in assigning work is lost. Duplication crops up when a developer does not realize that a behavior already exists elsewhere, and so the system becomes even more complex.
难以理解的系统修改起来会很困难,而且修改的结果也难以预料。开发人员如果脱离自己熟悉的领域,也会迷失方向(当团队中有新人加入时尤其如此,但老成员也面临同样的状况,除非代码表达得非常清楚并且组织有序)。这样一来就必须分门别类地为人们安排任务。当开发人员把他们的工作限定到具体的模块时,知识的传递就更少了。这种工作上的划分导致系统很难平滑地集成,也无法灵活地分配工作。如果开发人员没有了解到某项功能已经被实现了,那么就会出现重复,这样系统会变得更加复杂。
Those are some of the consequences of any design that is hard to understand, but there is another, equally serious risk from losing the big picture of the domain:
以上只是难以理解的设计所导致的一部分后果。当失去了领域的整体视图时,还存在另一个同样严重的风险。
The harsh reality is that not all parts of the design are going to be equally refined. Priorities must be set. To make the domain model an asset, the model’s critical core has to be sleek and fully leveraged to create application functionality. But scarce, highly skilled developers tend to gravitate to technical infrastructure or neatly definable domain problems that can be understood without specialized domain knowledge.
一个严峻的现实是我们不可能对所有设计部分进行同等的精化,而是必须分出优先级。为了使领域模型成为有价值的资产,必须整齐地梳理出模型的真正核心,并完全根据这个核心来创建应用程序的功能。但本来就稀缺的高水平开发人员往往会把工作重点放在技术基础设施上,或者只是去解决那些不需要专门领域知识就能理解的领域问题(这些问题都已经有了很好的定义)。
Such parts of the system seem interesting to computer scientists, and are perceived to build transferable professional skills and provide better resume material. The specialized core, that part of the model that really differentiates the application and makes it a business asset, typically ends up being put together by less skilled developers who work with DBAs to create a data schema and then code feature-by-feature without drawing on any conceptual power in the model at all.
计算机科学家对系统的这些部分更感兴趣,他们认为通过这些工作可以让自己具备一些在其他地方也能派上用场的专业技能,同时也丰富了个人简历。而真正体现应用程序价值并且使之成为业务资产的领域核心却通常是由那些技术水平稍差的开发人员完成的,他们与 DBA 一起创建数据模式,然后逐个特性编写代码,而根本没有对模型的概念能力加以任何利用。
Poor design or implementation of this part of the software leads to an application that never does compelling things for the users, no matter how well the technical infrastructure works, no matter how nice the supporting features are. This insidious problem can take root when a project lacks a sharp picture of the overall design and the relative significance of the various parts.
如果软件的这个部分实现得很差,那么无论技术基础设施有多好,无论支持功能有多完善,应用程序永远都不会为用户提供真正有吸引力的功能。这个严重问题的根源在于项目没有一个明确的整体设计视图,而且也没有认清各个部分的相对重要性。
One of the most successful projects I’ve joined initially suffered from this syndrome. The goal was to develop a very complex syndicated loan system. Most of the strong talent was happily working on database mapping layers and messaging interfaces while the business model was in the hands of developers new to object technology.
我曾经参与过的最成功的项目中,有一个开始时就受到了这种问题的困扰。这个项目的目标是开发一个非常复杂的联合贷款系统。技术能力最强的开发人员在数据库映射层和消息传递接口这些工作上忙得不亦乐乎,而业务模型则交到了那些不熟悉对象技术的新人手中。
The single exception, an experienced object developer working on a domain problem, devised a way of attaching comments to any of the long-lived domain objects. These comments could be organized so that traders could see the rationale they or others recorded for some past decision. He also built an elegant user interface that gave intuitive access to the flexible features of the comment model.
唯一的例外是有一个领域问题是由一位经验丰富的对象开发人员处理的,他为那些长期存在的领域对象设计了一种添加注释的功能。通过把这些注释组织到一起,交易商能够看到他们或其他人过去所做的一些决策的基本思想。这位开发人员还构建了一个优秀的用户界面,它为用户提供了直观的访问,用户可以利用这个界面来灵活地使用注释模型的各种功能。
These features were useful and well designed. They went into production.
这些特性很有用处,而且设计得很好。它们被合并到最终产品中。
Unfortunately, they were peripheral. This talented developer modeled his interesting, generic way of commenting, implemented it cleanly, and put it into users’ hands. Meanwhile an incompetent developer was turning the mission-critical “loan” module into an incomprehensible tangle that the project very nearly did not recover from.
遗憾的是,它们只是一些次要特性。这位能力超群的开发人员把一种有趣的、通用的注释方法建模出来,并干净利落地实现了它,最后交付到用户手中。同时,另一位能力上不太胜任的开发人员却把关键的“贷款”模块弄得一团糟,项目差一点就因此失败。
The planning process must drive resources to the most crucial points in the model and design. To do that, those points must be identified and understood by everyone during planning and development.
在制定项目规划的时候,必须把资源分配给模型和设计中最关键的部分。要想达到这个目的,在规划和开发期间每个人都必须识别和理解这些关键部分。
Those parts of the model distinctive and central to the purposes of the intended applications make up the CORE DOMAIN. The CORE DOMAIN is where the most value should be added in your system.
这些部分是应用程序的标志性部分,也是目标应用程序的核心诉求,它们构成了 CORE DOMAIN。CORE DOMAIN 是系统中最有价值的部分。
Therefore:
因此:
Boil the model down. Find the CORE DOMAIN and provide a means of easily distinguishing it from the mass of supporting model and code. Bring the most valuable and specialized concepts into sharp relief. Make the CORE small.
对模型进行提炼。找到 CORE DOMAIN 并提供一种易于区分的方法把它与那些起辅助作用的模型和代码分开。最有价值和最专业的概念要轮廓分明。尽量压缩 CORE DOMAIN。
Apply top talent to the CORE DOMAIN, and recruit accordingly. Spend the effort in the CORE to find a deep model and develop a supple design—sufficient to fulfill the vision of the system. Justify investment in any other part by how it supports the distilled CORE.
让最有才能的人来开发 CORE DOMAIN,并据此要求进行相应的招聘。在 CORE DOMAIN 中努力开发能够确保实现系统蓝图的深层模型和柔性设计。仔细判断任何其他部分的投入,看它是否能够支持这个提炼出来的 CORE。
Distilling the CORE DOMAIN is not easy, but it does lead to some easy decisions. You’ll put a lot of effort into making your CORE distinctive, while keeping the rest of the design as generic as is practical. If you need to keep some aspect of your design secret as a competitive advantage, it is the CORE DOMAIN. There is no need to waste effort concealing the rest. And whenever a choice has to be made (due to time limitations) between two desirable refactorings, the one that most affects the CORE DOMAIN should be chosen first.
提炼 CORE DOMAIN 并不容易,但它确实会让一些决策变得容易。你需要投入大量的工作使你的 CORE 鲜明突出,而其他设计部分则只需依照常规做得实用即可。如果某个设计部分需要保密以便保持竞争优势,那么它就是你的 CORE DOMAIN。其他的部分则没有必要隐藏起来。当必须在两个看起来都很有用的重构之间进行抉择时(由于时限的缘故),应该首选对 CORE DOMAIN 影响最大的那个重构。
The patterns in this chapter make the CORE DOMAIN easier to see and use and change.
本章中的模式能够使我们更容易发现、使用和修改 CORE DOMAIN。
We are looking at those parts of the model particular to representing your business domain and solving your business problems.
我们需要关注的是那些能够表示业务领域并解决业务问题的模型部分。
The CORE DOMAIN you choose depends on your point of view. For example, many applications need a generic model of money that could represent various currencies and their exchange rates and conversions. On the other hand, an application to support currency trading might need a more elaborate model of money, which would be considered part of the CORE. Even in such a case, there may be a part of the money model that is very generic. As insight into the domain deepens with experience, the distillation process can continue by separating the generic money concepts and retaining only the specialized aspects of the model in the CORE DOMAIN.
对 CORE DOMAIN 的选择取决于看问题的角度。例如,很多应用程序需要一个通用的货币模型,用来表示各种货币以及它们的汇率和兑换。另一方面,一个用来支持货币交易的应用程序可能需要更精细的货币模型,这个模型有可能就是 CORE 的一部分。即使在这种情况下,货币模型中可能有一部分仍是非常通用的。随着对领域理解的不断加深,精炼过程可以持续进行,这会把通用的货币概念分离出来,而只把模型中那些专有的部分保留在 CORE DOMAIN 中。
In a shipping application, the CORE could be the model of how cargoes are consolidated for shipping, how liability is transferred when containers change hands, or how a particular container is routed on various transports to reach its destination. In investment banking, the CORE could include the models of syndication of assets among assignees and participants.
在运输应用程序中,CORE 可能是以下几方面的模型:货物是如何装船运输的,当集装箱转交时责任是如何转接的,或者特定的集装箱是如何经由不同的运输路线最后到达目的地的。在投资银行中,CORE 可能包括委托人和参与者之间的合资模型。
One application’s CORE DOMAIN is another application’s generic supporting component. Still, throughout one project, and usually throughout one company, a consistent CORE can be defined. Like every other part of the design, the identification of the CORE DOMAIN should evolve through iterations. The importance of a particular set of relationships might not be apparent at first. The objects that seem obviously central at first may turn out to have supporting roles.
一个应用程序的 CORE DOMAIN 在另一个应用程序中可能只是通用的支持组件。尽管如此,仍然可以在一个项目中(而且通常在一个公司中)定义一个一致的 CORE。像其他设计部分一样,人们对 CORE DOMAIN 的认识也会随着迭代而发展。开始时,一些特定关系可能显得不重要。而最初被认为是核心的对象可能逐渐被证明只是起支持作用。
The discussion in the following sections, particularly GENERIC SUBDOMAINS, will give more guidelines for these decisions.
下面几节(特别是 GENERIC SUBDOMAIN 这节)将给出制定这些决策的指导。
The most technically proficient members of project teams seldom have much knowledge of the domain. This limits their usefulness and reinforces the tendency to assign them to supporting components, sustaining a vicious circle in which lack of knowledge keeps them away from the work that would build domain knowledge.
在项目团队中,技术能力最强的人员往往缺乏丰富的领域知识。这限制了他们的作用,并且更倾向于分派他们来开发一些支持组件,从而形成了一个恶性循环——知识的缺乏使他们远离了那些能够学到领域知识的工作。
It is essential to break this cycle by assembling a team matching up a set of strong developers who have a long-term commitment and an interest in becoming repositories of domain knowledge with one or more domain experts who know the business deeply. Domain design is interesting, technically challenging work when approached seriously, and developers can be found who see it this way.
打破这种恶性循环是很重要的,方法是建立一支由开发人员和一位或多位领域专家组成的联合团队,其中开发人员必须能力很强、能够长期稳定地工作并且对学习领域知识非常感兴趣,而领域专家则要掌握深厚的业务知识。如果你认真对待领域设计,那么它就是一项有趣且充满技术挑战的工作。你肯定也会找到持这种观点的开发人员。
It is usually not practical to hire short-term, outside design expertise for the nuts and bolts of creating the CORE DOMAIN, because the team needs to accumulate domain knowledge, and a temporary member is a leak in the bucket. On the other hand, an expert in a teaching/mentoring role can be very valuable by helping the team build its domain design skills and facilitating the use of sophisticated principles that team members probably have not mastered.
从外界聘请一些短期的专业人员来设计 CORE DOMAIN 的关键环节通常是行不通的,因为团队需要积累领域知识,而且短期人员会造成知识流失。相反,充当培训和指导角色的专家可能非常有价值,因为他们帮助团队建立领域设计技巧,并促进团队成员使用尚未掌握的高级设计原则。
For similar reasons, it is unlikely that the CORE DOMAIN can be purchased. Efforts have been made to build industry-specific model frameworks, conspicuous examples being the semiconductor industry consortium SEMATECH’s CIM framework for semiconductor manufacturing automation, and IBM’s “San Francisco” frameworks for a wide range of businesses. Although this is a very enticing idea, so far the results have not been compelling, except perhaps as PUBLISHED LANGUAGES facilitating data interchange (see Chapter 14). The book Domain-Specific Application Frameworks (Fayad and Johnson 2000) gives an overview of the state of this art. As the field advances, more workable frameworks may be available.
出于类似的原因,购买 CORE DOMAIN 也是行不通的。人们已经在建立特定于行业的模型框架方面付出了一些工作,著名的例子就是半导体行业协会 SEMATECH 创立的用于半导体制造自动化的 CIM 框架,以及 IBM 为很多业务开发的 San Francisco 框架。虽然这是一个有吸引力的想法,但除了能够促进数据交换的 PUBLISHED LANGUAGE(参见第 14 章)以外,其他结果并不理想。Domain-Specific Application Frameworks[Fayad and Johnson 2000]一书介绍了这项工作的总体状况。随着这个领域的进步,可能会出现一些更有用的框架。
Even so, there is a more fundamental reason for caution: The greatest value of custom software comes from the total control of the CORE DOMAIN. A well-designed framework may be able to provide high-level abstractions that you can specialize for your use. It may save you from developing the more generic parts and leave you free to concentrate on the CORE. But if it constrains you more than that, then there are three likely possibilities.
除了上述原因之外,还有一个更重要的原因需要引起我们的注意。自主开发的软件的最大价值来自于对 CORE DOMAIN 的完全控制。一个设计良好的框架可能会提供满足你的专门使用需求的高水平抽象,它可以节省开发那些更通用部分的时间,并使你能够专注于 CORE。但是,如果它对你的约束超出了这个限度,可能有以下 3 种原因。
- You are losing an essential software asset. Back off restrictive frameworks in your CORE DOMAIN.
- The area treated by the framework is not as pivotal as you thought. Redraw the boundaries of the CORE DOMAIN to the truly distinctive part of the model.
- You don’t have special needs in your CORE DOMAIN. Consider a lower-risk solution, such as purchasing software to integrate with your applications.
- 你正在失去一项重要的软件资产。此时应该让这些限制性的框架退出你的 CORE DOMAIN。
- 框架所处理的部分并不是你所认为的核心。此时应该重新划定 CORE DOMAIN 的边界,把你的模型中真正的标志性部分识别出来。
- 你的 CORE DOMAIN 并没有特殊的需求。此时应该考虑采用一种风险更低的解决方案,如购买软件并与你的应用程序进行集成。
One way or another, creating distinctive software comes back to a stable team accumulating specialized knowledge and crunching it into a rich model. No shortcuts. No magic bullets.
不管是哪种情况,创建与众不同的软件还是会回到原来的轨道上——需要一支稳定工作的团队,他们不断积累和消化专业知识,并将这些知识转化为一个丰富的模型。没有捷径,也没有魔法。
The various distillation techniques that make up the rest of this chapter can be applied in almost any order, but there is a range in how radically they modify the design.
本章接下来将要介绍各种精炼技术,它们在使用顺序上基本没什么要求,但对设计的改动却大不相同。
A simple DOMAIN VISION STATEMENT communicates the basic concepts and their value with a minimum investment. The HIGHLIGHTED CORE can improve communication and help guide decision making—and still requires little or no modification to the design.
一份简单的 DOMAIN VISION STATEMENT(领域愿景说明)只需很少的投入,它传达了基本概念以及它们的价值。HIGHLIGHTED CORE(突出核心)可以增进沟通,并指导决策制定,这也只需对设计进行很少的改动甚至无需改动。
More aggressive refactoring and repackaging explicitly separate GENERIC SUBDOMAINS, which can then be dealt with individually. COHESIVE MECHANISMS can be encapsulated with versatile, communicative, and supple design. Removing these distractions disentangles the CORE.
更积极的精炼方法是通过重构和重新打包显式地分离出 GENERIC SUBDOMAIN,然后单独进行处理。在使用 COHESIVE MECHANISM 的同时,也要保持设计的通用性、易懂性和柔性,这两个方面可以结合起来。只有除去了这些细枝末节,才能把 CORE 剥离出来。
Repackaging a SEGREGATED CORE makes the CORE directly visible, even in the code, and facilitates future work on the CORE model.
重新打包出一个 SEGREGATED CORE(分离的核心),可以使这个 CORE 清晰可见(即使在代码中也是如此),并且促进将来在 CORE 模型上的工作。
And most ambitious is the ABSTRACT CORE, which expresses the most fundamental concepts and relationships in a pure form (and requires extensive reorganizing and refactoring of the model).
最富雄心的精炼是 ABSTRACT CORE(抽象内核),它用纯粹的形式表示了最基本的概念和关系(因此,需要对模型进行全面的重新组织和重构)。
Each of these techniques requires a successively greater commitment, but a knife gets sharper as its blade is ground finer. Successive distillation of a domain model produces an asset that gives the project speed, agility, and precision of execution.
每种技术都需要我们连续不断地投入越来越多的工作,但刀磨得越薄,就会越锋利。领域模型的连续精炼将为我们创造一项资产,使项目进行得更快、更敏捷、更精确。
To start, we can boil off the least distinctive aspects of the model. GENERIC SUBDOMAINS provide a contrast to the CORE DOMAIN that clarifies the meaning of each. . . .
首先,我们可以把模型中最普通的那些部分分离出去,它们就是 GENERIC SUBDOMAIN(通用子领域)。GENERIC SUBDOMAIN 与 CORE DOMAIN 形成鲜明的对比,使我们可以更清楚地理解它们各自的含义。
Some parts of the model add complexity without capturing or communicating specialized knowledge. Anything extraneous makes the CORE DOMAIN harder to discern and understand. The model clogs up with general principles everyone knows or details that belong to specialties which are not your primary focus but play a supporting role. Yet, however generic, these other elements are essential to the functioning of the system and the full expression of the model.
模型中有些部分除了增加复杂性以外并没有捕捉或传递任何专门的知识。任何外来因素都会使 CORE DOMAIN 愈发的难以分辨和理解。模型中充斥着大量众所周知的一般原则,或者是专门的细节,这些细节并不是我们的主要关注点,而只是起到支持作用。然而,无论它们是多么通用的元素,它们对实现系统功能和充分表达模型都是极为重要的。
There is a part of your model that you would like to take for granted. It is undeniably part of the domain model, but it abstracts concepts that would probably be needed for a great many businesses. For example, a corporate organization chart is needed in some form by businesses as diverse as shipping, banking, or manufacturing. For another example, many applications track receivables, expense ledgers, and other financial matters that could all be handled using a generic accounting model.
模型中有你想当然的部分。不可否认,它们确实是领域模型的一部分,但它们抽象出来的概念是很多业务都需要的。比如,各个行业(如运输业、银行业或制造业)都需要某种形式的企业组织图。再比如,很多应用程序都需要跟踪应收账款、开支分类账和其他财务事项,而这些都可以用一个通用的会计模型来处理。
Often a great deal of effort is spent on peripheral issues in the domain. I personally have witnessed two separate projects that have employed their best developers for weeks in redesigning dates and times with time zones. While such components must work, they are not the conceptual core of the system.
通常,人们投注了大量精力去处理领域的周边问题。我亲眼目睹过两个不同项目都分派了最好的开发人员来重新设计带有时区的日期和时间功能,这些工作耗费了他们数周的时间。虽然这样的组件必须正常工作,但它们并不是系统的概念核心。
Even if such a generic model element is deemed critical, the overall domain model needs to make prominent the most value-adding and special aspects of your system, and needs to be structured to give that part as much power as possible. This is hard to do when the CORE is mixed with all the interrelated factors.
即使这样的通用模型元素确实非常重要,整个领域模型仍然需要把系统中最有价值和最特别的方面突出出来,而且整个模型的组织应该尽可能把重点放在这个部分上。当核心与所有相关的因素混杂在一起时,这一点会更难做到。
Therefore:
因此:
Identify cohesive subdomains that are not the motivation for your project. Factor out generic models of these subdomains and place them in separate MODULES. Leave no trace of your specialties in them.
识别出那些与项目意图无关的内聚子领域。把这些子领域的通用模型提取出来,并放到单独的 MODULE 中。任何专有的东西都不应放在这些模块中。
Once they have been separated, give their continuing development lower priority than the CORE DOMAIN, and avoid assigning your core developers to the tasks (because they will gain little domain knowledge from them). Also consider off-the-shelf solutions or published models for these GENERIC SUBDOMAINS.
把它们分离出来以后,在继续开发的过程中,它们的优先级应低于 CORE DOMAIN 的优先级,并且不要分派核心开发人员来完成这些任务(因为他们很少能够从这些任务中获得领域知识)。此外,还可以考虑为这些 GENERIC SUBDOMAIN 使用现成的解决方案或“公开发布的模型”(PUBLISHED MODEL)。
You may have a few extra options when developing these packages.
当开发这样的软件包时,有以下几种选择。
Option 1: An Off-the-Shelf Solution
选择 1:现成的解决方案
Sometimes you can buy an implementation or use open source code.
有时可以购买一个已实现好的解决方案,或使用开源代码。
Advantages
- Less code to develop.
- Maintenance burden externalized.
- Code is probably more mature, used in multiple places, and therefore more bulletproof and complete than homegrown code.
- 可以减少代码的开发。
- 维护负担转移到了外部。
- 代码已经在很多地方使用过,可能较为成熟,因此比自己开发的代码更可靠和完备。
Disadvantages
- You still have to spend the time to evaluate it and understand it before using it.
- Quality control being what it is in our industry, you can’t count on it being correct and stable.
- It may be overengineered for your purposes; integration could be more work than a minimalist homegrown implementation.
- Foreign elements don’t usually integrate smoothly. There may be a distinct BOUNDED CONTEXT. Even if not, it may be difficult to smoothly reference ENTITIES from your other packages.
- It may introduce platform dependencies, compiler version dependencies, and so on.
- 在使用之前,仍需要花时间来评估和理解它。
- 就业内目前的质量控制水平而言,无法保证它的正确性和稳定性。
- 它可能设计得过于细致了(远远超出了你的目的),集成的工作量可能比开发一个最小化的内部实现更大。
- 外部元素的集成常常不顺利。它可能有一个与你的项目完全不同的 BOUNDED CONTEXT。即使不是这样,它也很难顺利地引用你的其他软件包中的 ENTITY。
- 它可能会引入对平台、编译器版本的依赖等。
Off-the-shelf subdomain solutions are worth investigating, but they are usually not worth the trouble. I’ve seen success stories in applications with very elaborate workflow requirements that used commercially available external workflow systems with API hooks. I’ve also seen success with an error-logging package that was deeply integrated into the application. Sometimes GENERIC SUBDOMAIN solutions are packaged in the form of frameworks, which implement a very abstract model that can be integrated with and specialized for your application. The more generic the subcomponent, and the more distilled its own model, the better the chance that it will be useful.
现成的子领域解决方案是值得我们去考虑的,但如果它们常常会带来麻烦,那么往往就得不偿失了。我曾经看到过一些成功案例——一些应用程序需要非常精细的工作流,它们通过 API 挂钩(API hook)成功地使用了商用的外部工作流系统。我曾经还见过错误日志被深入地集成到应用程序中。有时,GENERIC SUBDOMAIN 被打包为框架的形式,它实现了非常抽象的模型,从而可以与你的应用程序集成来满足你的特殊需求。子组件越通用,其自己的模型的精炼程度越高,它的用处可能就越大。
Option 2: A Published Design or Model
选择 2:公开发布的设计或模型
Advantages
- More mature than a homegrown model and reflects many people’s insights
- Instant, high-quality documentation
- 比自己开发的模型更为成熟,并且反映了很多人的深层知识。
- 提供了随时可用的高质量文档。
Disadvantage
- May not quite fit your needs or may be overengineered for your needs
- 可能不是很符合你的需要,或者设计得过于细致了(远远超出了你的需要)。
Tom Lehrer (the comedic songwriter from the 1950s and 1960s) said the secret to success in mathematics was, “Plagiarize! Plagiarize. Let no one’s work evade your eyes. . . . Only be sure always to call it please, research.” Good advice in domain modeling, and especially when attacking a GENERIC SUBDOMAIN.
Tom Lehrer(20 世纪 50 和 60 年代的喜剧作曲家)曾经讲过数学上的成功秘诀是:“抄袭!抄袭。不要让任何人的工作逃过你的眼睛……但一定要把这叫做研究。”在领域建模中,特别是在攻克 GENERIC SUBDOMAIN 时,这是金玉良言。
This works best when there is a widely distributed model, such as the ones in Analysis Patterns (Fowler 1996). (See Chapter 11.)
当有一个被广泛使用的模型时,如《分析模式》[Fowler 1996]一书中所列举的那些模型(参见第 11 章),这种方法最为有效。
When the field already has a highly formalized and rigorous model, use it. Accounting and physics are two examples that come to mind. Not only are these very robust and streamlined, but they are widely understood by people everywhere, reducing your present and future training burden. (See Chapter 10, on using established formalisms.)
如果领域中已经有了一种非常正式且严格的模型,那么就使用它。会计和物理学是我们立即能想到的两个例子。这些模型不仅精简和健壮,而且被人们广泛理解,因此可以减轻目前和将来的培训负担(参见 10.9.2 节)。
Don’t feel compelled to implement all aspects of a published model, if you can identify a simplified subset that is self-consistent and satisfies your needs. But in cases where there is a well-traveled and well-documented—or better yet, formalized—model available, it makes no sense to reinvent the wheel.
如果在一个公开发布的模式中能够发现一个简化的子集,它本身是一致的而且能够满足你的要求,那么就不要强迫自己完全实现一个这样的模型。如果一个模型已经有人很好地研究过了,并且提供了完备的文档,甚至已经得到正规化,那么重新去设计它就没有意义了。
Option 3: An Outsourced Implementation
选择 3:把实现外包出去
Advantages
- Keeps core team free to work on the CORE DOMAIN, where most knowledge is needed and accumulated.
- Allows more development to be done without permanently enlarging the team, but without dissipating knowledge of the CORE DOMAIN.
- Forces an interface-oriented design, and helps keep the subdomain generic, because the specification is being passed outside.
- 使核心团队可以脱身去处理 CORE DOMAIN,那才是最需要知识和经验积累的部分。
- 开发工作的增加不会使团队规模无限扩大下去,同时又不会导致 CORE DOMAIN 知识的分散。
- 强制团队采用面向接口的设计,并且有助于保持子领域的通用性,因为规格已经被传递到外部。
Disadvantages
- Still requires time from the core team, because the interface, coding standards, and any other important aspects need to be communicated.
- Incurs significant overhead of transferring ownership back inside, because code has to be understood. (Still, overhead is less than for specialized subdomains, because a generic model presumably requires no special background to understand.)
- Code quality can vary. This could be good or bad, depending on the relative caliber of the two teams.
- 仍需要核心团队花费一些时间,因为他们需要与外包人员商量接口、编码标准和其他重要方面。
- 当把代码移交回团队时,团队需要耗费大量精力来理解这些代码。(但是这个开销比理解专用子领域要小一些,因为通用子领域不需要理解专门的背景知识。)
- 代码质量或高或低,这取决于两个团队能力的高低。
Automated tests can play an important role in outsourcing. The implementers should be required to provide unit tests for the code they deliver. A really powerful approach—one that helps ensure a degree of quality, clarifies the spec, and smooths reintegration—is to specify or even write automated acceptance tests for the outsourced components. Also, “outsourced implementation” can be an excellent combination with “published design or model.”
自动测试在外包中可能起到重要作用。应该要求外包人员为他们交付的代码提供单元测试。真正有用的方法是为外包的组件详细说明甚至是编写自动验收测试,这有助于确保质量、明确规格并且使这些组件的再集成变得顺利。此外,“把实现外包出去”能够与“公开发布的设计或模型”完美地组合到一起。
Option 4: An In-House Implementation
选择 4:内部实现
Advantages
- Easy integration.
- You get just what you want and nothing extra.
- Temporary contractors can be assigned.
- 易于集成。
- 只开发自己需要的,不做多余的工作。
- 可以临时把工作分包出去。
Disadvantages
- Ongoing maintenance and training burden.
- It is easy to underestimate the time and cost of developing such packages.
- 需要承受后续的维护和培训负担。
- 很容易低估开发这些软件包所需的时间和成本。
Of course, this too combines well with “published design or model.”
当然,这也可以与“公开发布的设计或模型”结合起来使用。
GENERIC SUBDOMAINS are the place to try to apply outside design expertise, because they do not require deep understanding of your specialized CORE DOMAIN, and they do not present a major opportunity to learn that domain. Confidentiality is of less concern, because little proprietary information or business practice will be involved in such modules. A GENERIC SUBDOMAIN lessens the training burden for those not committed to deep knowledge of the domain.
GENERIC SUBDOMAIN 是你充分利用外部设计专家的地方,因为这些专家不需要深入理解你特有的 CORE DOMAIN,而且他们也没有太大的机会学习这个领域。机密性问题可以不用过多关注,因为这些模块几乎不涉及专有信息或业务实践。GENERIC SUBDOMAIN 可以减轻对那些不了解领域知识的人员进行培训而带来的负担。
Over time, I believe our ideas of what constitutes the CORE model will narrow, and more and more generic models will be available as implemented frameworks, or at least as published models or analysis patterns. For now, we still have to develop most of these ourselves, but there is great value in partitioning them from the CORE DOMAIN model.
我相信,随着时间的推移,CORE 模型的范围将会不断变窄,而越来越多的通用模型将作为框架被实现出来,或者至少被实现为公开发布的模型或分析模式。但是现在,大部分模型仍然需要我们自己开发,但把它们与 CORE DOMAIN 模型区分开是很有价值的。
Example: A Tale of Two Time Zones
示例两个与时区有关的故事
Twice I’ve watched as the best developers on a project spent weeks of their time solving the problem of storing and converting times with time zones. While I’m always suspicious of such activities, sometimes it is necessary, and these two projects provide almost perfect contrast.
我曾经两次亲眼目睹项目中最好的开发人员花费好几周的时间来解决各个时区的时间存储和转换问题。虽然我对这样的工作安排总是持怀疑态度,但有时它是必要的,而且下面这两个项目几乎形成了鲜明的对比。
The first was an effort to design scheduling software for cargo shipping. To schedule international transports, it is critical to have accurate time calculations, and because all such schedules are tracked in local time, it is impossible to coordinate transports without conversions.
第一个项目是为货物运输系统设计日程安排软件。为了安排国际运输,准确的时间计算是非常必要的,而由于所有这些日程安排都是按照当地时间计算的,因此运输过程的安排必然需要进行时间转换。
Having clearly established their need for this functionality, the team proceeded with development of the CORE DOMAIN and some early iterations of the application using the available time classes and some dummy data. As the application began to mature, it was clear that the existing time classes were not adequate, and that the problem was very intricate because of the variations between the many countries and the complexity of the International Date Line. With their requirements by now even clearer, they searched for an off-the-shelf solution, but found none. They had no option but to build it themselves.
既然这项功能需求已经确定了,团队就开始了 CORE DOMAIN 的开发并利用现有的时间类和一些哑数据进行了一些早期的应用程序迭代。随着应用程序不断成熟,现有的时间类已无法满足项目的要求,而且由于很多国家的时间是不同的,再加上国际日期变更线的复杂性,这个问题变得异常复杂。此时,他们的需求更加明确了,他们开始寻找现成的解决方案,但却没有找到。这样,除了自己构建之外已经别无选择了。
The task would require research and precision engineering, so the team leaders assigned one of their best programmers. But the task did not require any special knowledge of shipping and would not cultivate that knowledge, so they chose a programmer who was on the project on a temporary contract.
这项任务需要做一番研究并进行精确的设计,因此团队领导打算分派一位最好的程序员来完成它。但这项任务并不需要任何运输方面的专业知识,而且做这项任务也不会获得这样的知识,因此他们选择了一位临时在项目上工作的程序员。
This programmer did not start from scratch. He researched several existing implementations of time zones, most of which did not meet requirements, and decided to adapt the public-domain solution from BSD Unix, which had an elaborate database and an implementation in C. He reverse-engineered the logic and wrote an import routine for the database.
这位程序员并没有从头开始工作。他研究了几个现有的时区实现,但大部分并不能满足需要,于是他决定把 BSD Unix 的一个公共的解决方案改造一下,它已经有了一个完善的数据库和 C 语言实现。他通过逆向工程找出了其中的逻辑,并编写了一个数据库导入例程。
The problem turned out to be even harder than expected (involving, for example, the import of databases of special cases), but the code got written and integrated with the CORE and the product was delivered.
事实证明问题比他预计的要难得多(如涉及特殊情况的数据库导入),尽管如此他仍然完成了代码的编写并与 CORE 进行了集成,最终完成了产品的交付。
Things went very differently on the other project. An insurance company was developing a new claims-processing system, and planned to capture the times of various events (time of car crash, time of hail storm, and so on). This data would be recorded in local time, so time zone functionality was needed.
在另一个项目上发生的事情就完全不同了。一家保险公司开发一个新的理赔处理系统,他们打算把各种事件发生的时间记录下来(发生车祸的时间、下冰雹的时间等)。这些数据是按照当地时间记录的,因此需要用到时区功能。
When I arrived, they had assigned a junior, but very smart, developer to the task, although the exact requirements of the app were still in play and not even an initial iteration had been attempted. He had dutifully set out to build a time zone model a priori.
当我参加这个项目时,他们已经安排了一位初级(但很聪明的)开发人员来从事这项任务,尽管应用程序的准确需求仍在变化中,而且项目甚至还没有开始尝试第一次迭代。他已经开始尽职尽责地基于假设来构建一个时区模型。
Not knowing what would be needed, it was assumed that it should be flexible enough to handle anything. The programmer assigned to the task needed help with such a difficult problem, so a senior developer was assigned to it also. They wrote complex code, but no specific application was using it, so it was never clear that the code worked correctly.
由于不知道需要什么样的功能,这位开发人员假设时区组件应该足够灵活,以便处理任何可能的情况。这个问题对他来说太难了,因此项目又分派了一位高级开发人员来帮助他。他们编写了复杂的代码,但由于还没有具体的应用程序使用这些代码,因此他们根本不知道代码是否能正确工作。
The project ran aground for various reasons, and the time zone code was never used. But if it had been, simply storing local times tagged with the time zone might have been sufficient, even with no conversion, because this was primarily reference data and not the basis of computations. Even if conversion had turned out to be necessary, all the data was going to be gathered from North America, where time zone conversions are relatively simple.
项目由于种种原因而搁浅,时区代码从未派上用场。但如果项目不中断,那么简单地存储标明时区的当地时间可能就足够了,甚至不需要转换,因为这些时间数据主要用作参考,而不是用于计算。即使需要转换,由于所有数据都来自北美洲,时区转换也相对很简单。
The main cost of this attention to the time zones was the neglect of the CORE DOMAIN model. If the same energy had been placed there, they might have produced a functioning prototype of their own application and a first cut at a working domain model. Furthermore, the developers involved, who were committed long-term to the project, should have been steeped in the insurance domain, building up critical knowledge within the team.
过分关注时区带来的主要代价是忽略了 CORE DOMAIN 模型。如果他们能够把同样的精力放在核心模型上,可能早就为自己的应用程序开发出了一个有效的原型和一个初步的、可以工作的领域模型。此外,那些长期稳定地在项目上工作的开发人员此时本来应该对保险领域有所了解了,以便为团队积累关键知识。
One thing both projects did right was to cleanly segregate the GENERIC time zone model from the CORE DOMAIN. A shipping-specific or insurance-specific model of time zones would have coupled the model to this generic supporting model, making the CORE harder to understand (because it would contain irrelevant detail about time zones). It would have made the time zone MODULE harder to maintain (because the maintainer would have to understand the CORE and its interrelationship with time zones).
有一件事情这两个团队都做得很正确,那就是把通用的时区模型明确地从 CORE DOMAIN 中分离出来。如果在运输模型或保险模型中使用各自专用的时区 MODULE,那么这会导致核心模型与这个通用的支持模型耦合在一起,使得 CORE 模型更难以理解(因为它将包含无关的时区细节)。而且时区模块可能更难维护(因为维护人员必须理解核心以及它与时区的相互关系)。
We technical people tend to enjoy definable problems like time zone conversion, and we can easily justify spending our time on them. But a disciplined look at priorities usually points to the CORE DOMAIN.
技术人员喜欢处理那些可定义的问题(如时区转换),而且很容易就能证明他们花时间做这些工作是值得的。但严格地从优先级角度来看,他们应该先去完成 CORE DOMAIN 的工作。
Note that while I have emphasized the generic quality of these subdomains, I have not mentioned the reusability of code. Off-the-shelf solutions may or may not make sense for a particular situation, but assuming that you are implementing the code yourself, in-house or outsourced, you should specifically not concern yourself with the reusability of that code. This would go against the basic motivation of distillation: that you should be applying as much of your effort to the CORE DOMAIN as possible and investing in supporting GENERIC SUB-DOMAINS only as necessary.
注意,虽然我一直在强调这些子领域的通用性,但我并没有提代码的可重用性。现成的解决方案可能适用于某种特殊情况,也可能不适用,但假设你要自己实现代码(内部实现或外包出去),那么不要特别关注代码的可重用性。因为那样做会违反精炼的基本动机——我们应该尽可能把大部分精力投入到 CORE DOMAIN 工作中,而只在必要的时候才在支持性的 GENERIC SUBDOMAIN 中投入工作。
Reuse does happen, but not always code reuse. The model reuse is often a better level of reuse, as when you use a published design or model. And if you have to create your own model, it may well be valuable in a later related project. But while the concept of such a model may be applicable to many situations, you do not have to develop the model in its full generality. You can model and implement only the part you need for your business.
重用确实会发生,但不一定总是代码重用。模型重用通常是更高级的重用,例如,当使用公开发布的设计或模型的时候就是如此。如果你必须创建自己的模型,那么它在以后的相关项目中可能很有价值。但是,虽然这样的模型概念可能适用于很多情况,我们也不必把它开发成“万能的”模型。我们只要把业务所需的那部分建模出来并实现即可。
Though you should seldom design for reusability, you must be strict about keeping within the generic concept. Introducing industry-specific model elements will have two costs. First, it will impede future development. Although you need only a small part of the subdomain model now, your needs will grow. By introducing anything to the design that is not part of the concept, you make it much more difficult to expand the system cleanly without completely rebuilding the older part and redesigning the other modules that use it.
尽管我们很少需要考虑设计的可重用性,但通用子领域的设计必须严格地限定在通用概念的范围之内。如果把行业专用的模型元素引入到通用子领域中,会产生两个后果。第一,它会妨碍将来的开发。虽然现在我们只需要子领域模型的一小部分,但我们的需求会不断增加。如果把任何不属于子领域概念的部分引入到设计中,那么再想灵活地扩展系统就很难了,除非完全重建原来的部分并重新设计使用该部分的其他模块。
The second, and more important, reason is that those industry-specific concepts belong either in the CORE DOMAIN or in their own, more specialized, subdomains, and those specialized models are even more valuable than the generic ones.
第二,也是更重要的,这些行业专用的概念要么属于 CORE DOMAIN,要么属于它们自己的更专业的子领域,而且这些专业的模型比通用子领域更有价值。
Agile processes typically call for managing risk by tackling the riskiest tasks early. XP specifically calls for getting an end-to-end system up and running immediately. This initial system often proves a technical architecture, and it is tempting to build a peripheral system that handles some supporting GENERIC SUBDOMAIN because these are usually easier to analyze. But be careful; this can defeat the purpose of risk management.
敏捷过程通常要求通过尽早解决最具风险的任务来管理风险。特别是 XP 过程,它要求迅速建立并运行一个端到端的系统。这种初步的系统通常用来检验某种技术架构,而且人们会试图建立一个外围系统,用来处理一些支持性的 GENERIC SUBDOMAIN,因为这些子领域通常更易于分析。但是要注意,这可能会不利于风险管理。
Projects face risk from both sides, with some projects having greater technical risks and others greater domain modeling risks. The end-to-end system mitigates risk only to the extent that it is an embryonic version of the challenging parts of the actual system. It is easy to underestimate the domain modeling risk. It can take the form of unforeseen complexity, inadequate access to business experts, or gaps in key skills of the developers.
项目面临着两方面的风险,有些项目的技术风险更大,有些项目则是领域建模的风险更大一些。端到端的系统是实际系统中最困难部分的“雏形”——它控制风险的能力也仅限于此。当使用这种雏形时,我们很容易低估领域建模的风险。这种风险包括未预料到存在复杂性、与业务专家的交流不够充分,或者开发人员的关键技能存在欠缺等。
Therefore, except when the team has proven skills and the domain is very familiar, the first-cut system should be based on some part of the CORE DOMAIN, however simple.
因此,除非团队拥有精湛的技术并且对领域非常熟悉,否则第一个雏形系统应该以 CORE DOMAIN 的某个部分作为基础,不管它有多么简单。
The same principle applies to any process that tries to push high-risk tasks forward: the CORE DOMAIN is high risk because it is often unexpectedly difficult and because without it, the project cannot succeed.
相同的原则也适用于任何试图把高风险的任务放到前面处理的过程。CORE DOMAIN 就是高风险的,因为它的难度往往会超出我们的预料,而且如果没有它,项目就不可能获得成功。
Most of the distillation patterns in this chapter show how to change the model and code to distill the CORE DOMAIN. However, the next two patterns, DOMAIN VISION STATEMENT and HIGHLIGHTED CORE, show how the use of supplemental documents can, with a very minor investment, improve communication and awareness of the CORE and focus development effort. . . .
本章介绍的大多数精炼模式都展示了如何修改模型和代码,以便提炼出 CORE DOMAIN。但是,接下来的两个模式 DOMAIN VISION STATEMENT 和 HIGHLIGHTED CORE 将展示如何用最少的投入通过补充文档来增进沟通、提高人们对核心的认识并使之把开发工作集中到 CORE 上来……
At the beginning of a project, the model usually doesn’t even exist, yet the need to focus its development is already there. In later stages of development, there is a need for an explanation of the value of the system that does not require an in-depth study of the model. Also, the critical aspects of the domain model may span multiple BOUNDED CONTEXTS, but by definition these distinct models can’t be structured to show their common focus.
在项目开始时,模型通常并不存在,但是模型开发的需求是早就确定下来的重点。在后面的开发阶段,我们需要解释清楚系统的价值,但这并不需要深入地分析模型。此外,领域模型的关键方面可能跨越多个 BOUNDED CONTEXT,而且从定义上看,无法将这些彼此不同的模型组织起来表明其共同的关注点。
Many project teams write “vision statements” for management. The best of these documents lay out the specific value the application will bring to the organization. Some mention the creation of the domain model as a strategic asset. Usually the vision statement document is abandoned after the project gets funding, and it is never used in the actual development process or even read by the technical staff.
很多项目团队都会编写“愿景说明”以便管理。最好的愿景说明会展示出应用程序为组织带来的具体价值。一些愿景说明会把创建领域模型当作一项战略资产。通常,愿景说明文档在项目启动以后就被弃之不用了,而在实际开发过程中从来不会使用它,甚至根本不会有技术人员去阅读它。
A DOMAIN VISION STATEMENT is modeled after such documents, but it focuses on the nature of the domain model and how it is valuable to the enterprise. It can be used directly by the management and technical staff during all phases of development to guide resource allocation, to guide modeling choices, and to educate team members. If the domain model serves many masters, this document can show how their interests are balanced.
DOMAIN VISION STATEMENT 就是模仿这类文档创建的,但它关注的重点是领域模型的本质,以及如何为企业带来价值。在项目开发的所有阶段,管理层和技术人员都可以直接用领域愿景说明来指导资源分配、建模选择和团队成员的培训。如果领域模型为多个群体提供服务,那么此文档还能够显示出他们的利益是如何均衡的。
Therefore:
因此:
Write a short description (about one page) of the CORE DOMAIN and the value it will bring, the “value proposition.” Ignore those aspects that do not distinguish this domain model from others. Show how the domain model serves and balances diverse interests. Keep it narrow. Write this statement early and revise it as you gain new insight.
写一份 CORE DOMAIN 的简短描述(大约一页纸)以及它将会创造的价值,也就是“价值主张”。那些不能将你的领域模型与其他领域模型区分开的方面就不要写了。展示出领域模型是如何实现和均衡各方利益的。这份描述要尽量精简。尽早把它写出来,随着新的理解随时修改它。
A DOMAIN VISION STATEMENT can be used as a guidepost that keeps the development team headed in a common direction in the ongoing process of distilling the model and code itself. It can be shared with nontechnical team members, management, and even customers (except where it contains proprietary information, of course).
DOMAIN VISION STATEMENT 可以用作一个指南,它帮助开发团队在精炼模型和代码的过程中保持统一的方向。团队中的非技术成员、管理层甚至是客户也都可以共享领域愿景说明(当然,包含专有信息的情况除外)。
A DOMAIN VISION STATEMENT gives the team a shared direction. Some bridge between the high-level STATEMENT and the full detail of the code or model will usually be needed. . . .
DOMAIN VISION STATEMENT 为团队提供了统一的方向。但在高层次的说明和代码或模型的完整细节之间通常还需要做一些衔接……
A DOMAIN VISION STATEMENT identifies the CORE DOMAIN in broad terms, but it leaves the identification of the specific CORE model elements up to the vagaries of individual interpretation. Unless there is an exceptionally high level of communication on the team, the VISION STATEMENT alone will have little impact.
DOMAIN VISION STATEMENT 从宽泛的角度对 CORE DOMAIN 进行了说明,但它把什么是具体核心模型元素留给人们自己去解释和猜测。除非团队的沟通极其充分,否则单靠 VISION STATEMENT 是很难产生什么效果的。
Even though team members may know broadly what constitutes the CORE DOMAIN, different people won’t pick out quite the same elements, and even the same person won’t be consistent from one day to the next. The mental labor of constantly filtering the model to identify the key parts absorbs concentration better spent on design thinking, and it requires comprehensive knowledge of the model. The CORE DOMAIN must be made easier to see.
尽管团队成员可能大体上知道核心领域是由什么构成的,但 CORE DOMAIN 中到底包含哪些元素,不同的人会有不同的理解,甚至同一个人在不同的时间也会有不同的理解。如果我们总是要不断过滤模型以便识别出关键部分,那么就会分散本应该投入到设计上的精力,而且这还需要广泛的模型知识。因此,CORE DOMAIN 必须要很容易被分辨出来。
Significant structural changes to the code are the ideal way of identifying the CORE DOMAIN, but they are not always practical in the short term. In fact, such major code changes are difficult to undertake without the very view the team is lacking.
对代码所做的重大结构性改动是识别 CORE DOMAIN 的理想方式,但这些改动往往无法在短期内完成。事实上,如果团队的认识还不够全面,这样的重大代码修改是很难进行的。
Structural changes in the organization of the model, such as partitioning GENERIC SUBDOMAINS and a few others to come later in this chapter, can allow the MODULES to tell the story. But as the only means of communicating the CORE DOMAIN, this is too ambitious to shoot for straight away.
通过修改模型的组织结构(如划分 GENERIC SUBDOMAIN 和本章后面要介绍的一些改动),可以用 MODULE 表达出核心领域。但如果把它作为表达 CORE DOMAIN 的唯一方法,那么对模型的改动会很大,因此很难马上看到结果。
You will probably need a lighter solution to supplement these aggressive techniques. You may have constraints that prevent you from physically separating the CORE. Or you may be starting out with existing code that does not differentiate the CORE well, but you really need to see the CORE, and share that view, to effectively refactor toward better distillation. And even at an advanced stage, a few carefully selected diagrams or documents provide mental anchor points and entry points for the team.
我们可能需要用一种轻量级的解决方案来补充这些激进的技术手段。可能有一些约束使你无法从物理上分离出 CORE,或者你可能是从已有代码开始工作的,而这些代码并没有很好地区分出 CORE,但你确实很需要知道什么是 CORE 并建立起共识,以便有效地通过重构进行更好的精炼。即使到了高级阶段,通过仔细挑选几个图或文档,也能够为团队提供思考的定位点和切入点。
These issues arise equally for projects that use elaborate UML models and those (such as XP projects) that keep few external documents and use the code as the primary repository of the model. An Extreme Programming team might be more minimalist, keeping these supplements more casual and more transient (for example, a hand-drawn diagram on the wall for all to see), but these techniques can fold nicely into the process.
无论是使用了详尽的 UML 模型的项目,还是那些只使用很少的外部文档并且把代码用作主要的模型存储库的项目(如 XP 项目),都会面临这些问题。极限编程团队可能采用更简洁的做法,他们更少地使用这些补充解决方案,而且只是临时使用(例如,在墙上挂一张手绘的图,让所有人都能看到),但这些技术可以很好地结合到开发过程中。
Marking off a privileged part of a model, along with the implementation that embodies it, is a reflection on the model, not necessarily part of the model itself. Any technique that makes it easy for everyone to know the CORE DOMAIN will do. Two specific techniques can represent this class of solutions.
把模型的一个特别部分连同它的实现一起区分出来,这只是对模型的一种反映,而不必是模型自身的一部分。任何使人们易于了解 CORE DOMAIN 的技术都可以采用。这类解决方案有两种典型的代表性技术。
Often I create a separate document to describe and explain the CORE DOMAIN. It can be as simple as a list of the most essential conceptual objects. It can be a set of diagrams focused on those objects, showing their most critical relationships. It can walk through the fundamental interactions at an abstract level or by example. It can use UML class or sequence diagrams, nonstandard diagrams particular to the domain, carefully worded textual explanations, or combinations of these. A distillation document is not a complete design document. It is a minimalist entry point that delineates and explains the CORE and suggests reasons for closer scrutiny of particular pieces. The reader is given a broad view of how the pieces fit and guided to the appropriate part of the code for more details.
我经常会创建一个单独的文档来描述和解释 CORE DOMAIN。这个文档可能很简单,只是最核心的概念对象的清单。它可能是一组描述这些对象的图,显示了它们最重要的关系。它可能在抽象层次上或通过示例来描述基本的交互过程。它可能会使用 UML 类图或序列图、专用于领域的非标准的图、措辞严谨的文字解释或上述这些元素的组合。精炼文档并不是完备的设计文档。它只是一个最简单的切入点,描述并解释了核心,并给出了更进一步研究这些核心部分的理由。精炼文档为读者提供了一个总体视图,指出了各个部分是如何组合到一起的,并且指导读者到相应的代码部分寻找更多细节。
Therefore (as one form of HIGHLIGHTED CORE):
因此(作为 HIGHLIGHTED CORE(突出核心)的一种形式):
Write a very brief document (three to seven sparse pages) that describes the CORE DOMAIN and the primary interactions among CORE elements.
编写一个非常简短的文档(3 ~ 7 页,每页内容不必太多),用于描述 CORE DOMAIN 以及 CORE 元素之间的主要交互过程。
All the usual risks of separate documents apply.
独立文档带来的所有常见风险也会在这里出现:
- The document may not be maintained.
- The document may not be read.
- By multiplying the information sources, the document may defeat its own purpose of cutting through complexity.
- 文档可能得不到维护;
- 文档可能没人阅读;
- 由于有多个信息来源,文档可能达不到简化复杂性的目的。
The best way to limit these risks is to be absolutely minimalist. Staying away from mundane detail and focusing on the central abstractions and their interactions allows the document to age more slowly, because this level of the model is usually more stable.
控制这些风险的最好方法是保持绝对的精简。剔除那些不重要的细节,只关注核心抽象以及它们的交互,这样文档的老化速度就会减慢,因为这个层次的模型通常更稳定。
Write the document to be understood by the nontechnical members of the team. Use it as a shared view that delineates what every-one needs to know, and a guide by which all team members may start their exploration of the model and code.
精炼文档应该能够被团队中的非技术人员理解。把它当作一个共享的视图,描述每个人都应该知道的东西,而且可以把它作为团队所有成员研究模型和代码的一个起点。
On my first day on a project at a major insurance company, I was given a copy of the “domain model,” a two-hundred-page document, purchased at great expense from an industry consortium. I spent a few days wading through a jumble of class diagrams covering everything from the detailed composition of insurance policies to extremely abstract models of relationships between people. The quality of the factoring of these models ranged from high-school project to rather good (a few even described business rules, at least in the accompanying text). But where to start? Two hundred pages.
我以前参加过一家大型保险公司的项目,在上班的第一天,有人给了我一份 200 页的“领域模型”文档的复印件,这个文档是花高价从一家行业协会购买的。我花了几天时间仔细研究了一大堆类图,它们涵盖了所有细节,从详细的保险政策组合到人们之间极为抽象的关系模型。这些模型的质量也参差不齐,有的只有高中生的水平,有的却相当好(有几个甚至描述了业务规则,至少在附带的文本中做了描述)。但我要从哪里开始工作呢?要知道它有 200 页啊。
The project culture heavily favored abstract framework building, and my predecessors had focused on a very abstract model of the relationship of people with each other, with things, and with activities or agreements. It was actually a nice analysis of these relationships, and their experiments with the model had the quality of an academic research project. But it wasn’t getting us anywhere near an insurance application.
这个项目的人员热衷于构建抽象框架,我的前任们非常关注人与人之间、人与事物之间以及人与活动或协议之间的抽象关系模型。他们确实对关系进行了很好的分析,而且模型实验也达到了专业研究项目的水准,但却并没有使我们找到开发这个保险应用程序的任何思路。
My first instinct was to start slashing, finding a small CORE DOMAIN to fall back on, then refactoring that and reintroducing other complexities as we went. But the management was alarmed by this attitude. The document was invested with great authority. Its production had involved experts from across the industry, and in any event they had paid the consortium far more than they were paying me, so they were unlikely to weigh my recommendations for radical change too heavily. But I knew we had to get a shared picture of our CORE DOMAIN and get everyone’s efforts focused on that.
我对它的第一反应就是大幅删减,找到一个小的 CORE DOMAIN 并重构它,然后再逐步添加其他细节。但我的这个观点使管理层感到担心。这份文档具有极大的权威性。它是由整个行业的专家们编写的,而且无论如何他们付给协会的费用远远超过付给我的费用,因此他们不太可能慎重考虑我所提出的要进行彻底修改的建议。但我知道必须有一个共享的 CORE DOMAIN 视图,并让每个人的工作都以它为中心。
Instead of refactoring, I went through the document and, with the help of a business analyst who knew a great deal about the insurance industry in general and the requirements of the application we were to build in particular, I identified the handful of sections that presented the essential, differentiating concepts we needed to work with. I provided a navigation of the model that clearly showed the CORE and its relationship to supporting features.
我没有进行重构,而是走查了文档,并且还得到了一位既懂得大量保险业一般知识又了解我们这个特殊应用程序的具体需求的业务分析师的帮助,把那些体现出基本的、区别于其他系统概念的部分标识出来,这些是我们真正需要处理的部分。我提供了一个模型的导航图,它清晰地显示了核心,以及它与支持特性的关系。
A new prototyping effort started from this perspective, and quickly yielded a simplified application that demonstrated some of the required functionality.
我们从这个角度开始了建立原型的新工作,很快就开发出了一个简化的应用程序,它展示了一些必需的功能。
Two pounds of recyclable paper was turned into a business asset by a few page tabs and some yellow highlighter.
这沓两磅重的再生纸变成了一项有用的业务资产,而我做的只是加了少量的页标和一些黄色标记。
This technique is not specific to object diagrams on paper. A team that uses UML diagrams extensively could use a “stereotype” to identify core elements. A team that uses the code as the sole repository of the model might use comments, maybe structured as Java Doc, or might use some tool in its development environment. The particular technique doesn’t matter, as long as a developer can effortlessly see what is in and what is out of the CORE DOMAIN.
这种技术并不仅限于纸面上的对象图。使用大量 UML 图的团队可以使用一个“原型”(Stereotype)来识别核心元素。把代码用作唯一模型存储库的团队可以使用注释(可以采用 Java Doc 这样的结构),或使用开发环境中的一些工具。使用哪种特定技术都没关系,只要使开发人员容易分辨出什么在核心领域内,什么在核心领域外就可以了。
Therefore (as another form of HIGHLIGHTED CORE):
因此(作为另一种形式的 HIGHLIGHTED CORE):
Flag each element of the CORE DOMAIN within the primary repository of the model, without particularly trying to elucidate its role. Make it effortless for a developer to know what is in or out of the CORE.
把模型的主要存储库中的 CORE DOMAIN 标记出来,不用特意去阐明其角色。使开发人员很容易就知道什么在核心内,什么在核心外。
The CORE DOMAIN is now clearly visible to those working with the model, with a fairly small effort and low maintenance, at least to the extent that the model is factored fine enough to distinguish the contributions of parts.
现在,我们只做了很少的处理和维护工作,负责处理模型的人员就已经清晰地看到 CORE DOMAIN 了,至少模型已经被整理得很好,使人们很容易分清各个部分的组成。
Theoretically on an XP project, any pair (two programmers working together) can change any code in the system. In practice, some changes have major implications, and call for more consultation and coordination. When working in the infrastructure layer, the impact of a change may be clear, but it may not be so obvious in the domain layer, as typically organized.
理论上,在 XP 项目上工作的任何结对成员(两位一起工作的程序员)都可以修改系统中的任何代码。但在实际中,一些修改会产生很大影响,因此需要更多的商量和协调。按照项目通常的组织形式,当在基础设施层中工作时,变更的影响可能很清楚;但在领域层中,影响就不那么明显了。
With the concept of the CORE DOMAIN, this impact can be made clear. Changes to the model of the CORE DOMAIN should have a big effect. Changes to widely used generic elements may require a lot of code updating, but they still shouldn’t create the conceptual shift that CORE changes do.
从 CORE DOMAIN 的概念来看,这种影响会变得清楚。更改 CORE DOMAIN 模型会产生较大的影响。对广泛使用的通用元素进行修改可能要求更新大量的代码,但不会像 CORE DOMAIN 修改那样产生概念上的变化。
Use the distillation document as a guide. When developers realize that the distillation document itself requires change to stay in sync with their code or model change, then consultation is called for. Either they are fundamentally changing the CORE DOMAIN elements or relationships, or they are changing the boundaries of the CORE, including or excluding something different. Dissemination of the model change to the whole team is necessary by whatever communication channels the team uses, including distribution of a new version of the distillation document.
把精炼文档作为一个指南。如果开发人员发现精炼文档本身需要修改以便与他们的代码或模型修改保持同步,那么这样的修改需要大家一起协商。这种修改要么是从根本上修改 CORE DOMAIN 元素或关系;要么是修改 CORE DOMAIN 的边界,把一些元素包含进来,或是把一些元素排除出去。不管使用什么沟通渠道(包括新版本的精炼文档的分发),模型的修改都必须传达到整个团队。
If the distillation document outlines the essentials of the CORE DOMAIN, then it serves as a practical indicator of the significance of a model change. When a model or code change affects the distillation document, it requires consultation with other team members. When the change is made, it requires immediate notification of all team members, and the dissemination of a new version of the document. Changes outside the CORE or to details not included in the distillation document can be integrated without consultation or notification and will be encountered by other members in the course of their work. Then the developers have the full autonomy that XP suggests.
如果精炼文档概括了 CORE DOMAIN 的核心元素,那么它就可以作为一个指示器——用以指示模型改变的重要程度。当模型或代码的修改影响到精炼文档时,需要与团队其他成员一起协商。当对精炼文档做出修改时,需要立即通知所有团队成员,而且要把新版本的文档分发给他们。CORE 外部的修改或精炼文档外部的细节修改则无需协商或通知,可以直接把它们集成到系统中,其他成员在后续工作过程中自然会看到这些修改。这样开发人员就拥有了 XP 所建议的完全的自治性。
Although the VISION STATEMENT and HIGHLIGHTED CORE inform and guide, they do not actually modify the model or the code itself. Partitioning GENERIC SUBDOMAINS physically removes some distracting elements. The next patterns look at ways to structurally change the model and the design itself to make the CORE DOMAIN more visible and manageable. . . .
尽管 VISION STATEMENT 和 HIGHLIGHTED CORE 可以起到通知和指导的作用,但它们本身并没有修改模型或代码。具体地划分 GENERIC SUBDOMAIN 可以除去一些非核心元素。接下来的几个模式着眼于从结构上修改模型和设计本身,目的是使 CORE DOMAIN 更明显,更易于管理。
Encapsulating mechanisms is a standard principle of object-oriented design. Hiding complex algorithms in methods with intention-revealing names separates the “what” from the “how.” This technique makes a design simpler to understand and use. Yet it runs into natural limits.
封装机制是面向对象设计的一个基本原则。把复杂算法隐藏到方法中,再为方法起一个一看就知道其用途的名字,这样就把“做什么”和“如何做”分开了。这种技术使设计更易于理解和使用。然而它也有一些先天的局限性。
Computations sometimes reach a level of complexity that begins to bloat the design. The conceptual “what” is swamped by the mechanistic “how.” A large number of methods that provide algorithms for resolving the problem obscure the methods that express the problem.
计算有时会非常复杂,使设计开始变得膨胀。机械性的“如何做”大量增加,把概念性的“做什么”完全掩盖了。为解决问题提供算法的大量方法掩盖了那些用于表达问题的方法。
This proliferation of procedures is a symptom of a problem in the model. Refactoring toward deeper insight can yield a model and design whose elements are better suited to solving the problem. The first solution to seek is a model that makes the computation mechanism simple. But now and then the insight emerges that some part of the mechanism is itself conceptually coherent. This conceptual computation will probably not include all of the messy computations you need. We are not talking about some kind of catch-all “calculator.” But extracting the coherent part should make the remaining mechanism easier to understand.
这种方法的扩散是模型出问题的一种症状。这时应该通过重构得到更深层的理解,从而找到更适合解决问题的模型和设计元素。首先要寻找的解决方案是找到一个能使计算机制变得简单的模型。但有时我们会发现,有些计算机制本身在概念上就是内聚的。这种内聚的计算概念可能并不包括我们所需的全部计算。我们讨论的也不是一种万能的计算器。把内聚部分提取出来会使剩下的部分更易于理解。
Therefore:
因此:
Partition a conceptually COHESIVE MECHANISM into a separate lightweight framework. Particularly watch for formalisms or well-documented categories of algorithms. Expose the capabilities of the framework with an INTENTION-REVEALING INTERFACE. Now the other elements of the domain can focus on expressing the problem (“what”), delegating the intricacies of the solution (“how”) to the framework.
把概念上的 COHESIVE MECHANISM(内聚机制)分离到一个单独的轻量级框架中。要特别注意公式或那些有完备文档的算法。用一个 INTENTION-REVEALING INTERFACE 来暴露这个框架的功能。现在,领域中的其他元素就可以只专注于如何表达问题(做什么)了,而把解决方案的复杂细节(如何做)转移给了框架。
These separated mechanisms are then placed in their supporting roles, leaving a smaller, more expressive CORE DOMAIN that uses the mechanism through the interface in a more declarative style.
然后,这些被分离出来的机制承担起支持的任务,从而留下一个更小的、表达得更清楚的 CORE DOMAIN,这个核心以更加声明式的方式通过接口来使用这些机制。
Recognizing a standard algorithm or formalism moves some of the complexity of the design into a studied set of concepts. With such a guide, we can implement a solution with confidence and little trial and error. We can count on other developers knowing about it or at least being able to look it up. This is similar to the benefits of a published GENERIC SUBDOMAIN model, but a documented algorithm or formal computation may be found more often because this level of computer science has been studied more. Still, more often than not you will have to create something new. Make it narrowly focused on the computation and avoid mixing in the expressive domain model. There is a separation of responsibilities: The model of the CORE DOMAIN or a GENERIC SUBDOMAIN formulates a fact, rule, or problem. A COHESIVE MECHANISM resolves the rule or completes the computation as specified by the model.
把标准的算法或公式识别出来以后,可以把一部分设计的复杂性转移到一系列已经过深入研究的概念中。在这种方法的引导下,我们可以放心地实现一个解决方案,而且只需进行很少的尝试和改错。我们可以依靠其他一些了解这种算法或至少能够查到相关资料的开发人员。这个好处类似于从公开发布的 GENERIC SUBDOMAIN 模型获得的好处,但找到完备的算法或公式计算的机会比利用通用子领域模型的机会更大一些,因为这种水平的计算机科学已经有了较深入的研究。但是,我们仍常常需要创建新的算法。创建的算法应该主要用于计算,避免在算法中混杂用于表达问题的领域模型。二者的职责应该分离。CORE DOMAIN 或 GENERIC SUBDOMAIN 的模型描述的是事实、规则或问题。而 COHESIVE MECHANISM 则用来满足规则或者用来完成模型指定的计算。
Example: A Mechanism in an Organization Chart
示例从组织结构图中分离出一个 COHESIVE MECHANISM
I went through this process on a project that needed a fairly elaborate model of an organization chart. This model represented the fact that one person worked for another, and in which branches of the organization, and it provided an interface by which relevant questions might be asked and answered. Because most of these questions were along the lines of “Who, in this chain of command, has authority to approve this?” or “Who, in this department, is capable of handling an issue like this?” the team realized that most of the complexity involved traversing specific branches of the organizational tree, searching for specific people or relationships. This is exactly the kind of problem solved by the well-developed formalism of a graph, a set of nodes connected by arcs (called edges) and the rules and algorithms needed to traverse the graph.
我曾经在一个项目上经历过这种分离过程,这个项目需要一种非常详细的组织结构图模型。这个模型可以表示出一个人正在为谁工作以及他属于哪个分支部门,模型还提供了一个接口,通过这个接口可以提出和回答相关的问题。由于大部分问题都类似于“在这个指挥链中谁有权批准这件事”或“在这个部门中谁能够处理这样的问题”,因此团队意识到大部分复杂性都来自于遍历组织树中的特定分支,从中搜索特定的人员或关系。这恰好是成熟的图系统所能够解决的问题,图是一个由弧连接的节点集合(弧叫做边)以及遍历图所需的规则和算法组成。
A subcontractor implemented a graph traversal framework as a COHESIVE MECHANISM. This framework used standard graph terminology and algorithms familiar to most computer scientists and abundantly documented in textbooks. By no means did he implement a fully general graph. It was a subset of that conceptual framework that covered the features needed for our organization model. And with an INTENTION-REVEALING INTERFACE, the means by which the answers are obtained are not a primary concern.
负责这项工作的开发人员开发出了一个图的遍历框架,并把它实现为一种 COHESIVE MECHANISM。这个框架使用了标准的图术语和算法,大多数计算机专业人员都很熟悉这些术语和算法,而且它们在教科书中也大量出现。这位开发人员并没有实现一个完整的概念框架,而只是实现了它的一个子集,该子集涵盖了组织模型所需的功能。而且由于采用了 INTENTION-REVEALING INTERFACE,因此获取答案的方式并不是我们主要关心的问题。
Now the organization model could simply state, using standard graph terminology, that each person is a node, and that each relationship between people is an edge (arc) connecting those nodes. After that, presumably, mechanisms within the graph framework could find the relationship between any two people.
现在,组织模型可以用标准的图术语简单地把每个人表示为一个节点,把人们之间的关系表示为连接这些节点的边(弧)。这样,使用这个图框架机制就可以找到任意两个人之间的关系了。
If this mechanism had been incorporated into the domain model, it would have cost us in two ways. The model would have been coupled to a particular method of solving the problem, limiting future options. More important, the model of an organization would have been greatly complicated and muddied. Keeping mechanism and model separate allowed a declarative style of describing organizations that was much clearer. And the intricate code for graph manipulation was isolated in a purely mechanistic framework, based on proven algorithms, that could be maintained and unit-tested in isolation.
如果这个机制被混杂到领域模型中,那么将会产生两个后果。一是模型会与一个用于解决问题的特殊方法耦合在一起,这将限制将来的选择。更重要的是,组织的模型将变得异常复杂和混乱。把该机制与模型分开的好处是可以用声明式的风格来描述组织,使组织结构变得更清晰。而且用于图操作的复杂代码被分离到一个单纯的、基于成熟算法的机制框架中,从而可以进行单独的维护和单元测试。
Another example of a COHESIVE MECHANISM would be a framework for constructing SPECIFICATION objects and supporting the basic comparison and combination operations expected of them. By employing such a framework, the CORE DOMAIN and GENERIC SUBDOMAINS can declare their SPECIFICATIONS in the clear, easily understood language described in that pattern (see Chapter 10). The intricate operations involved in carrying out the comparisons and combinations can be left to the framework.
COHESIVE MECHANISM 的另一个例子是用一个框架来构造 SPECIFICATION 对象,并为这些对象所需的基本的比较和组合操作提供支持。利用这个框架,CORE DOMAIN 和 GENERIC SUBDOMAIN 可以用 SPECIFICATION 模式中所描述的清晰的、易于理解的语言来声明它们的规格(参见第 10 章)。这样,比较和组合等复杂操作可以留给框架去完成。
Both GENERIC SUBDOMAINS and COHESIVE MECHANISMS are motivated by the same desire to unburden the CORE DOMAIN. The difference is the nature of the responsibility taken on. A GENERIC SUBDOMAIN is based on an expressive model that represents some aspect of how the team views the domain. In this it is no different than the CORE DOMAIN, just less central, less important, less specialized. A COHESIVE MECHANISM does not represent the domain; it solves some sticky computational problem posed by the expressive models.
GENERIC SUBDOMAIN 与 COHESIVE MECHANISM 的动机是相同的——都是为 CORE DOMAIN 减负。区别在于二者所承担的职责的性质不同。GENERIC SUBDOMAIN 是以描述性的模型作为基础的,它用这个模型表示出团队会如何看待领域的某个方面。在这一点上它与 CORE DOMAIN 没什么区别,只是重要性和专门程度较低而已。COHESIVE MECHANISM 并不表示领域,它的目的是解决描述性模型所提出来的一些复杂的计算问题。
A model proposes; a COHESIVE MECHANISM disposes.
模型提出问题,COHESIVE MECHANISM 解决问题。
In practice, unless you recognize a formalized, published computation, this distinction is usually not pure, at least not at first. In successive refactoring it could either be distilled into a purer mechanism or be transformed into a GENERIC SUBDOMAIN with some previously unrecognized model concepts that would make the mechanism simple.
在实践中,除非你识别出一种正式的、公开发布的算法,否则这种区别通常并不十分清楚,至少在开始时是这样。在后续的重构中,如果发现一些先前未识别的模型概念会使这种机制变得更为简单,那么就可以把这种算法精炼成一种更纯粹的机制,或者转换为一个 GENERIC SUBDOMAIN。
You almost always want to remove MECHANISMS from the CORE DOMAIN. The one exception is when a MECHANISM is itself proprietary and a key part of the value of the software. This is sometimes the case with highly specialized algorithms. For example, if one of the distinguishing features of a shipping logistics application were a particularly effective algorithm for working out schedules, that MECHANISM could be considered part of the conceptual CORE. I once worked on a project at an investment bank in which highly proprietary algorithms for rating risk were definitely in the CORE DOMAIN. (In fact, they were held so closely that even most of the CORE developers were not allowed to see them.) Of course, these algorithms are probably a particular implementation of a set of rules that really predict risk. Deeper analysis might lead to a deeper model that would allow those rules to be explicit, with an encapsulated solving mechanism.
我们几乎总是想要把 MECHANISM 从 CORE DOMAIN 中分离出去。例外的情况是 MECHANISM 本身就是专有的并且是软件的一项核心价值。有时,非常专用的算法就是这种情况。例如,如果一个非常高效的算法(用于计算日程安排)是运输物流应用程序中的标志性特性之一,那么该机制就可以被认为是概念核心的一部分。我以前参加过一个投资银行的项目,在这个项目中有一个非常专业的风险评估算法,它无疑是 CORE DOMAIN 的一部分(事实上,这个算法是高度机密的,甚至大部分核心开发人员都看不到它们)。当然,这些算法可能是一个用于预测风险的规则集的特殊实现。通过更深入的分析可能会得到一个更深层的模型,从而用一种封装的解决机制把这些规则显式地表达出来。
But that would be another incremental improvement in the design, for another day. The decision as to whether to go that next step would be based on a cost-benefit analysis: How difficult would it be to work out that new design? How difficult is the current design to understand and modify? How much easier would it be with a more advanced design, for the type of people who would be expected to do the work? And of course, does anyone have any idea what form the new model might take?
但那只是将来要做的进一步改进。是否做这个决定取决于成本—效益分析。实现新设计的难度有多大?当前设计有多难理解和修改?采用更高级的设计后,对从事这些工作的人来说,设计会得到多大程度的简化?当然,有人对新模型的组成有什么想法吗?
Example: Full Circle: Organization Chart Reabsorbs Its MECHANISM
示例绕了一圈,MECHANISM 又重新回到组织结构图中
Actually, a year after we completed the organization model in the previous example, other developers redesigned it to eliminate the separation of the graph framework. They felt the increased object count and the complication of separating the MECHANISM into a separate package were not warranted. Instead, they added node behavior to the parent class of the organizational ENTITIES. Still, they retained the declarative public interface of the organization model. They even kept the MECHANISM encapsulated, within the organizational ENTITIES.
实际上,在我们完成了前面示例中的组织模型一年之后,其他开发人员又重新设计了它,取消了分离的图框架。他们认为对象数量在增加,而且把这种 MECHANISM 分离到单独的包中也会变得很复杂,于是觉得这二者没必要如此。相反,他们把节点行为添加到组织 ENTITY 的父类中。但他们保留了组织模型的声明式公共接口。他们甚至在组织 ENTITY 中保持了 MECHANISM 的封装。
These full circles are common, but they do not return to their starting point. The end result is usually a deeper model that more clearly differentiates facts, goals, and MECHANISMS. Pragmatic refactoring retains the important virtues of the intermediate stages while shedding the unneeded complications.
绕弯路之后又返回到原来的老路上是很常见的事情,但并不会退回到起点。最终结果通常是得到了一个更深层的模型,这个模型能够更清楚地区分出事实、目标和 MECHANISM。实用的重构在保留中间阶段的重要价值的同时还能够去除不必要的复杂性。
Declarative design and “declarative style” is a topic of Chapter 10, but that design style deserves special mention in this chapter on strategic distillation. The value of distillation is being able to see what you are doing: cutting to the essence without being distracted by irrelevant detail. Important parts of the CORE DOMAIN may be able to follow a declarative style, when the supporting design provides an economical language for expressing the concepts and rules of the CORE while encapsulating the means of computing or enforcing them.
声明式设计和“声明式风格”是第 10 章的一个主题,但在本章的战略精炼这个话题上,有必要特别提一下这种设计风格。精炼的价值在于使你能够看到自己正在做什么,不让无关细节分散你的注意力,并通过不断削减得到核心。如果领域中那些起到支持作用的部分提供了一种简练的语言,可用于表示 CORE 的概念和规则,同时又能够把计算或实施这些概念和规则的方式封装起来,那么 CORE DOMAIN 的重要部分就可以采用声明式设计。
COHESIVE MECHANISMS are by far most useful when they provide access through an INTENTION-REVEALING INTERFACE, with conceptually coherent ASSERTIONS and SIDE-EFFECT-FREE FUNCTIONS. MECHANISMS and supple designs allow the CORE DOMAIN to make meaningful statements rather than calling obscure functions. But an exceptional payoff comes when part of the CORE DOMAIN itself breaks through to a deep model and starts to function as a language that can express the most important application scenarios flexibly and concisely.
COHESIVE MECHANISM 用途最大的地方是它通过一个 INTENTION-REVEALING INTERFACE 来提供访问,并且具有概念上一致的 ASSERTION 和 SIDE-EFFECT-FREE FUNCTION。利用这些 MECHANISM 和柔性设计,CORE DOMAIN 可以使用有意义的声明,而不必调用难懂的函数。但最不同寻常的回报来自于使 CORE DOMAIN 的一部分产生突破,得到一个深层模型,而且这部分核心领域本身成为了一种语言,可以灵活且精确地表达出最重要的应用场景。
A deep model often comes with a corresponding supple design. When a supple design reaches maturity, it provides an easily understood set of elements that can be combined unambiguously to accomplish complex tasks or express complex information, just as words are combined into sentences. At that point, client code takes on a declarative style and can be much more distilled.
深层模型往往与相对应的柔性设计一起产生。柔性设计变得成熟的时候,就可以提供一组易于理解的元素,我们可以明确地把它们组合到一起来完成复杂的任务,或表达复杂的信息,就像单词组成句子一样。此时,客户代码就可以采用声明式风格,而且更为精炼。
Factoring out GENERIC SUBDOMAINS reduces clutter, and COHESIVE MECHANISMS serve to encapsulate complex operations. This leaves behind a more focused model, with fewer distractions that add no particular value to the way users conduct their activities. But you are unlikely ever to find good homes for everything in the domain model that is not CORE. The SEGREGATED CORE takes a direct approach to structurally marking off the CORE DOMAIN...
把 GENERIC SUBDOMAIN 提取出来可以减少混乱,而 COHESIVE MECHANISM 可以把复杂操作封装起来。这样可以得到一个更专注的模型,从而减少了那些对用户活动没什么价值的、分散注意力的方面。但我们不太可能为领域模型中所有非 CORE 元素安排一个适当的去处。SEGREGATED CORE(分离的核心)采用直接的方法从结构上把 CORE DOMAIN 划分出来。
Elements in the model may partially serve the CORE DOMAIN and partially play supporting roles. CORE elements may be tightly coupled to generic ones. The conceptual cohesion of the CORE may not be strong or visible. All this clutter and entanglement chokes the CORE. Designers can’t clearly see the most important relationships, leading to a weak design.
模型中的元素可能有一部分属于 CORE DOMAIN,而另一部分起支持作用。核心元素可能与一般元素紧密耦合在一起。CORE 的概念内聚性可能不是很强,看上去也不明显。这种混乱性和耦合关系抑制了 CORE。设计人员如果无法清晰地看到最重要的关系,就会开发出脆弱的设计。
By factoring out GENERIC SUBDOMAINS, you clear away some of the obscuring detail from the domain, making the CORE more visible. But it is hard work identifying and clarifying all these subdomains, and some of them don’t seem worth the trouble. Meanwhile, the all-important CORE DOMAIN is left entangled with the residue.
通过把 GENERIC SUBDOMAIN 提取出来,可以从领域中清除一些干扰性的细节,使 CORE 变得更清楚。但识别和澄清所有这些子领域是很困难的工作,而且有些工作看起来并不值得去做。同时,最重要的 CORE DOMAIN 仍然与剩下的那些元素纠缠在一起。
Therefore:
因此:
Refactor the model to separate the CORE concepts from supporting players (including ill-defined ones) and strengthen the cohesion of the CORE while reducing its coupling to other code. Factor all generic or supporting elements into other objects and place them into other packages, even if this means refactoring the model in ways that separate highly coupled elements.
对模型进行重构,把核心概念从支持性元素(包括定义得不清楚的那些元素)中分离出来,并增强 CORE 的内聚性,同时减少它与其他代码的耦合。把所有通用元素或支持性元素提取到其他对象中,并把这些对象放到其他的包中——即使这会把一些紧密耦合的元素分开。
This is basically taking the same principles we applied to GENERIC SUBDOMAINS but from the other direction. The cohesive subdomains that are central to our application can be identified and partitioned into coherent packages of their own. What is done with the undifferentiated mass left behind is important, but not as important. It can be left more or less where it was, or placed into packages based on prominent classes. Eventually, more and more of the residue can be factored into GENERIC SUBDOMAINS, but in the short term any easy solution will do, just so the focus on the SEGREGATED CORE is retained.
这里基本上采用了与 GENERIC SUBDOMAIN 一样的原则,只是从另一个方向来考虑而已。那些在应用程序中非常关键的内聚子领域可以被识别出来,并分离到它们自己的内聚包中。如何处理剩下那些未加区分的元素虽然也很重要,但其重要性略低。这些元素或多或少地可以保留在原先的位置,也可以放到包含了重要类的包中。最后,越来越多的剩余元素可以被提取到 GENERIC SUBDOMAIN 中。但就目前来看,使用哪种简单解决方案都可以,只需把注意力集中在 SEGREGATED CORE(分离的核心)上即可。
The steps needed to refactor to SEGREGATED CORE are typically something like these:
通过重构得到 SEGREGATED CORE 的一般步骤如下所示。
- Identify a CORE subdomain (possibly drawing from the distillation document).
- Move related classes to a new MODULE, named for the concept that relates them.
- Refactor code to sever data and functionality that are not directly expressions of the concept. Put the removed aspects into (possibly new) classes in other packages. Try to place them with conceptually related tasks, but don’t waste too much time being perfect. Keep focused on scrubbing the CORE subdomain and making the references from it to other packages explicit and self-explanatory.
- Refactor the newly SEGREGATED CORE MODULE to make its relationships and interactions simpler and more communicative, and to minimize and clarify its relationships with other MODULES. (This becomes an ongoing refactoring objective.)
- Repeat with another CORE subdomain until the SEGREGATED CORE is complete.
- 识别出一个 CORE 子领域(可能是从精炼文档中得到的)。
- 把相关的类移到新的 MODULE 中,并根据与这些类有关的概念为模块命名。
- 对代码进行重构,把那些不直接表示概念的数据和功能分离出来。把分离出来的元素放到其他包的类(可以是新的类)中。尽量把它们与概念上相关的任务放在一起,但不要为了追求完美而浪费太长时间。把注意力放在提炼 CORE 子领域上,并且使 CORE 子领域对其他包的引用变得更明显且易于理解。
- 对新的 SEGREGATED CORE MODULE 进行重构,使其中的关系和交互变得更简单、表达得更清楚,并且最大限度地减少并澄清它与其他 MODULE 的关系(这将是一个持续进行的重构目标)。
- 对另一个 CORE 子领域重复这个过程,直到完成 SEGREGATED CORE 的工作。
Segregating the CORE will sometimes make relationships with tightly coupled non-CORE classes more obscure or even more complicated, but that cost is outweighed by the benefit of clarifying the CORE DOMAIN and making it much easier to work on.
有时候,把 CORE 分离出来会使得它与那些紧密耦合的非 CORE 类的关系变得更晦涩,甚至更复杂,但 CORE DOMAIN 更清晰了,而且更易于处理,因此获得的好处还是足以抵偿这种代价。
The SEGREGATED CORE will let you enhance the cohesion of that CORE DOMAIN. There are many meaningful ways of breaking down a model, and sometimes in the creation of a SEGREGATED CORE a nicely cohesive MODULE may be broken, sacrificing that cohesion for the sake of bringing out the cohesiveness of the CORE DOMAIN. This is a net gain, because the greatest value-added of enterprise software comes from the enterprise-specific aspects of the model.
SEGREGATED CORE 使我们能够提高 CORE DOMAIN 的内聚性。我们可以使用很多有意义的方式来分解模型,有时在创建 SEGREGATED CORE 时,可以把一个内聚性很好的 MODULE 拆分开,通过牺牲这种内聚性来换取 CORE DOMAIN 的内聚性。这样做是值得的,因为企业软件的最大价值来自于模型中企业的那些特有方面。
The other cost, of course, is that segregating the CORE is a lot of work. It must be acknowledged that a decision to go to a SEGREGATED CORE will potentially absorb developers in changes all over the system.
当然,另一个代价是分离 CORE 需要付出很大的工作量。我们必须认识到,在做出 SEGREGATED CORE 的决定时,有可能需要开发人员对整个系统做出修改。
The time to chop out a SEGREGATED CORE is when you have a large BOUNDED CONTEXT that is critical to the system, but where the essential part of the model is being obscured by a great deal of supporting capability.
当系统有一个很大的、非常重要的 BOUNDED CONTEXT 时,但模型的关键部分被大量支持性功能掩盖了,那么就需要创建 SEGREGATED CORE 了。
As with many strategic design decisions, an entire team must move to a SEGREGATED CORE together. This step requires a team decision process and a team disciplined and coordinated enough to carry out the decision. The challenge is to constrain everyone to use the same definition of the CORE while not freezing that decision. Because the CORE DOMAIN evolves just like every other aspect of a design, experience working with a SEGREGATED CORE will lead to new insights into what is essential and what is a supporting element. Those insights should feed back into a refined definition of the CORE DOMAIN and of the SEGREGATED CORE MODULES.
就像很多战略设计决策所要求的一样,创建 SEGREGATED CORE 需要整个团队一致行动。这一行动需要团队的一致决策,而且团队必须足够自律和协调才能执行这样的决策。困难之处在于既要约束每个人使其都使用相同的 CORE 定义,又不能一成不变地去执行这个决策。由于 CORE DOMAIN 也是不断演变的(像任何其他设计方面一样),在处理 SEGREGATED CORE 的过程中我们会不断积累经验,这将使我们对什么是核心什么是支持元素这些问题产生新的理解。我们应该把这些理解反馈到设计中,从而得到更完善的 CORE DOMAIN 和 SEGREGATED COREMODULE 的定义。
This means that new insights must be shared with the team on an ongoing basis, but an individual (or programming pair) cannot act on those insights unilaterally. Whatever the process is for joint decisions, whether consensus or team leader directive, it must be agile enough to make repeated course corrections. Communication must be effective enough to keep everyone together in one view of the CORE.
这意味着新的理解必须持续不断地在整个团队中共享,但个人(或编程对)不能单方面根据这些理解擅自采取行动。无论团队采用了什么样的决策过程,团队一致通过也好,由领导者下命令决定也好,决策过程都必须具有足够的敏捷性,可以反复纠正。团队必须进行有效的沟通,以便使每个人都共享同一个 CORE 视图。
Example: Segregating the CORE of a Cargo Shipping Model
示例把货物运输模型的 CORE 分离出来
We start with the model shown in Figure 15.2 as the basis of software for cargo shipping coordination.
我们从图 15-2 所示的模型开始,把它作为货物运输调度软件的基础。
Note that this is highly simplified compared to what would likely be needed for a real application. A realistic model would be too cumbersome for an example. Therefore, although this example may not be complicated enough to drive us to a SEGREGATED CORE, take a leap of imagination to treat this model as being too complex to interpret easily and deal with as a whole.
注意,与实际应用程序所需的模型相比,这个模型是高度简化的。真实的模型过于复杂,不适合作为例子。因此,尽管这个示例的复杂程度可能不足以驱使我们创建 SEGREGATED CORE,但可以把这个模型想象得十分复杂,很难解释,而且无法作为一个整体来处理。
Now, what is the essence of the shipping model? Usually a good place to start looking is the “bottom line.” This might lead us to focus on pricing and invoices. But we really need to look at the DOMAIN VISION STATEMENT. Here is an excerpt from this one.
现在,运输模型的实质是什么?通常“梗概”是一个很好的起点。据此,我们可能会注意到 Pricing(定价)和 Invoice(发票)上。但实际上我们需要看一下 DOMAIN VISION STATEMENT。以下就是从愿景说明中摘录的:
. . . Increase visibility of operations and provide tools to fulfill customer requirements faster and more reliably...
……提高操作的可见性,并提供更快速可靠地满足客户需求的工具……
This application is not being designed for the sales department. It is going to be used by the front-line operators of the company. So let’s relegate all money-related issues to (admittedly important) supporting roles. Someone has already placed some of these items into a separate package (Billing). We can keep that, and further recognize that it plays a supporting role.
这个应用程序并不是为销售部门设计的,而是供公司一线操作人员使用。因此,我们把所有与金钱有关的问题(当然很重要)归结为支持性作用。已经有人把一些这样的项放到一个单独的包(Billing)中。我们可以保留这个包,并进一步确认它起到支持作用。
The focus needs to be on the cargo handling: delivery of the cargo according to customer requirements. Extracting the classes most directly involved in these activities produces a SEGREGATED CORE in a new package called Delivery, as shown in Figure 15.3.
我们需要把重点放在货物处理上:根据客户需求来运输货物。我们把与这些活动直接相关的类提取出来放到一个新的包 Delivery 中,这样就产生了一个 SEGREGATED CORE,如图 15-3 所示。
Reliable delivery in adherence with customer requirements is the core goal of this project.
For the most part, classes have just moved into the new package, but there have been a few changes to the model itself.
大部分操作都只是把类移动到新的包中,但模型本身也有几处改动。
First, the Customer Agreement now constrains the Handling Step. This is typical of the insights that tend to arise as the team segregates the CORE. As attention is focused on effective, correct delivery, it becomes clear that the delivery constraints in the Customer Agreement are fundamental and should be explicit in the model.
首先,Customer Agreement 对 Handling Step 进行了约束。这是团队在分离 CORE 过程中获得的典型理解。由于团队把注意力放在有效、正确的运输上,显然 Customer Agreement 中的运输约束是非常重要的,而且应该在模型中显式地表达出来。
The other change is more pragmatic. In the refactored model, the Customer Agreement is attached directly to the Cargo, rather than requiring a navigation through the Customer. (It will have to be attached when the Cargo is booked, just as the Customer is.) At actual delivery time, the Customer is not as relevant to operations as the agreement itself. In the other model, the correct Customer had to be found, according to the role it played in the shipment, and then queried for its Customer Agreement. This interaction would clog up every story you set out to tell about the model. The new association makes the most important scenarios as simple and direct as possible. Now it becomes easy to pull the Customer out of the CORE altogether.
另一项更改更有实效。在重构之后的模型中,Customer Agreement 直接连接到 Cargo,而不再需要通过 Customer 进行导航(在预订 Cargo 时,Customer Agreement 必须像 Customer 一样连接到 Cargo)。在实际运输时,Customer 与运输作业的关系不如 Agreement 与作业的关系紧密。而在原来的模型中,必须根据 Customer 在运输中的角色找到正确的 Customer,然后再查询其 Customer Agreement。这种交互使得模型的表述不易理解。新的关联使那些最重要的场景变得尽可能简单和直接。现在就很容易把 Customer 完全从 CORE 中分离出去了。
And what about pulling Customer out, anyway? The focus is on fulfilling the Customer’s requirements, so at first Customer seems to belong in the CORE. Yet the interactions during delivery do not usually need to involve the Customer class now that the Customer Agreement is available directly. And the basic model of a Customer is pretty generic.
那么到底是否应该把 Customer 提取出来呢?我们的关注点是要满足 Customer 的需求,因此最初看上去 Customer 应该属于 CORE。然而,由于运输期间的交互现在可以直接访问 Customer Agreement 了,因此就不再需要 Customer 类。这样 Customer 的基本模型就非常通用了。
A strong argument could be made for Leg to remain in the CORE. I tend to be minimalist in the CORE, and the Leg has tighter cohesion with Transport Schedule, Routing Service, and Location, none of which needed to be in the CORE. But if a lot of the stories I wanted to tell about this model involved Legs, I’d move it into the Delivery package and suffer the awkwardness of its separation from those other classes.
Leg 是否应该保留在 CORE 中这个问题可能会引起很大的争议。我的意见是 CORE 应保持最小化,而且 Leg 与 Transport Schedule、Routing Service 和 Location 具有更紧密的联系,而这三者都不需要在 CORE 中。但是,如果这个模型描述的很多场景都涉及 Leg,那么我就会把它移到 Delivery 包中,即使把它与上面那些类分开显得有些不协调。
In this example, all the class definitions are the same as before, but often distillation requires refactoring the classes themselves to separate the generic and domain-specific responsibilities, which can then be segregated.
在这个例子中,所有类定义都与先前相同,但精炼通常都需要对类进行重构,以便分离出通用职责和领域专有职责,然后就可以把核心分离出来了。
Now that we have a SEGREGATED CORE, the refactoring is complete. But the Shipping package we are left with is just “everything left over after we pulled out the CORE.” We can follow up with other refactorings to get more communicative packaging, as shown in Figure 15.4.
既然我们已经有了一个 SEGREGATED CORE,重构就完成了。但剩下的 Shipping 包正是“把 CORE 提取出来后剩下的所有东西”。我们可以再进行其他的重构过程,以便得到更清晰的打包方式,如图 15-4 所示。
Meaningful MODULES for non-CORE subdomains follow after the SEGREGATED CORE is complete.
It might take several refactorings to get to this point; it doesn’t have to be done all at once. Here, we’ve ended up with one SEGREGATED CORE package, one GENERIC SUBDOMAIN, and two domain-specific packages in supporting roles. Deeper insight might eventually produce a GENERIC SUBDOMAIN for Customer, or it might end up more specialized for shipping.
这种效果不是一次就能实现的,可能需要经过多次重构。于是,我们最后得到了一个 SEGREGATED CORE 包、一个 GENERIC SUBDOMAIN 和两个起支持作用的领域专用包。在有了更深层的理解后,可能会为 Customer 创建一个 GENERIC SUBDOMAIN,或者将 Customer 专用于运输。
Recognizing useful, meaningful MODULES is a modeling activity (as discussed in Chapter 5). Developers and domain experts collaborate in strategic distillation as part of the knowledge crunching process.
识别有用的、有意义的 MODULE 是一项建模活动(正如第 5 章中所讨论的那样)。开发人员和领域专家在战略精炼中进行协作,这种协作是知识消化过程的一部分。
Even the CORE DOMAIN model usually has so much detail that communicating the big picture can be difficult.
通常,即便是 CORE DOMAIN 模型也会包含太多的细节,以至于它很难表达出整体视图。
We usually deal with a large model by breaking it into narrower subdomains that are small enough to be grasped and placing them in separate MODULES. This reductive style of packaging often works to make a complicated model manageable. But sometimes creating separate MODULES can obscure or even complicate the interactions between the subdomains.
我们处理大模型的方法通常是把它分解为足够小的子领域,以便能够掌握它们并把它们放到一些独立的 MODULE 中。这种简化式的打包风格通常是行之有效的,能够使一个复杂的模型变得易于管理。但有时创建独立的 MODULE 反而会使子领域之间的交互变得晦涩难懂,甚至变得更复杂。
When there is a lot of interaction between subdomains in separate MODULES, either many references will have to be created between MODULES, which defeats much of the value of the partitioning, or the interaction will have to be made indirect, which makes the model obscure.
当不同 MODULE 的子领域之间有大量交互时,要么需要在 MODULE 之间创建很多引用,这在很大程度上抵消了划分模块的价值;要么就必须间接地实现这些交互,而后者会使模型变得晦涩难懂。
Consider slicing horizontally rather than vertically. Polymorphism gives us the power to ignore a lot of the detailed variation among instances of an abstract type. If most of the interactions across MODULES can be expressed at the level of polymorphic interfaces, it may make sense to refactor these types into a special CORE MODULE.
我们不妨考虑采用横向切割而不是纵向切割的方式。多态性(polymorphism)允许我们忽略抽象类型实例的很多细节变化。如果 MODULE 之间的大部分交互都可以在多态接口这个层次上表达出来,那么就可以把这些类型重构到一个特定的 CORE MODULE 中。
We are not looking for a technical trick here. This is a valuable technique only when the polymorphic interfaces correspond to fundamental concepts in the domain. In that case, separating these abstractions decouples the MODULES while distilling a smaller and more cohesive CORE DOMAIN.
这里并不是寻找技术上的技巧。只有当领域中的基本概念能够用多态接口来表达时,这才是一种有价值的技术。在这种情况下,把这些分散注意力的细节分离出来可以使 MODULE 解耦,同时可以精炼出一个更小、更内聚的 CORE DOMAIN。
Therefore:
因此:
Identify the most fundamental concepts in the model and factor them into distinct classes, abstract classes, or interfaces. Design this abstract model so that it expresses most of the interaction between significant components. Place this abstract overall model in its own MODULE, while the specialized, detailed implementation classes are left in their own MODULES defined by subdomain.
把模型中最基本的概念识别出来,并分离到不同的类、抽象类或接口中。设计这个抽象模型,使之能够表达出重要组件之间的大部分交互。把这个完整的抽象模型放到它自己的 MODULE 中,而专用的、详细的实现类则留在由子领域定义的 MODULE 中。
Most of the specialized classes will now reference the ABSTRACT CORE MODULE but not the other specialized MODULES. The ABSTRACT CORE gives a succinct view of the main concepts and their interactions.
现在,大部分专用的类都将引用 ABSTRACT CORE MODULE,而不是其他专用的 MODULE。ABSTRACT CORE(抽象核心)提供了主要概念及其交互的简化视图。
The process of factoring out the ABSTRACT CORE is not mechanical. For example, if all the classes that were frequently referenced across MODULES were automatically moved into a separate MODULE, the likely result would be a meaningless mess. Modeling an ABSTRACT CORE requires a deep understanding of the key concepts and the roles they play in the major interactions of the system. In other words, it is an example of refactoring to deeper insight. And it usually requires considerable redesign.
提取 ABSTRACT CORE 并不是一个机械的过程。例如,如果把 MODULE 之间频繁引用的所有类都自动移动到一个单独的 MODULE 中,那么结果可能是一团糟,而且毫无意义。对 ABSTRACT CORE 进行建模需要深入理解关键概念以及它们在系统的主要交互中扮演的角色。换言之,它是通过重构得到更深层理解的。而且它通常需要大量的重新设计。
The ABSTRACT CORE should end up looking a lot like the distillation document (if both were used on the same project, and the distillation document had evolved with the application as insight deepened). Of course, the ABSTRACT CORE will be written in code, and therefore more rigorous and more complete.
如果项目中同时使用了 ABSTRACT CORE 和精炼文档,而且精炼文档随着应用程序理解的加深而不断演变,那么抽象核心的最后结果看起来应该与精炼文档非常类似。当然,ABSTRACT CORE 是用代码编写的,因此更为严格和完整。
Distillation does not operate only on the gross level of separating parts of the domain away from the CORE. It also means refining those subdomains, especially the CORE DOMAIN, through continuously refactoring toward deeper insight, driving toward a deep model and supple design. The goal is a design that makes the model obvious, a model that expresses the domain simply. A deep model distills the most essential aspects of a domain into simple elements that can be combined to solve the important problems of the application.
精炼并不仅限于从整体上把领域中的一些部分从 CORE 中分离出来。它也意味着对子领域(特别是 CORE DOMAIN)进行精炼,通过持续重构得到更深层的理解,从而向深层模型和柔性设计推进。精炼的目标是把模型设计得更明显,使我们可以用模型简单地把领域表示出来。深层模型把领域中最本质的方面精炼成一些简单的元素,使我们可以把这些元素组合起来解决应用程序中的重要问题。
Although a breakthrough to a deep model provides value anywhere it happens, it is in the CORE DOMAIN that it can change the trajectory of an entire project.
尽管任何带来深层模型的突破都有价值,但只有 CORE DOMAIN 中的突破才能改变整个项目的轨道。
When you encounter a large system that is poorly factored, where do you start? In the XP community, the answer tends to be either one of these:
当你遇到一个杂乱无章的大型系统时,应该从哪里入手呢?在 XP 社区中,答案往往是以下之一:
- Just start anywhere, because it all has to be refactored.
- Start wherever it is hurting. I’ll refactor what I need to in order to get my specific task done.
- 可以从任何地方开始,因为所有的东西都要进行重构;
- 从影响你工作的那部分开始——也就是完成具体任务所需要的那个部分。
I don’t hold with either of these. The first is impractical except in a few projects staffed entirely with top programmers. The second tends to pick around the edges, treating symptoms and ignoring root causes, shying away from the worst tangles. Eventually the code becomes harder and harder to refactor.
这两种做法我都不赞成。第一种做法并不十分可行,只有少数完全由顶尖的程序员组成的团队才是例外。第二种做法往往只是对外围问题进行了处理,只治其标而不治其本,回避了最严重的问题。最终这会使代码变得越来越难以重构。
So, if you can’t do it all, and you can’t be pain-driven, what do you do?
因此,如果你既不能全面解决问题,又不能“哪儿痛治哪儿”,那么该怎么办呢?
- In a pain-driven refactoring, you look to see if the root involves the CORE DOMAIN or the relationship of the CORE to a supporting element. If it does, you bite the bullet and fix that first.
- When you have the luxury of refactoring freely, you focus first on better factoring of the CORE DOMAIN, on improving the segregation of the CORE, and on purifying supporting subdomains to be GENERIC.
- 如果采用“哪儿痛治哪儿”这种重构策略,要观察一下根源问题是否涉及 CORE DOMAIN 或 CORE 与支持元素的关系。如果确实涉及,那么就要接受挑战,首先修复核心。
- 当可以自由选择重构的部分时,应首先集中精力把 CORE DOMAIN 更好地提取出来,完善对 CORE 的分离,并且把支持性的子领域提炼成通用子领域。
This is how to get the most bang for your refactoring buck.
以上就是如何从重构中获取最大利益的方法。