Books - Domain-Driven Refactoring - 1

This is where Domain-Driven Design (DDD) steps in. Since its introduction by Eric Evans in 2003, DDD has served as a transformative approach for designing software systems that reflect the intricacies of real-world domains. The approach offers strategies for modeling complexity, structuring applications, and enabling effective collaboration between technical and business teams. This book is our contribution to the rich ecosystem of DDD knowledge, aiming to guide you through the principles, patterns, and practices that make DDD not just a philosophy but a practical toolset for modern software development.
这就是领域驱动设计(DDD)发挥作用的地方。自从 2003 年由埃里克·埃文斯(Eric Evans)提出以来,DDD 已成为一种变革性的方法,用于设计能够反映现实世界领域复杂性的软件系统。该方法提供了建模复杂性、构建应用程序以及促进技术团队与业务团队之间有效协作的策略。这本书是我们对 DDD 知识丰富生态系统的贡献,旨在引导你了解 DDD 的原则、模式和最佳实践,使 DDD 不仅是一种理念,更成为现代软件开发实用的工具集。
Who this book is for
* Developers who want to move beyond coding and understand how to design systems that solve real-world problems effectively
想要超越编程,并了解如何设计能够有效解决实际问题的系统的开发者
* Architects tasked with creating modular, maintainable, and scalable solutions in increasingly complex environments
负责在日益复杂的环境中创建模块化、可维护和可扩展解决方案的架构师
* Technical leaders who seek to foster collaboration between cross-functional teams and ensure that technical decisions support business goals
寻求促进跨职能团队协作并确保技术决策支持业务目标的技术领导者
Chapter 1, Evolution of Domain-Driven Design
Since the birth of software development in the 1960s, developers strived to create better applications to deal with the complexity of the world. During the following 20 years, many reports emerged pointing out the inefficiency of software systems and their design processes. We also went through the infamous software crisis that led to many incidents, such as the Therac-25 (https://en.wikipedia.org/wiki/Therac-25).
自 1960 年代软件开发诞生以来,开发者们一直努力创造更好的应用程序来应对世界的复杂性。在接下来的 20 年里,许多报告指出软件系统及其设计过程的低效。我们还经历了臭名昭著的软件危机,导致了许多事件,例如 Therac-25(https://en.wikipedia.org/wiki/Therac-25)。
The turning point arrived in 1968 during the NATO conference where the issue was acknowledged, and people started laying the groundwork for software engineering as a formal discipline (https://docslib.org/doc/9230794/crisis-what-crisis-reconsidering-the-software-crisis-of-the-1960s-and-the-origins-of-software-engineering).
转折点发生在 1968 年的北约会议上,当时这个问题被承认,人们开始为软件工程作为一个正式学科奠定基础(https://docslib.org/doc/9230794/crisis-what-crisis-reconsidering-the-software-crisis-of-the-1960s-and-the-origins-of-software-engineering)。
Progression of the software development approaches
Between the 1980s and 1990s, the awareness of the software crisis led to the rise of various “silver-bullet” approaches that did not, however, provide a definitive solution. The famous article, No Silver Bullets, written by Fred Brooks, took the problem head-on and brought to the attention of the reader that there are mainly two different kinds of complexity; essential and accidental (you will read in depth about them in Chapter 2).
在 20 世纪 80 年代至 90 年代,人们对软件危机的认识导致了各种“银弹”方法的出现,然而这些方法并没有提供确切的解决方案。弗雷德·布鲁克斯撰写的著名文章《没有银弹》直面了这一问题,并将两种主要类型的复杂性——本质性和偶然性——呈现在读者面前(你将在第 2 章深入阅读它们)。
In Steve McConnell’s book, Software Estimation: Demystifying the Black Art, there is a really interesting concept called “cone of uncertainty,” which exposes part of the problem with a simple diagram (Figure 1.1). This diagram points out that estimates created early in the project are subject to a high degree of error. As you can see, these estimates can be off by a factor of four both in high and lower ends. The application of this concept was in the estimate process, but it maps very well to the problem that DDD tries to solve. A deep understanding of the domain leads to stronger models, greater project resilience, and more accurate estimates. This could be only obtained by investing time in understanding the problem. As also stated in the book itself,”The reason the estimate contains variability is that the software project itself contains variability.”
在 Steve McConnell 的书中《软件估算:揭秘黑色艺术》,有一个非常有趣的概念叫做“不确定性锥”,它通过一个简单的图表(图 1.1)揭示了问题的一部分。这个图表指出,项目早期创建的估算会存在高度误差。如您所见,这些估算在高端和低端都可能相差四倍。这个概念的应用是在估算过程中,但它与 DDD 试图解决的问题非常契合。对领域的深入理解会带来更强的模型、更高的项目弹性和更准确的估算。这只能通过投入时间来理解问题才能获得。正如书中自己所说,“估算包含变异性是因为软件项目本身包含变异性。”
As a result of this awareness, as predicted by F. Brooks, and the evolution of development methods, such as object-oriented programming, we assisted in the rise of new development tools called RAD (e.g., Delphi, Visual Basic, Paradox, Visual FoxPro), which provided solutions to the accidental complexity of the problem, while still leaving room for improvement to essential complexity.
由于这种意识,正如 F.布鲁克斯所预测的,以及开发方法的演变,例如面向对象编程,我们协助推动了称为 RAD(例如 Delphi、Visual Basic、Paradox、Visual FoxPro)的新开发工具的兴起,这些工具为问题的偶然复杂性提供了解决方案,同时仍为本质复杂性留下了改进空间。
What he realized was that the traditional approach in software design was focused on translating the complexity of the business flows with just technical solutions (DB first, anyone?).
他所意识到的是,传统的软件设计方法专注于用技术解决方案来翻译业务流程的复杂性(DB 优先,对吧?)。
His proposal was to first do a deep exploration and modeling of the problem space (we will delve into it in Chapter 2) and only then try to find an acceptable solution. This approach could only be achieved by involving a continuous collaboration between developers and domain experts.
他的提议是首先进行深入的问题空间探索和建模(我们将在第 2 章中深入探讨),然后才能尝试找到一个可接受的解决方案。这种方法的实现只能通过开发者和领域专家之间的持续合作来完成。
What is domain-driven design (DDD)?
First, we can say what DDD is not. It is not a framework, or a library, to be installed on our computers to guide us in the development of software systems.
At the heart of DDD are two interconnected principles: ubiquitous language and bounded context.
DDD 的核心是两个相互关联的原则:通用语言和边界上下文。
Ubiquitous language is a shared vocabulary consistently used by all stakeholders, including domain experts, developers, and business teams. It eliminates ambiguities in communication, ensuring that everyone involved speaks the same language when discussing the domain. This shared understanding directly influences the accuracy and clarity of the software model, aligning it closely with the business domain.
通用语言是所有利益相关者(包括领域专家、开发人员和业务团队)一致使用的共享词汇。它消除了沟通中的歧义,确保在讨论领域时,所有参与者使用同一种语言。这种共同的理解直接影响软件模型的准确性和清晰度,使其与业务领域紧密对齐。
Bounded context defines the boundaries within which a specific domain model and its associated ubiquitous language apply. These boundaries prevent overlaps or inconsistencies between different parts of a system, enabling teams to work independently within their assigned contexts. This modular approach simplifies the management of complex systems and ensures that changes within one context do not unintentionally affect others.
限界上下文定义了特定领域模型及其相关通用语言的适用边界。这些边界防止系统不同部分之间出现重叠或不一致,使团队能够在其分配的上下文中独立工作。这种模块化方法简化了复杂系统的管理,并确保一个上下文中的变更不会无意中影响其他上下文。
As an example, you can think of the game that many Agile coaches use, the broken telephone. The game points out how with each hand-off of information from one person to another, the information is always altered due to the interpretation of each individual.
例如,你可以想到许多敏捷教练使用的游戏——传话游戏。这个游戏指出了信息在从一个人传递到另一个人时,由于每个人的解释,信息总是会被改变。
In human conversations, context is naturally developed as people engage in dialog. When someone enters the discussion midway, they often ask, “Who or what are you talking about?” rather than directly inquiring, “What is the context?”
在人类对话中,随着人们的互动,语境会自然地形成。当有人中途加入讨论时,他们通常会问“你们在谈论谁或什么?”而不是直接询问“背景是什么?”
Without context, meaning can be ambiguous, distorted, or even completely lost. A lack of context when joining a conversation can lead to misunderstandings, as the newcomer may make incorrect assumptions about the subject at hand. Similarly, an abstraction can only be as accurate as the shared understanding of the context among all participants in the communication.
没有上下文,意义可能变得模糊、扭曲,甚至完全丢失。在加入对话时缺乏上下文会导致误解,因为新人可能会对所讨论的主题做出错误的假设。同样,一个抽象只能精确到所有沟通参与者对上下文共享理解的程度上。
As stated before, one of the main goals of DDD is to reduce as much as possible this phenomenon by establishing a common language to make explicit the implicit.
如前所述,领域驱动设计的一个主要目标是通过建立共同语言来尽可能减少这种现象,使隐含的内容显式化。
Communication is key to understanding the problem we need to solve. DDD wants to be an alternative to an anemic list of requirements and delivery of the software. This can be achieved by starting by trying to understand the problem instead of defining a list of requirements. We should not start with one, or more, ready-made solutions, because requirements are in fact a solution to the problem and are given to us at the beginning of the project exactly when we do not know anything about the domain. This means that we are unable to clearly understand whether they really are the solution or not. Requirements capture a stakeholder’s perspective of the system at a particular point in time and are subject to change.
沟通是理解我们需要解决的问题的关键。领域驱动设计(DDD)旨在成为一份贫血的需求列表和软件交付的替代方案。这可以通过从尝试理解问题开始,而不是定义一份需求列表来实现。我们不应该从一个或多个现成的解决方案开始,因为需求实际上是问题的解决方案,而我们是在项目开始时对领域一无所知的情况下得到这些需求的。这意味着我们无法清楚地理解它们是否真的是解决方案。需求捕捉了利益相关者在特定时间点对系统的视角,并且可能会发生变化。
DDD aims to help create software more aligned with the business goals, more adaptable to change, and easier to maintain over time. To ease the conversation, DDD focuses on the business domain, so it is necessary to clarify its meaning right from the start.
领域驱动设计旨在帮助创建更符合业务目标、更能适应变化、且更易于长期维护的软件。为了简化讨论,领域驱动设计聚焦于业务领域,因此有必要从一开始就明确其含义。
What you will do, exactly, is better understand the business domain, which is the main area of activity of our brewery, and refactor your way toward a more resilient and scalable application using baby steps instead of a “big bang change” (or nuclear option, as we call it).
你将要做的是更深入地理解业务领域,这是我们啤酒厂的主要活动领域,并使用小步快跑的方式而不是“大爆炸式变革”(或如我们所说的“核选项”)来重构,从而构建一个更具弹性和可扩展性的应用程序。
Now that we know what “domain” is, why “driven”? By the book, the term implies that the design of the software is guided by someone or something. In our case, it is based on a deep understanding of the domain, and only after understanding a domain, we’ll introduce technical considerations or implementation details.
现在我们已经知道“领域”是什么,为什么是“驱动”?根据书中的解释,这个术语意味着软件的设计是由人或某种事物引导的。在我们的情况下,它是基于对领域的深刻理解,只有理解了领域之后,我们才会引入技术考虑或实现细节。
Finally, “design” simply refers to the process of creating a solution.
最后,“设计”仅仅指的是创建解决方案的过程。
Refactoring is a crucial part of the DDD approach. It involves restructuring existing code without changing its external behavior to improve nonfunctional attributes. In the context of DDD, refactoring is not just about code; it’s about refining the model to better reflect the domain as your understanding deepens.
重构是领域驱动设计方法的关键部分。它涉及在不改变外部行为的情况下重新组织现有代码,以改善非功能性属性。在领域驱动设计的背景下,重构不仅仅是关于代码;它还关乎随着你对领域理解的深入,不断优化模型以更好地反映领域。
This continuous alignment of the software model with the evolving understanding of the business domain is one of the key principles of DDD. Regularly revisiting and refining the model ensures it accurately represents the current state of the domain. This iterative process of refining and improving the model is where refactoring comes into play.
将软件模型与不断发展的业务领域理解持续对齐是领域驱动设计的关键原则之一。定期回顾和优化模型可以确保它准确反映领域的当前状态。这种不断优化和改进模型的过程就是重构发挥作用的地方。
In practice, refactoring with DDD involves several steps:
在实践中,使用领域驱动设计进行重构涉及多个步骤:
1. Understanding the Domain: Before any refactoring, you need a deep understanding of the business domain. Engage with domain experts to gather insights and ensure the model accurately reflects the domain knowledge.
理解领域:在进行任何重构之前,你需要深入理解业务领域。与领域专家合作,收集见解,并确保模型准确反映领域知识。
2. Identifying Areas for Improvement: Look for parts of the code where the domain model is not well represented or where technical debt has accumulated. These are prime candidates for refactoring.
识别改进区域:寻找代码中领域模型未能良好表示或技术债务累积的部分。这些是重构的首选目标。
3. Applying DDD Patterns: Use DDD patterns, such as aggregates, entities, value objects, and services, to restructure the code. Ensure that these patterns are applied in a way that enhances the clarity and integrity of the domain model.
应用 DDD 模式:使用 DDD 模式,如聚合、实体、值对象和服务,来重构代码。确保这些模式的应用方式能够增强领域模型的清晰性和完整性。
4. Maintaining Functionality: Refactor in small steps to ensure that the system remains functional throughout the process. Use automated tests to verify that existing functionality is preserved.
保持功能:小步进行重构,确保整个过程中系统保持功能。使用自动化测试来验证现有功能是否得到保留。
5. Continuous Integration: Integrate changes frequently to catch issues early and ensure that the refactored code works well with the rest of the system.
持续集成:频繁集成变更,以便尽早发现问题,并确保重构的代码与系统的其他部分良好协作。
6. Feedback Loop: Regularly review the changes with domain experts to ensure that the refactoring aligns with their understanding of the domain. Use their feedback to further refine the model.
反馈循环:定期与领域专家审查变更,以确保重构与他们对领域的理解保持一致。使用他们的反馈来进一步优化模型。
This iterative process ensures that the software remains adaptable to changes in business requirements and it is easier to maintain and extend over time.
这种迭代过程确保软件能够适应业务需求的变化,并且随着时间的推移更容易维护和扩展。
How DDD changes the approach to the problem
DDD fundamentally transforms the approach to software development by placing the business domain at the heart of the development process. Traditional software development methodologies often start with technical considerations, such as data modeling, database design, or user interface wireframes.
领域驱动重构从根本上转变了软件开发方法,将业务领域置于开发过程的核心。传统的软件开发方法论通常从技术考虑开始,例如数据建模、数据库设计或用户界面线框图。
While these aspects are essential, DDD shifts the focus from technical priorities to aligning software design with fundamental business concepts, resulting in more relevant, flexible, and maintainable systems.
虽然这些方面至关重要,但领域驱动设计将重点从技术优先级转移到使软件设计与基本业务概念保持一致,从而产生更相关、更灵活且更易于维护的系统。
DDD emphasized the importance of explicitly defining context to ensure the precise interpretation of an abstraction. It advocates for a mindset shift where the primary focus is the alignment between all the members of the team and avoiding misunderstanding. This is one of the primary ways DDD is used to change the approach to problem-solving. This common language is something shared between the stakeholders, domain experts, developers, and end users and is as strict as a programming language. The good thing is that it is a vocabulary that is understood by each party and its consistent use allows every team member to easily refactor parts of the code that do not align with business requirements. It also strongly reduces misunderstandings and ensures that the code base evolves in harmony with the business.
领域驱动设计强调明确定义上下文以确保抽象的精确解释。它提倡思维方式的转变,主要关注团队所有成员之间的对齐并避免误解。这是领域驱动设计用来改变问题解决方法的主要方式之一。这种通用语言是利益相关者、领域专家、开发人员和最终用户共享的,其严格程度不亚于编程语言。好的方面在于,这是一种被各方理解的词汇,其一致使用使每个团队成员能够轻松地重构与业务需求不一致的代码部分。它还大大减少了误解,并确保代码库与业务和谐发展。
DDD encourages developers to immerse themselves in domain knowledge and collaborate closely with domain experts (e.g., business analysts, end users, etc.). This deep exploration of the domain allows developers to gain a comprehensive understanding of the concepts, rules, processes, and behaviors that govern the real-world problem space. Obviously, this is not something that is achieved easily, but requires exploration and experimentation with several iterations with a lot of the time spent, as we will see in the next chapter, in what is called the problem space.
领域驱动设计鼓励开发者深入领域知识,并与领域专家(例如业务分析师、最终用户等)紧密合作。这种对领域的深入探索使开发者能够全面理解支配现实问题领域概念、规则、流程和行为。显然,这不是一件容易实现的事情,而是需要通过多次迭代进行探索和实验,花费大量时间,正如我们将在下一章看到的,在所谓的“问题领域”中。
Just as in human conversations, fully grasping a model requires establishing the appropriate context and clear boundaries. A model, as we have noted, is a structured system of abstractions. Beware that a model remains an oversimplification of reality as defined by Rebecca Wirfs-Brock (https://weave-it.org/blog/overcoming-additive-bias-software-design):
就像人类对话一样,要完全理解一个模型,需要建立适当的背景并明确界限。正如我们所指出的,模型是一个抽象的结构化系统。要小心,模型仍然是现实的一种过度简化,正如 Rebecca Wirfs-Brock 所定义的(https://weave-it.org/blog/overcoming-additive-bias-software-design):
A model is a simplified representation of a thing or phenomenon that intentionally emphasizes certain aspects while ignoring others. Abstraction with a specific use in mind.
模型是对事物或现象的简化表示,它有意强调某些方面而忽略其他方面。具有特定用途的抽象。
These contexts help manage the complexity of large software systems by allowing different parts of the system to evolve independently. Each bounded context contains its own domain model, which is consistent and isolated from other contexts. This modularization is crucial for refactoring as it allows changes to be made within one context without impacting others, thus reducing the risk of introducing errors and improving the system’s overall maintainability.
这些上下文通过允许系统的不同部分独立演进来帮助管理大型软件系统的复杂性。每个限界上下文都包含其自己的领域模型,该模型是一致的,并且与其他上下文隔离。这种模块化对于重构至关重要,因为它允许在一个上下文中进行更改而不影响其他上下文,从而降低引入错误的风险并提高系统的整体可维护性。
In addition to bounded contexts, DDD leverages tactical patterns such as entities, value objects, aggregates, repositories, and services. These patterns provide a structured approach to encapsulating domain logic, ensuring that changes can be implemented cleanly and systematically. For example, entities represent objects that have a distinct identity and life cycle, while value objects encapsulate attributes and behaviors without identity. Aggregates are clusters of related entities and value objects that are treated as a single unit for data changes, ensuring consistency and integrity within the model.
除了限界上下文,领域驱动设计(DDD)还利用战术模式,如实体、值对象、聚合、存储库和服务。这些模式为封装领域逻辑提供了一种结构化的方法,确保变更可以清晰且系统地实施。例如,实体表示具有独特身份和生命周期的对象,而值对象则封装属性和行为但不具有身份。聚合是相关实体和值对象的集群,它们被视为一个单一单元进行数据变更,确保模型内部的一致性和完整性。
Repositories abstract the data access layer, providing a clean interface for storing and retrieving aggregates. As described in Martin Fowler’s book, Patterns of Enterprise Application Architecture, (https://martinfowler.com/eaaCatalog/repository.html) a repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection.
仓库抽象了数据访问层,为存储和检索聚合提供了清晰的接口。正如在马丁·福勒的《企业应用架构模式》一书中所述(https://martinfowler.com/eaaCatalog/repository.html),仓库在领域层和数据映射层之间进行中介,类似于内存中的领域对象集合。
Domain services encapsulate domain logic that does not naturally fit within an aggregate, promoting a clear separation of concerns. Its main use is to coordinate one or more aggregates removing as much as possible the coupling between them.
领域服务封装不适合聚合内的领域逻辑,促进关注点的清晰分离。其主要用途是协调一个或多个聚合,尽可能减少它们之间的耦合。
These patterns not only facilitate cleaner and more maintainable code but also make it easier to refactor and extend the system in response to the ever-changing business requirements.
这些模式不仅有助于编写更清晰、更易于维护的代码,还使得根据不断变化的业务需求重构和扩展系统变得更加容易。
Furthermore, DDD encourages iterative development and continuous refactoring. This iterative process allows teams to incrementally improve the system, making small, manageable changes that collectively lead to significant enhancements in the code base’s quality and functionality. These concepts do not apply to a green field project but are also true for the refactoring of a legacy system.
此外,领域驱动设计鼓励迭代开发和持续重构。这种迭代过程允许团队逐步改进系统,通过进行小而可控的变更,共同提升代码库的质量和功能。这些概念不仅适用于绿色田野项目,也适用于遗留系统的重构。
To close, by placing the domain at the center of the design process, DDD helps bridge the gap between the technical and business perspectives. As already stated, it significantly changes the approach to problem-solving in software development by prioritizing a deep understanding of the business domain, fostering clear communication through a ubiquitous language, and structuring the system using bounded contexts and well-defined design patterns. This methodology not only makes the refactoring process more efficient and effective but also ensures that the software evolves in alignment with the business’s needs, resulting in more robust and maintainable systems.
最后,通过将领域置于设计过程的核心,领域驱动设计有助于弥合技术和业务视角之间的差距。如前所述,它通过优先理解业务领域、通过通用语言促进清晰沟通,以及使用限界上下文和明确定义的设计模式来构建系统,从而显著改变软件开发中的问题解决方法。这种方法论不仅使重构过程更加高效和有效,而且确保软件与业务需求保持一致,从而产生更健壮和可维护的系统。
In conclusion, DDD transforms refactoring by prioritizing domain understanding and communication, leading to more intuitive, business-aligned, and resilient software solutions.
总之,领域驱动设计通过优先考虑领域理解和沟通,转变了重构,从而带来了更直观、与业务一致且更具弹性的软件解决方案。
Chapter 2, Understanding Complexity: Problem and Solution Space
In the previous chapter, we went through the history of DDD and what it tries to solve. We also started to talk about the need to explore the domain, improve our knowledge of it, and find solutions in an iterative way. In this chapter, we will delve into problem and solution spaces, and by the end of it, you will have a clear understanding of their importance not only when approaching a greenfield project but also when refactoring one that already exists. Such a project may already be drifting away with useless features or complexity that do not represent the business anymore. You have probably seen many such types of projects that try to solve problems they themselves create, rather than adding value for the user.
在上一章中,我们回顾了领域驱动设计的历程及其试图解决的问题。我们还开始讨论探索领域、提升对领域的认知以及以迭代方式寻找解决方案的必要性。在本章中,我们将深入探讨问题与解决方案空间,到本章结束时,你将清晰地理解它们在处理新项目以及重构现有项目时的重要性。这样的项目可能已经因无用的功能或不再代表业务的复杂性而偏离轨道。你很可能见过许多此类项目,它们试图解决自己创造的问题,而不是为用户增加价值。
We will explore the intricate nature of modern complex systems and how to navigate their inherent complexity. Understanding these concepts is a fundamental skill for DDD as it allows us to deconstruct and manage the various components that define your system.
我们将探讨现代复杂系统的复杂性质以及如何驾驭其固有复杂性。理解这些概念是领域驱动设计的核心技能,因为它使我们能够分解和管理定义你系统的各个组件。
Specifically, we’ll cover the following main topics in this chapter:
在本章中,我们将具体涵盖以下主要主题:
* Dealing with complexity  处理复杂性
* Problem and solution space
问题和解决方案空间
* Decision-making and biases
决策与偏见
Dealing with complexity  处理复杂性
One of the best things about the nineties was that you could deploy new versions of systems with ease. When you were ready, you simply took down the application, upgraded it, and then put it back online. The same was true for our awesome SQL scripts that updated the DB in one fell swoop and, until the end of the nineties, most systems were deployed this way.
九十年代最棒的事情之一是你可以轻松部署新版本的系统。当你准备好了,只需关闭应用程序,进行升级,然后重新上线。对于我们的强大 SQL 脚本也是如此,它们能一次性更新数据库,直到九十年代末,大多数系统都是这样部署的。
These days, you can no longer afford to do this anymore because you do not have the luxury of being able to take down all the components of a system and upgrade them all at once. You must take into account that different teams are working on different components at different speeds, and there could be a lot of DBs that need to be kept somewhat aligned. What we are trying to say here is that the main reason this is not an acceptable way of doing things anymore is because at the root of everything lies complexity. Modern systems are so big and complicated that complexity itself is an inherent characteristic. No matter what you are dealing with, complexity arises from various sources—such as the sheer number of components, their interdependencies, and the dynamic nature of their interactions.
如今,你再也负担不起这种方式了,因为你没有奢侈到可以一次性关闭系统所有组件并进行升级的条件。你必须考虑到不同团队在不同速度下工作在不同组件上,而且可能有很多数据库需要保持一定程度的同步。我们想说的是,这种做法不再可接受的主要原因在于,一切的根本在于复杂性。现代系统如此庞大和复杂,以至于复杂性本身已成为其固有特性。无论你处理什么,复杂性都源于各种因素——比如组件数量之多、它们之间的相互依赖性以及它们交互的动态性质。
Understanding complexity involves recognizing its multifaceted nature and can be classified into two main types: essential complexity and accidental complexity. Essential complexity is intrinsic to the problem domain and cannot be removed. It is the complexity that arises from the nature of the problem itself. For example, the complexity of a financial trading system is inherent due to the numerous rules, regulations, and market conditions it must adhere to.
理解复杂性涉及认识到其多面性,可分为两种主要类型:本质复杂性和偶然复杂性。本质复杂性是问题域固有的,无法消除。它是源于问题本身的复杂性。例如,金融交易系统的复杂性是固有的,因为它必须遵守众多规则、法规和市场条件。
Accidental complexity, on the other hand, stems from the solution domain. It is the unnecessary complexity introduced by poor design decisions, inefficient processes, or inadequate tools. Reducing accidental complexity is mandatory for managing and simplifying systems.
另一方面,偶然复杂性源于解决方案域。它是由于糟糕的设计决策、低效的流程或不足的工具引入的不必要复杂性。减少偶然复杂性对于管理和简化系统是必要的。
Figure 2.1 is a summary of the key points to classify complexity.
图 2.1 是对分类复杂性的关键点的总结。
Figure 2.1 – Key points when dealing with complexity
As we can see in Figure 2.1, there is a lot to take into consideration when dealing with complexity, but do not worry; we have tools created by very smart people that can help us tackle it.
如图 2.1 所示,处理复杂性时需要考虑很多因素,但不必担心;我们拥有由非常聪明的人创造的工具,可以帮助我们应对它。
One of the first tools we would like to introduce to you is the Cynefin framework (https://en.wikipedia.org/wiki/Cynefin_framework).
我们想要介绍给你们的第一个工具是 Cynefin 框架(https://en.wikipedia.org/wiki/Cynefin_framework)。
Cynefin framework  Cynefin 框架
The Cynefin framework was developed by Dave Snowden in 1999, and its name, pronounced /kəˈnɛvɪn/ kuh-NEV-in, is a Welsh word that means “habitat.” We can sum it up by saying that it is a sense-making device that helps individuals and organizations understand and navigate complexity. Figure 2.2 shows the Cynefin template.
Cynefin 框架由 Dave Snowden 于 1999 年开发,其名称发音为/kəˈnɛvɪn/ kuh-NEV-in,是一个威尔士语词汇,意为“栖息地。”我们可以将其总结为一种帮助个人和组织理解与导航复杂性的认知工具。图 2.2 展示了 Cynefin 模板。
As we can see in Figure 2.2, the framework categorizes situations into five distinct contexts.
如图 2.2 所示,该框架将情境分为五个不同的背景。
Clear context  清晰背景
Clear context represents the “known knowns.” This means that the relationship between cause and effect requires analysis or expertise but is still predictable. Best practices or well-defined rules are already in place. In this situation, the advice is to “sense–categorize–respond”: first, establish the facts (“sense”), then categorize them, and finally, respond by following the rules or applying the best practices. Here, the DDD strategic patterns are useless because we already have a clear vision of the domain and so we can move directly to implementing tactical patterns.
清晰背景代表“已知已知”。这意味着因果关系需要分析或专业知识,但仍然是可预测的。最佳实践或明确定义的规则已经存在。在这种情况下,建议是“感知-分类-响应”:首先,建立事实(“感知”),然后对它们进行分类,最后通过遵循规则或应用最佳实践来响应。在这里,领域驱动设计(DDD)战略模式是无用的,因为我们已经对领域有清晰的认识,因此可以直接进入战术模式的实施。
Complicated context  复杂的背景
Complicated context represents the “known unknowns”—situations where the relationship between cause and effect requires analysis or expertise but it is still predictable. Good practice and expert advice are applicable. As we can see in Figure 2.2, the framework suggests “sense–analyze–respond”: assess the facts, analyze, and apply the appropriate good operating practice. In this specific domain, strategic and tactical patterns are essential to increase its understanding and start moving to a clear context.
复杂的背景代表了“已知的未知”——那些因果关系需要分析或专业知识才能理解,但仍然可以预测的情况。良好的实践和专家建议都适用。如图 2.2 所示,该框架建议“感知-分析-响应”:评估事实,分析,并应用适当的良好操作实践。在这个特定领域,战略和战术模式对于提高其理解并开始转向清晰的背景至关重要。
Complex context  复杂上下文
Complex context represents the “unknown unknowns.” As it were, it is when cause and effect are deducible only in retrospect, there are no right answers, and patterns emerge through interaction. Emergent practices are needed here. “Probe–sense–respond” takes place: small-scale experiments (“probe”) to explore the space and generate data, sense the results, and respond with actions. Strategic patterns with explorative tools come to the rescue to help us root a better vision and comprehension of this context. Tactical patterns are useless here.
复杂的背景代表了“未知的未知”。换言之,当因果关系只能事后推论,没有正确答案,模式通过互动出现时,就是这种情况。这里需要涌现的实践。“探测-感知-响应”发生:小规模的实验(“探测”)来探索空间和生成数据,感知结果,并采取行动做出响应。具有探索工具的战略模式来帮助我们扎根对这个背景更好的愿景和理解。战术模式在这里毫无用处。
Chaotic context  混乱的上下文
In a chaotic context situation, cause and effect are unclear because there is no clear relationship, and immediate action is required to stabilize the situation. We must “act–sense–respond”: act to establish order, sense where stability lies, and respond to try to turn a chaotic context into a complex context. Novel practices emerge. In this specific context, the pattern of DDD does not help, but we should use other exploration tools to give us a starting point on which we could start to apply strategic patterns.
在混乱的上下文情况下,因果关系不明确,因为没有明确的关系,需要立即采取行动来稳定局势。我们必须“行动—感知—回应”:行动以建立秩序,感知稳定所在,回应以尝试将混乱的上下文转变为复杂的上下文。新的实践会出现。在这种特定情况下,DDD 的模式没有帮助,但我们应使用其他探索工具来给我们一个起点,我们可以从那里开始应用战略模式。
Confusion context  困惑情境
The confusion context is in the center of Figure 2.2 and represents situations where there is no clarity about which of the other contexts apply. As written by Snowden and Boone in their article A Leader’s Framework for Decision Making (https://strategicleadership.com.au/wp-content/uploads/2017/06/A-Leader%E2%80%99s-Framework-for-Decision-Making-HBR-Nov-2007.pdf): “Here, multiple perspectives jostle for prominence, factional leaders argue with one another, and cacophony rules.”
混淆上下文位于图 2.2 的中心,它代表那些对其他适用上下文缺乏明确性的情况。正如斯诺登和博恩在他们的文章《领导者的决策框架》(https://strategicleadership.com.au/wp-content/uploads/2017/06/A-Leader%E2%80%99s-Framework-for-Decision-Making-HBR-Nov-2007.pdf)中所写:“在这里,多种视角争相突出,派系领导者相互争论,嘈杂声主导一切。”
Table 2.1 summarizes when we should use strategic, tactical, and explorative patterns.
表 2.1 总结了何时应使用战略、战术和探索性模式。
To conclude with a practical example, let us look at the one given by the author himself in 2007. It refers to an incident that happened in 1993 at the Brown’s Chicken and Pasta restaurant in Palatine, Illinois. A shooter murdered seven employees, and as a result, Deputy Police Chief Walt Gasior had to deal with a situation in which the local police faced all the domains. He had to act immediately to manage the initial panic (chaotic), keep the department running by following standard procedures (simple), ask for expert help (complicated), and keep the community calm in the following weeks (complex).
以一个实际案例来总结,让我们看看作者自己在 2007 年给出的那个例子。它指的是 1993 年在伊利诺伊州帕拉丁的布朗鸡肉面馆发生的一起事件。一名枪手杀害了七名员工,结果,副警察局长沃尔特·加西奥尔不得不处理一个当地警察面临所有领域的局面。他必须立即行动,管理最初的恐慌(混乱),通过遵循标准程序(简单)使部门继续运作,请求专家帮助(复杂),并在接下来的几周内保持社区平静(复杂)。
Residuality theory  剩余性理论
Another powerful tool we have in our toolbox is residuality theory (https://www.sciencedirect.com/science/article/pii/S1877050921007420). Formulated by Barry O’Reilly, it states that the future of a system is determined by its residues, which are the remnants left behind after the system has been affected by a stressor.
我们工具箱中的另一个强大工具是残余性理论(https://www.sciencedirect.com/science/article/pii/S1877050921007420)。该理论由巴里·奥赖利提出,它指出系统的未来由其残余性决定,而残余性是指系统在受到应激因素影响后留下的残留物。
Residuality theory is a pivotal concept in the realm of DDD, offering a structured approach to understanding and improving complex systems. At its core, residuality theory examines how a system retains its structure and behavior after being subjected to changes or disruptions, referred to as stressors.
残余性理论是领域驱动设计(DDD)中的一个关键概念,它提供了一种结构化的方法来理解和改进复杂系统。其核心在于,残余性理论研究系统在受到变化或干扰(称为压力源)后如何保持其结构和行为。
Imagine a legacy e-commerce platform that struggles to handle peak shopping seasons, such as Christmas or Black Friday. Each peak period acts as a stressor, revealing underlying issues such as slow performance or system crashes. By applying the residuality theory, we analyze these stress responses to identify persistent problems and areas resistant to change.
想象一个难以应对高峰购物季(如圣诞节或黑色星期五)的遗留电子商务平台。每个高峰期都充当一个压力源,暴露出潜在问题,如性能缓慢或系统崩溃。通过应用剩余性理论,我们分析这些压力响应,以识别持续存在的问题和难以改变的区域。
This method allows us to target refactoring efforts more effectively, ensuring that improvements address the root causes of system fragility. By refactoring this aspect, we enhance the system’s robustness, making it more resilient to future stressors. With this approach, we can better pinpoint which area of our system needs refactoring and design a system that gracefully adapts to evolving demands and challenges.
这种方法使我们能够更有效地定位重构工作,确保改进能够解决系统脆弱性的根本原因。通过重构这一方面,我们增强了系统的鲁棒性,使其更能抵抗未来的压力。采用这种方法,我们可以更准确地确定系统哪个部分需要重构,并设计出一个能够优雅地适应不断变化的需求和挑战的系统。
O’Reilly’s residuality theory presents a nuanced understanding of how systems evolve and sustain themselves through the continuous accumulation of past states and interactions. This theory wants to shift our perspective on change, suggesting that systems (what he calls naïve architectures) do not simply go through isolated, linear steps but are profoundly shaped by the “residue” that remains when facing changes. These residues are active, influential components that affect how systems adapt, resist, and evolve over time.
奥赖利残余性理论提出了一种细致入微的理解,即系统如何通过持续积累过去的状况和互动来演变并维持自身。这一理论试图转变我们对变化的认知,指出系统(他称之为天真架构)并非仅仅经历孤立、线性的步骤,而是深受面对变化时留下的“残余”的深刻影响。这些残余是活跃且具影响力的组成部分,它们影响着系统在时间中的适应、抵抗和演变。
To truly understand a system, one must consider these residuals, which manifest in various forms, such as legacy code in software, ingrained processes in organizations, or established cultural norms within communities. Each of these residues carries with it the weight of past decisions, interactions, and contexts, creating a complex web that influences current and future states. For example, in the realm of software development, understanding the intricacies of legacy code is essential for making informed decisions about future development and integrations.
要真正理解一个系统,就必须考虑这些残余,它们以多种形式显现,例如软件中的遗留代码、组织中根深蒂固的流程,或社区内形成的既定文化规范。这些每一项残余都承载着过去决策、互动和背景的重量,形成了一个复杂的网络,影响着当前和未来的状态。例如,在软件开发领域,理解遗留代码的复杂性对于就未来的开发和集成做出明智决策至关重要。
Residuality theory advocates for a holistic approach to change management and system design. It encourages us to look beyond immediate actions and outcomes and to consider the deeper, more persistent influences that shape a system’s behavior. By doing so, we can better predict potential challenges, identify areas of resistance, and develop strategies that are more aligned with the underlying reality of the system. This approach contrasts sharply with traditional models of change that often overlook the importance of historical context and residual effects, leading to strategies that may be effective in the short term but fail to sustain over time.
残余性理论提倡一种整体性的变革管理和系统设计方法。它鼓励我们超越眼前的行动和结果,去考虑那些塑造系统行为的更深层次、更持久的因素。通过这样做,我们能够更好地预测潜在挑战,识别阻力区域,并制定更符合系统深层现实状况的策略。这种做法与传统变革模型形成鲜明对比,后者往往忽视历史背景和残余效应的重要性,导致短期内有效的策略却无法持久。
In practical terms, applying residuality theory means engaging in a continuous process of reflection and analysis, where past experiences are not just acknowledged but are critically examined to understand their ongoing impact. This involves not only identifying the residues but also interpreting their significance and leveraging this understanding to inform future actions. For instance, in a business context, leaders might analyze past project failures and successes to identify persistent patterns that could influence current initiatives. In software development, teams might conduct thorough code reviews to understand how past coding practices and design decisions affect current performance and scalability.
在实际应用中,运用残余性理论意味着进行持续反思和分析的过程,不仅承认过去的经验,还要批判性地审
Stressors and refactoring
压力源与重构
A stressor, in the context of refactoring, is any external factor or event that places pressure on the system and tests its stability, performance, and resilience. As per the example before, this pressure can be caused by a spike in the number of users, unexpected behaviors, and network or hardware failures. These are practical tests that reveal the system’s weaknesses and bottlenecks. Do not equate this with Netflix’s Chaos Monkey though. You identify stressors with brainstorming sessions, analysis of the production system in its ecosystem, or by using random simulation.
在重构的语境中,压力源是指任何施加压力于系统并测试其稳定性、性能和弹性的外部因素或事件。以之前的例子为例,这种压力可能由用户数量激增、意外行为以及网络或硬件故障引起。这些都是实际的测试,可以揭示系统的弱点和瓶颈。但不要将其与 Netflix 的混沌猴等同起来。你可以通过头脑风暴会议、分析生产系统在其生态系统中的运行情况,或使用随机模拟来识别压力源。
Observing and analyzing how your system behaves under these stress scenarios allows you to gain critical insights into system weaknesses and bottlenecks. This understanding is crucial for effective refactoring, enhancing the system’s ability to handle future stressors, and improving overall robustness and reliability.
观察和分析系统在这些压力场景下的行为,可以帮助你深入了解系统的弱点和瓶颈。这种理解对于有效的重构至关重要,能够增强系统应对未来压力的能力,并提高整体稳健性和可靠性。
If you want to learn more on the topic, we suggest watching the speech O’Reilly gave at NDC Oslo in 2023 on YouTube (https://www.youtube.com/watch?v=0wcUG2EV-7E).
如果您想了解更多关于这个主题的内容,我们建议您观看 O'Reilly 在 2023 年 NDC 奥斯陆会议上发表的演讲(https://www.youtube.com/watch?v=0wcUG2EV-7E)。
EventStorming  事件风暴
Last but not least, we want to bring your attention to EventStorming (https://www.eventstorming.com/), a tool created by Alberto Brandolini. This tool is especially useful for the exploration of your domain and is different from other similar tools (i.e., domain storytelling). The idea behind it is quite simple; since your goal is to understand the complexity of the domain, bring all the interested parties, from domain experts to stakeholders, to the table and build a domain model together that is understandable to everyone. There is no single format for EventStorming; it is more of a family of workshops aimed at graphically representing the complexity of key information flows within organizations using events as an exploration tool. There are three main kinds of formats we can choose from, and every single one is specifically designed for different moments of exploration. Let’s go through them in the next sub-sections.
最后但同样重要的是,我们想将您的注意力引向由 Alberto Brandolini 创建的工具——事件风暴(https://www.eventstorming.com/)。这个工具特别适用于领域探索,并且与其他类似工具(例如领域故事讲述)有所不同。其背后的理念相当简单;由于您的目标是理解领域的复杂性,因此将所有利益相关者——从领域专家到利益相关者——召集到一起,共同构建一个每个人都能理解的领域模型。事件风暴没有单一的格式;它更像是一系列旨在使用事件作为探索工具,以图形方式表示组织内关键信息流复杂性的研讨会。我们可以从三种主要格式中选择,每一种都专门设计用于探索的不同阶段。让我们在下一节中逐一介绍它们。
Big picture  大局
When you must deal with the refactoring of a code base, you need to understand what this solution solves, and you need to talk to all the stakeholders of the project, all the businesspeople, and all the developers. The goal is to build a model that represents the flow of all data in your domain. Everything starts by hanging a sheet of paper on the wall, typically 10-15 meters in length (but it usually grows a lot more), and applying fundamental ingredients on it—orange sticky notes. These notes represent events that occur in the domain, and, usually, after a couple of hours of discussions and writing of orange stickies, you will see that processes start to emerge on the wall as a flow represented by all the orange sticky notes. From here, you will be able to start exploring with the stakeholders the different ways in which they perceive the same problem.
当你必须处理代码库的重构时,你需要理解这个解决方案解决了什么问题,并且需要与项目的所有利益相关者、所有业务人员以及所有开发人员沟通。目标是构建一个能够代表你领域内所有数据流的模型。一切始于在墙上挂一张纸,通常长度为 10-15 米(但它通常会增长得更多),并在上面应用基本元素——橙色便利贴。这些便利贴代表领域中发生的事件,通常经过几个小时讨论和书写橙色便利贴后,你会发现墙上开始显现出流程,这些流程由所有的橙色便利贴表示。从这里开始,你将能够与利益相关者一起探索他们看待同一问题的不同方式。
In this phase, it is important to understand whether these ways are simply different in solving the problem or whether each stakeholder has a different point of view on it. You will end up with a defined common language between developers, business experts, and stakeholders. Figure 2.3 shows an example of events in an EventStorming session with added notes about topics that must be covered during the detailed analysis of the flow. The scope of the big picture is to highlight the main events and potential pain points throughout the business flow.
在这个阶段,重要的是要理解这些方法是否仅仅是解决问题的不同方式,还是每个利益相关者对它有不同的观点。最终,你将定义开发人员、业务专家和利益相关者之间的共同语言。图 2.3 展示了一个 EventStorming 会议中的事件示例,并添加了在流程的详细分析中必须涵盖的主题的注释。大局的范围是突出整个业务流程中的主要事件和潜在痛点。
Process modeling  过程建模
In this case, the scope of the exploration is more limited, and so is the team dimension. You need to create a space in which each stakeholder can contribute to creating the model, and for this reason, you cannot use tools such as UML, otherwise, only developers could participate, or Business Process Modeling Notation, because only businesspeople could participate. You need to enable conversations between all the members of the domain so that you can create a model to share between them.
在这种情况下,探索的范围更加有限,团队规模也是如此。你需要创建一个空间,让每个利益相关者都能为创建模型做出贡献,因此你不能使用 UML 等工具,否则只能由开发者参与,或者业务流程建模符号,因为只能由业务人员参与。你需要促进领域内所有成员之间的对话,以便创建一个可以与他们共享的模型。
In Figure 2.4, you can see all the types of sticky notes that you can use during an EventStorming session. Having a common model avoids misinterpretation, and with that, you don’t lose any details on the business flow.
在图 2.4 中,你可以看到在 EventStorming 会议期间可以使用的所有类型便利贴。使用统一模型可以避免误解,并且因此,你不会丢失业务流程的任何细节。
Figure 2.4 – The grammar of EventStorming process modeling
To achieve this goal, you have to add more types of sticky notes to EventStorming’s grammar. You do not need a design of the processes as a result of your exploration, but to encourage the conversation, so that you can use a tool as simple as possible to be understood by everyone. For example, during refactoring, it is very important to identify the right boundaries to split our monolith with. That separation represents the way in which you will extrapolate the microservices architecture.
要实现这一目标,你需要在 EventStorming 的语法中添加更多类型的便利贴。你的探索结果不需要是一个流程设计,而是为了鼓励对话,以便你可以使用尽可能简单的工具让每个人都能理解。例如,在重构过程中,识别出正确的边界来拆分我们的单体应用非常重要。这种分离代表了你会用来推断微服务架构的方式。
Software design  软件设计
With the previous workshop, you end up with a clear definition of the domain boundaries. Now, with this third format, you are going to explore in detail every single one of them, so that the grammar will be richer.
通过之前的研讨会,你最终得到了领域边界的清晰定义。现在,通过这个第三种格式,你将详细探索每一个边界,使语法更加丰富。
Figure 2.5 – All of the elements used during EventStorming
With this workshop, you will identify the aggregate of your bounded context, as well as the domain events, commands, services (internal and external), policy, and all the objects you need to design your solution. The aim of this workshop is to provide a detailed structure of the software for the team using the language that you discovered during the previous EventStorming sessions, and the details of all objects discovered in this one.
通过这个工作坊,你将识别你的限界上下文的聚合,以及领域事件、命令、服务(内部和外部)、策略以及你设计解决方案所需的所有对象。这个工作坊的目的是为使用你在之前的 EventStorming 会议中发现的语言的团队提供软件的详细结构,以及在这个会议中发现的所有对象的细节。
Now that you have understood the importance of knowledge, you can discover how deep you can go into the problem and try to solve it.
现在你已经理解了知识的重要性,你可以发现你可以深入到问题的哪个程度并尝试解决它。
Problem and solution space
Among the many phrases apocryphally attributed (https://quoteinvestigator.com/2014/05/22/solve/) to Albert Einstein, there is one that goes as follows:
在众多据传(https://quoteinvestigator.com/2014/05/22/solve/)归于阿尔伯特·爱因斯坦的名言中,有一句是这样的:
“If I had an hour to save the world, I would spend 55 minutes defining the problem and only 5 minutes finding the solutions.”
“如果我有一个小时来拯救世界,我会花 55 分钟来定义问题,只花 5 分钟来寻找解决方案。”
We could summarize this statement by saying that the problem space is the set of all the problems that your application should solve, while the solution space is the set of all solutions that address each given problem.
我们可以将这句话总结为:问题空间是指你的应用程序应该解决的所有问题的集合,而解决方案空间是指针对每个给定问题所提供的所有解决方案的集合。
Allen Newell and Herbert Simon in their book Human Problem Solving argue that we, as human beings, tend to be problem solvers. We see this daily in our team while developing software. We tend to seek and try to find a solution as quickly as possible and leave the problem space as quickly too. We are uncomfortable staying in this area, but it is where our client needs to reside; it is the zone that allows us to acquire more information about the problems our client asks us to solve through the software we will develop for them because writing software means solving business problems! Essentially, this space constitutes the foundation upon which the solution space will rest. Mathematically speaking, the problem space is always a subset of the solution space. Therefore, we should not rush to leave the former to move, with poor domain knowledge, to the latter. As developers, to demonstrate our capabilities, we tend to provide a solution as soon as possible, as if to show that we are good at our job by providing solutions fast to our clients.
艾伦·纽厄尔和赫伯特·西蒙在他们合著的《人类问题解决》一书中认为,作为人类,我们倾向于成为问题解决者。在我们团队开发软件时,我们每天都能看到这一点。我们倾向于尽快寻找并尝试找到解决方案,然后迅速离开问题空间。我们不喜欢待在这个区域,但客户需要待在这里;这是让我们通过将要为他们开发的软件获取更多关于他们要求我们解决的问题信息的区域,因为编写软件就意味着解决商业问题!本质上,这个空间构成了解决方案空间的基础。从数学上讲,问题空间始终是解决方案空间的一个子集。因此,我们不应该急于离开前者,带着贫乏的领域知识去后者那里。作为开发者,为了展示我们的能力,我们倾向于尽快提供解决方案,仿佛通过快速向客户提供解决方案来证明我们工作能力强。
By acting this way, however, we do not delve deeply enough into the problem; we are taking a shortcut to exit an uncomfortable zone. If we are then given requirements, our biases suggest the solution to propose! Unfortunately, such a solution will always be incomplete, at best, and wrong, at worst, because it is at this stage that projects begin to fail. We will realize it later when it is already too late, but the root of the failure lies in not having thoroughly investigated the problem space.
然而,采取这种方式,我们并没有深入探究问题;我们是在走捷径以逃离一个不舒适的区域。如果我们随后被给出需求,我们的偏见就会建议我们提出解决方案!不幸的是,这样的解决方案总是不完整的,至少是错误的,最坏的情况是,因为正是在这个阶段项目开始失败。我们会在太晚的时候才意识到这一点,但失败的根源在于没有彻底调查问题空间。
Staying in the problem space means resisting the urge to prematurely jump into solutions. It requires a disciplined approach to fully understand and articulate the problem before considering any solution. This involves engaging with stakeholders to capture their perspectives, conducting thorough research, and employing techniques such as domain modeling and scenario analysis to explore all facets of the problem.
留在问题空间意味着抵制过早跳入解决方案的冲动。它需要一种自律的方法,在考虑任何解决方案之前充分理解和阐述问题。这包括与利益相关者互动以捕捉他们的观点,进行彻底的研究,并采用领域建模和场景分析等技术来探索问题的各个方面。
By deeply investigating the problem space, we uncover the underlying causes, constraints, and nuances that might not be immediately obvious. This process often reveals critical insights that significantly influence the design and implementation of the solution. It ensures that the problem is framed correctly, which is essential for creating effective and sustainable solutions.
通过深入探究问题领域,我们能够揭示那些可能并不显而易见的基础原因、约束条件和细微差别。这一过程往往能揭示关键洞察,从而显著影响解决方案的设计与实现。它确保问题被正确地界定,这对于创建有效且可持续的解决方案至关重要。
Furthermore, staying in the problem space helps to mitigate biases and assumptions that can cloud judgment. It promotes a culture of curiosity and continuous learning within the team, where questions are encouraged, and diverse viewpoints are valued. This collaborative exploration fosters a shared understanding of the problem, aligning all stakeholders around a common goal.
此外,停留在问题领域有助于减轻可能蒙蔽判断的偏见和假设。它促进了团队内部好奇心和持续学习的文化,鼓励提问,并重视多元化的观点。这种协作探索培养了人们对问题的共同理解,使所有利益相关者围绕共同目标达成一致。
Neglecting this phase leads to superficial solutions that fail to address the core issues. Projects that skip through problem investigation often suffer from scope creep, missed requirements, and ultimately, failure to deliver value. In contrast, a robust exploration of the problem space lays a solid foundation for successful projects, ensuring that solutions are not only technically sound but also relevant and impactful.
忽视这一阶段会导致表面化的解决方案,无法解决核心问题。跳过问题探究的项目往往面临范围蔓延、需求遗漏,最终无法交付价值。相比之下,对问题领域的充分探索为成功项目奠定了坚实基础,确保解决方案不仅技术上可靠,而且具有相关性和影响力。
Figure 2.6 summarizes the differences between them.
Figure 2.6 – Problem space versus solution space
The urge to provide an adequate solution soon from the start means starting off on the wrong foot. We all know that our applications start small but are destined to grow over time, some very quickly: as customer demands grow, a small deviation at the beginning of the journey will lead us to a destination different from what was imagined, making it increasingly difficult to align our solution with the actual problem solution.
从一开始就急于提供充分的解决方案意味着一开始就踏错了步。我们都知道我们的应用开始时规模很小,但注定会随着时间的推移而增长,有些增长非常迅速:随着客户需求的增长,在旅程开始时的一个小偏差将导致我们到达一个与想象不同的目的地,使得我们的解决方案越来越难以与实际问题的解决方案保持一致。
How can we avoid all of this? By staying in the problem space as long as possible, just like in Einstein’s quote. Even Evans proposes an exploratory model, consisting of continuous iterations of analysis, proposal, and feedback, as shown in Figure 2.7.
我们如何避免所有这些问题?就像爱因斯坦的名言一样,尽可能长时间地停留在问题空间中。即使是伊文斯也提出了一个探索性模型,由分析、建议和反馈的持续迭代组成,如图 2.7 所示。
Figure 2.7 – Model exploration whirlpool
Evans defines the action of finding a solution from the beginning to the entire problem as what we colloquially call big front design: a block “locking in our ignorance.” The problem with this type of approach is that we are forced to make a lot of important decisions about our solution when we have less knowledge of the problem itself.
埃文斯将从头到整个问题寻找解决方案的行为定义为我们所俗称为大前设计:一个“锁定我们的无知”的模块。这种方法的缺点在于,当我们对问题本身了解较少时,被迫要做出许多关于解决方案的重要决策。
To counter this, Dan North suggests extreme caution in moving toward a definitive solution. In his article Introducing Deliberate Discovery (https://dannorth.net/introducing-deliberate-discovery/), he advocates for a proactive exploration of the domain knowledge, emphasizing the importance of identifying and understanding what we do not yet know about the domain. Let’s spend some time going through the important parts of the article.
为了应对这种情况,Dan North 建议在迈向最终解决方案时要极其谨慎。在他的文章《介绍刻意发现》(https://dannorth.net/introducing-deliberate-discovery/)中,他提倡主动探索领域知识,强调识别和理解我们尚未了解的领域的重要性。让我们花些时间回顾一下这篇文章的重要部分。
Deliberate discovery  刻意发现
The main terms covered in North’s article are as follows:
诺斯文章中涵盖的主要术语如下:
* Deliberate discovery: Emphasizes the importance of actively seeking knowledge to reduce ignorance in projects.
刻意发现:强调主动寻求知识以减少项目中的无知。
* Learning versus ignorance: Identifies ignorance as a primary constraint to project success and highlights the need for proactive learning
学习与无知:将无知视为项目成功的主要制约因素,并强调主动学习的重要性
* Accidental versus deliberate learning: Contrasts passive, accidental learning with intentional, deliberate discovery to accelerate knowledge acquisition
偶然学习与有意学习:对比被动、偶然的学习与有意、自觉的发现,以加速知识获取
* Non-linear discovery: Discusses how learning happens in irregular, often unexpected ways
非线性发现:讨论学习如何在不规则、往往出乎意料的方式中发生
* Assumption of problems: Advocates planning with the expectation that unpredictable problems will arise, thus preparing better responses
假设问题:主张在预期不可预测的问题会出现的情况下进行规划,从而准备更好的应对措施
The key recommendations made by North are as follows:
North 提出的关键建议如下:
* Focus planning on knowledge acquisition rather than merely estimating the task
将规划重点放在知识获取上,而不是仅仅估算任务
* Recognize and address various forms of ignorance (technical, domain-specific, organizational)
识别并解决各种形式的无知(技术、领域特定、组织层面)
* Make deliberate efforts in discovery to significantly improve project outcomes by reducing unknowns early
通过早期减少未知因素,在探索中做出刻意努力,显著提升项目成果
* Acknowledge that learning happens in spurts, often influenced by unforeseen challenges
承认学习往往在突发的挑战影响下进行
* Prepare for bad events proactively to mitigate their impact on projects
主动准备应对不良事件,以减轻其对项目的影响
Now let us look at another perspective that delves into the risks of big front design stemming from lack of awareness. Interestingly, “lack of awareness” is termed as the “2nd order of ignorance” in Phillip G. Armour’s article titled The Five Orders of Ignorance (https://cacm.acm.org/opinion/the-five-orders-of-ignorance/)
现在让我们从另一个角度探讨因缺乏意识而导致的宏大前端设计风险。有趣的是,在菲利普·G·阿莫尔的《无知五阶》(https://cacm.acm.org/opinion/the-five-orders-of-ignorance/)一文中,“缺乏意识”被称为“第二阶无知”。
.Five orders of ignorance
无知五阶
The main argument in Armour’s article is that the true product of software development is the knowledge embedded in the software; creating functional software requires understanding what “works.”
阿莫尔文章的主要论点是,软件开发真正的产物是嵌入在软件中的知识;创建功能软件需要理解什么是“有效的”。
If knowledge is the key, then the following is also true:
如果知识是关键,那么以下也是正确的:
* Building effective software is primarily about acquiring the necessary knowledge
构建有效的软件主要在于获取必要的知识
* Software development should be viewed as a knowledge-acquisition process rather than a product-production activity
软件开发应被视为一个知识获取过程,而不是产品生产活动
Starting with these considerations, we end up with five orders of ignorance:
基于这些考虑,我们最终得出五个无知等级:
* 0th order ignorance (0OI): Lack of ignorance – you know something and can demonstrate it
0 级无知(0OI):缺乏无知——你知道某事并能证明它
* 1st order ignorance (1OI): Lack of knowledge – you don’t know something, but you know what you don’t know
第一级无知(1OI):缺乏知识——你不知道某事,但你知道自己不知道什么
* 2nd order ignorance (2OI): Lack of awareness – you don’t know you don’t know
第二级无知(2OI):缺乏意识——你不知道自己不知道什么
* 3rd order ignorance (3OI): Lack of process – you don’t know a suitable process to find out what you don’t know
第三级无知(3OI):缺乏流程——你不知道一个合适的流程来找出自己不知道什么
* 4th order ignorance (4OI): Meta ignorance – you don’t know about the five orders of ignorance
四阶无知(4OI):元无知——你不知道有五种无知
If ignorance is the opposite of knowledge, how can we remain in the problem space to bridge 1OI and increase awareness of 2OI? How do we control our tendency to propose solutions too quickly?
如果无知是知识的对立面,我们如何能保持在问题空间中,以弥合 1OI 并提高对 2OI 的认识?我们如何控制自己提出解决方案过快的倾向?
Bridging gaps in ignorance
填补知识空白
To address the challenge of navigating between known and unknown gaps in knowledge, we recommend the following useful tips:
为了应对在已知和未知知识差距之间导航的挑战,我们推荐以下实用建议:
* Maintain control of the discussion: You don’t have to talk continuously, but you have to avoid the discussion converging too quickly to a conclusion. Often, a signal to a colleague is enough to change the focus of the conversation with the client. The main reason for maintaining control of the discussion is that clients—or their representatives—often assume certain information is understood and leave it unsaid, so it’s up to us to surface and clarify those assumptions.
掌控讨论方向:你不必持续发言,但需避免讨论过早达成结论。通常,向同事发出一个信号就足以改变与客户的对话焦点。掌控讨论的主要原因是客户——或其代表——常常假定某些信息已被理解而未明确表达,因此需要我们揭示并澄清这些假设。
* Listen to different solutions: In initial meetings with a client, participants are often hesitant to speak or propose ideas. Then, after the ice is broken thanks to our capable agile coach, solutions start to emerge and sometimes conflict with each other. It is important to maintain a healthy and positive environment by including everyone’s suggestions in the solution space.
倾听不同方案:在与客户初步会面时,参与者往往不愿发言或提出想法。随着我们出色的敏捷教练打破僵局,解决方案开始浮现,有时彼此冲突。重要的是通过将所有人的建议纳入解决方案空间来维持健康积极的氛围。
* Keep the main solution hidden: As the moderator of the problem exploration, your task is to keep the solutions that globally prove to be valid hidden for as long as possible. For example, if you use EventStorming as an exploration tool, let participants continue to attach sticky notes to the wall, and perhaps guide them in a direction so that the main solution emerges autonomously. Highlight solutions that seem similar and focus attention on them to understand whether they are different expressions of the same solution or totally different ones.
隐藏主要解决方案:作为问题探索的主持人,你的任务是尽可能长时间地隐藏那些被证明具有全局有效性的解决方案。例如,如果你使用事件风暴法作为探索工具,让参与者继续在墙上贴便利贴,并可能引导他们朝某个方向发展,以便主要解决方案能够自主浮现。突出看似相似的解决方案,并集中注意力理解它们是同一解决方案的不同表达方式,还是完全不同的方案。
Staying in the problem space is certainly uncomfortable for both parties: the client and the supplier. The former feels a bit under pressure due to the countless questions they keep receiving, and the latter, often us, can’t wait to propose a solution. Completely addressing the client’s problem takes time, and it’s not always convenient to insist on deeper investigation or prolonged questioning during the first meeting. The important thing is to identify the boundaries of the problem and start proposing a solution that can be revisited for feedback and continued after potentially adjusting the course.
对于客户和供应商双方来说,停留在问题空间中肯定是不舒服的:前者由于不断收到无数问题而感到有些压力,后者,通常是我们,迫不及待地想提出一个解决方案。完全解决客户的问题需要时间,而且在第一次会议中坚持进行更深入的调查或延长提问时间并不总是方便的。重要的是要确定问题的边界,并提出一个可以用于反馈并在可能调整方向后继续的解决方案。
Our domain will always be in constant evolution, if only for everything that belongs to the level of unknown unknowns – the things we still don’t know we don’t know but will discover as we become greater experts in the domain we are working on. At this point, we need to understand how to approach such a solution, from an architectural point of view. And for this, we need to explore the domain before creating a model.
我们的领域将始终处于不断演变之中,至少对于属于未知未知层面的一切而言——那些我们尚未意识到自己不知道,但当我们成为我们正在工作的领域的更高级专家时将会发现的事情。在这个阶段,我们需要从架构的角度理解如何处理这样的解决方案。为此,在创建模型之前,我们需要探索领域。
Deleuzian walk  德鲁兹式漫步
We have already seen how the abstractions of reality can be dangerous to solve a problem. Creating a good model is the primary goal, either during the first design of your solution or while you are working to refactor it. But how do we do this? EventStorming, like storytelling and other tools, is good for exploring the domain together with all team members before creating a model. However, an alternative way to run an exploration is to simply experience the domain itself, just as we explore the territory around us when we walk.
我们已经看到现实中的抽象可能对解决问题是有害的。创建一个好的模型是主要目标,无论是在您解决方案的第一次设计期间,还是在您进行重构时。但我们如何做到这一点呢?EventStorming,就像讲故事和其他工具一样,在创建模型之前与所有团队成员一起探索领域是很好的。然而,进行探索的另一种替代方法是直接体验领域本身,就像我们漫步时探索周围的领土一样。
This form of exploration is known as the Deleuzian walk and describes an alternative way of learning. The term comes from the ideas of Gilles Deleuze, as described in his 1968 book Difference and Repetition, which can be summarized as follows:
这种探索形式被称为德勒兹式漫步,描述了一种替代性的学习方法。该术语源自吉尔·德勒兹的思想,如他在 1968 年出版的《差异与重复》一书中所阐述的,可以总结如下:
* Philosophy of difference: Deleuze challenges traditional philosophy’s focus on identity and sameness, advocating for a deeper exploration of differences
差异哲学:德勒兹挑战传统哲学对同一性和相同性的关注,倡导更深入地探索差异
* Repetition and novelty: He explores how repetition can generate new meanings or variations, challenging the idea that repetition simply reinforces what already exists or remains the same.
重复与新颖性:他探讨了重复如何产生新的意义或变化,挑战了重复仅仅强化既存事物或保持不变的观念。
* Ontology: Deleuze presents being as inherently different, emphasizing uniqueness over uniformity
本体论:德勒兹提出存在本质上是不同的,强调独特性而非一致性
* Time and memory: The roles of time and memory are scrutinized for their impact on cultivating differences
时间和记忆:审视时间和记忆在培养差异方面所起的作用
* Conceptual tools: Deleuze navigates through his arguments employing complex philosophical constructs such as the virtual, the actual, and intensity
概念工具:德勒兹通过运用虚拟、实在和强度等复杂的哲学结构来阐述他的论点
When you walk along a new path for the first time, you are totally involved in looking at the map to be sure to get back home safely. After a few times, you start to discover new things on your journey because now you know the path, and you can pay attention to the environment around you, the mountains around the valley, or the river at the bottom. You will see new landscapes or discover new alternative ways of traveling in the same space. When you bring your friends with you, they will see different things, because their interests are different from yours. Instead of understanding the world around you, you are contemplating it, and you become very rich. You are changing your way of thinking, from learning from the map (linear), in which the map provides an objective, well-defined, description of the walk, to observing the world around you with your eyes and discovering new things (laterally).
当你第一次走一条新路径时,你会完全专注于查看地图以确保安全回家。几次之后,你开始在旅途中发现新事物,因为你已经熟悉了这条路径,可以留意周围的环境,山谷周围的山峦,或河底。你会看到新的风景,或在同一空间中发现新的旅行方式。当你带上朋友一起时,他们会看到不同的东西,因为他们的兴趣和你不同。你不再只是理解周围的世界,而是在思考它,你变得非常丰富。你的思维方式发生了改变,从通过地图学习(线性),地图提供了对行走过程的客观、明确的描述,转变为用眼睛观察周围的世界,发现新事物(横向)。
This metaphor is quite fitting for domain exploration. As the environment changes during the different seasons, your domain also changes due to new business requirements, or simply because the world changes constantly and so does the business flow. This means that our structure is constantly changing, and implementing certain structures too early could be very dangerous and unproductive.
这个比喻非常适用于领域探索。随着不同季节环境的变化,你的领域也会因新的业务需求而变化,或者仅仅因为世界在不断变化,业务流程也在不断变化。这意味着我们的结构也在不断变化,过早地实施某些结构可能会非常危险且低效。
During domain exploration, knowledge is much preferable in contrast to the developer’s need for an immediate concrete implementation. So, Deleuze’s ideas map perfectly with the model exploration whirlpool shown in Figure 2.7. Basically, it is important to discover your domain iteratively and increase your knowledge of the domain step by step. Remember that you are a developer and do not necessarily know from the start the domain you will work on.
在领域探索过程中,知识远比开发者对立即具体实现的渴望更为重要。因此,德勒兹的思想与图 2.7 中所示的模型探索漩涡完美契合。基本上,发现你的领域需要迭代进行,并逐步增加你对领域的认知。记住,你是一名开发者,从一开始并不一定知道你将要工作的领域。

Decision-making and biases
决策与偏见
By now, it should be clear why it is important to spend most of our time understanding the problem instead of finding a solution, and now we can delve into the last aspect of handling complexity. This includes cognitive aspects of decision-making and how biases can impact the process, especially in the context of refactoring complex systems using DDD patterns and principles. Understanding these cognitive processes will help you make more informed and rational decisions during your refactoring journey.
到现在为止,应该很清楚为什么我们应该将大部分时间用于理解问题而不是寻找解决方案,现在我们可以深入探讨处理复杂性的最后一个方面。这包括决策的认知方面以及偏见如何影响这个过程,特别是在使用领域驱动设计(DDD)模式和原则重构复杂系统的背景下。理解这些认知过程将帮助你在重构旅程中做出更明智和理性的决策。
Understanding System 1 and System 2
理解系统 1 和系统 2
Daniel Kahneman, a renowned psychologist and Nobel laureate, introduced the concept of two systems of thinking in his book Thinking, Fast and Slow. These systems are fundamental to understanding human decision-making processes and are called System 1 and System 2.
丹尼尔·卡尼曼,一位著名的心理学家和诺贝尔奖得主,在他的著作《思考,快与慢》中提出了两种思维系统的概念。这些系统是人类决策过程的基础,被称为系统 1 和系统 2。
System 1 is efficient for routine tasks and familiar situations but can be prone to biases and errors when dealing with complex or unfamiliar problems. System 2, on the other hand, is slower and more deliberate and allows us to make more rational and informed decisions, especially when dealing with unfamiliar or complex situations. Their key traits are as follows:
系统 1 适用于常规任务和熟悉的情况,但在处理复杂或陌生问题时容易产生偏见和错误。而系统 2 则较慢且更审慎,使我们能够做出更理性、更明智的决策,尤其是在处理陌生或复杂情况时。它们的主要特征如下:
* System 1 – fast and intuitive: System 1 operates automatically and quickly, with little or no effort and no sense of voluntary control. It is our intuitive system, which we use for quick judgments and decisions. Examples of System 1 thinking include the following:
系统 1——快速且直观:系统 1 自动且快速运行,几乎不需要努力,也没有自愿控制的意识。它是我们的直觉系统,用于快速判断和决策。系统 1 思考的例子包括以下:
    * Recognizing a familiar face in a crowd
在人群中认出熟悉的面孔
    * Answering simple arithmetic questions (e.g., 2 + 2 = 4)
回答简单的算术问题(例如,2+2=4)
    * Driving a car on an empty road
在空旷的路上开车
* System 2 – slow and deliberate: System 2 allocates attention to the effortful mental activities that demand it, including complex computations. It is our analytical system, which we use for critical thinking and complex problem-solving. Examples of System 2 thinking include the following:
系统 2——缓慢而审慎:系统 2 将注意力分配给需要它付出的努力性心理活动,包括复杂的计算。它是我们的分析系统,我们用它来进行批判性思维和复杂问题解决。系统 2 思维的例子包括以下:
    * Solving a complex mathematical problem
解决一个复杂的数学问题
    * Making a strategic decision in a business context
在商业环境中做出战略决策
    * Refactoring a complex software system
重构复杂软件系统
The importance of Systems 1 and 2 in refactoring
系统 1 和系统 2 在重构中的重要性
Refactoring, particularly in complex systems, requires a balance between intuitive and deliberate thinking. Here’s how understanding and applying System 1 and System 2 can enhance your refactoring efforts.
重构,尤其是在复杂系统中,需要在直觉思维和刻意思维之间取得平衡。这里是如何理解和应用系统 1 和系统 2 来提升你的重构工作。
To leverage both systems, you must understand when and how to use them during the refactoring process. Starting with System 1, an experienced developer can quickly recognize patterns, code smells, and where to start a refactoring process through past experiences. Also, for minor tasks, such as extracting small methods, System 1 can be effective. System 2 kicks in when you deal with large-scale refactoring, such as restructuring an entire module or re-architecting a system. Here, deliberate thinking is crucial. It also helps in creating a refactoring plan and identifying potential risks ahead. As a last important thing, System 2 can help mitigate biases that could emerge with System 1.
要利用这两个系统,你必须了解在重构过程中何时以及如何使用它们。从系统 1 开始,有经验的开发者可以通过过去的经验快速识别模式、代码异味以及重构的起点。此外,对于提取小方法等小任务,系统 1 可以很有效。当处理大规模重构,如重构整个模块或重新架构系统时,系统 2 会介入。这时,刻意思维至关重要。它还有助于制定重构计划并提前识别潜在风险。最后一点重要的是,系统 2 可以帮助缓解系统 1 可能产生的偏见。
Common cognitive biases in refactoring
重构中的常见认知偏差
Refactoring is as much a mental process as a technical one, and our cognitive biases can significantly impact the outcomes. Recognizing these biases and taking steps to counteract them can help you avoid potential pitfalls. Let’s look at the main ones and what you can consider doing to mitigate them.
重构既是技术过程,也是思维过程,我们的认知偏差会显著影响结果。认识到这些偏差并采取措施加以对抗,可以帮助你避免潜在陷阱。让我们看看主要的偏差以及你可以考虑如何减轻它们。
Anchoring bias  锚定偏差
Anchoring bias occurs when we rely too heavily on the first piece of information encountered (the “anchor”) when making decisions. As stated, this might mean sticking to the first solution or design without considering other alternatives. You should encourage team discussions and explore multiple solutions before settling on a decision.
锚定偏差发生在我们做决策时过度依赖遇到的第一条信息(“锚点”)。如前所述,这可能意味着坚持第一个解决方案或设计,而不考虑其他替代方案。你应该鼓励团队讨论,并在做出决定前探索多种解决方案。
Here’s how to counteract it:
这是如何应对它的方法:
* Encourage exploration: Actively brainstorm multiple solutions before committing to one. Use tools such as design spikes or proof-of-concept development to evaluate alternatives.
鼓励探索:在做出决定前积极头脑风暴多种解决方案。使用设计尖峰或概念验证开发等工具来评估替代方案。
* Adopt decision frameworks: Use structured techniques such as decision matrices to evaluate options objectively.
采用决策框架:使用决策矩阵等结构化技术来客观评估选项。
* Set a “cooling-off period”: Give the team time to reflect on initial ideas before making a final decision.
设置“冷静期”:给团队时间在做出最终决定前反思初步想法。
Confirmation bias  确认偏差
Confirmation bias is the tendency to search for and remember information that confirms one’s preconceptions. This can lead to ignoring critical feedback or alternative approaches during refactoring. To mitigate this bias, you can seek different opinions and rely on thorough code reviews to challenge your decisions.
确认偏误是指人们倾向于寻找和记住符合自己先入为主观念的信息。这可能导致在重构过程中忽视关键反馈或替代方法。为了减轻这种偏误,你可以寻求不同意见并依赖彻底的代码审查来挑战你的决定。
Here’s how to counteract it:
这是如何应对它的方法:
* Foster a culture of challenge: Encourage team members to play devil’s advocate during discussions. Assign someone to question the prevailing assumptions in every meeting.
培养挑战文化:鼓励团队成员在讨论中扮演反对角色。指派专人负责在每次会议中质疑主流假设。
* Emphasize diverse perspectives: Actively involve people from different roles or with varying expertise to review designs and refactoring plans.
强调多元视角:主动邀请来自不同角色或拥有不同专业知识的成员来评审设计和重构计划。
* Automate feedback: Use tools such as static code analyzers and automated tests to surface objective insights, reducing reliance on subjective interpretations.
自动化反馈:使用静态代码分析器和自动化测试等工具来揭示客观见解,减少对主观解释的依赖。
Availability heuristic  可得性启发式
The availability heuristic involves prioritizing events based on vividness or recency instead of their frequency, such as a plane crash versus a car crash. The latter is more frequent, but we tend to think of the former more often. This can result in overestimating the importance of recent events that are not the norm and potentially lead us to suboptimal refactoring decisions. We should force ourselves to base our decisions on objective data rather than recent experiences alone.
可得性启发式是指根据生动性或近期性来优先考虑事件,而不是根据其频率,例如飞机失事与汽车事故。后者更为频繁,但我们往往更常想到前者。这可能导致我们高估非正常近期事件的重要性,并可能引导我们做出次优的重构决策。我们应该强迫自己基于客观数据而非仅凭近期经验来做决策。
Here’s how to counteract it:
这是如何应对它的方法:
* Rely on historical data: Analyze metrics such as defect rates, code churn, or feature usage to guide refactoring priorities
依靠历史数据:分析缺陷率、代码变更率或功能使用情况等指标来指导重构优先级
* Maintain a refactoring log: Document past refactoring efforts, lessons learned, and their outcomes to ground future decisions in accumulated knowledge
维护重构日志:记录过去的重构工作、经验教训及其结果,以便将未来的决策建立在积累的知识基础上
* Encourage structured retrospectives: Reflect regularly on past decisions to identify patterns that can inform better judgment
鼓励结构化回顾:定期反思过去的决策,以识别可以指导更好判断的模式
Practical example – refactoring a legacy system
实际案例——重构遗留系统
Let’s consider a practical example to illustrate the application of System 1 and System 2 thinking in refactoring a complex system. Imagine you are tasked with refactoring a monolithic application into a more modular and maintainable structure using DDD principles. This scenario provides an excellent opportunity to demonstrate how both types of thinking can be leveraged throughout the refactoring process.
让我们通过一个实际案例来说明在重构复杂系统时如何应用系统 1 和系统 2 的思维。假设你被要求使用领域驱动设计(DDD)原则将一个单体应用程序重构为一个更模块化和可维护的结构。这个场景为展示这两种思维如何在重构过程中发挥作用提供了绝佳的机会。
Your approach would likely begin with an initial assessment, combining both System 1 and System 2 thinking. You’d use your intuitive System 1 to quickly identify obvious code smells and areas that need improvement. Simultaneously, you’d engage your analytical System 2 thinking to perform a detailed analysis of the system’s architecture, dependencies, and business domains. This deeper, more deliberate analysis provides a comprehensive understanding of the system’s complexity.
你的方法可能从初步评估开始,结合系统 1 和系统 2 的思维。你会用系统 1 的直觉快速识别明显的代码异味和需要改进的领域。同时,你会运用系统 2 的分析性思维对系统的架构、依赖关系和业务领域进行详细分析。这种更深入、更审慎的分析提供了对系统复杂性的全面理解。
With a clear picture of the system, you move on to strategic planning, which primarily involves System 2 thinking. You develop a strategic plan for the refactoring process, carefully breaking down the monolith into bounded contexts. This step requires thoughtful consideration of the system’s structure and business logic. As part of this planning, you identify key aggregate roots, entities, and value objects within each bounded context (we will do a recap on these terms in Chapters 3 and 4), laying the groundwork for a more modular and domain-aligned architecture.
有了对系统的清晰认识,你便可以进入战略规划阶段,这主要涉及系统 2 型思维。你为重构过程制定战略计划,小心地将单体系统分解为限界上下文。这一步需要对系统的结构和业务逻辑进行深思熟虑的考虑。作为这一规划的一部分,你需要在每个限界上下文中识别关键的聚合根、实体和价值对象(我们将在第 3 章和第 4 章中回顾这些术语),为构建更模块化、与领域对齐的架构奠定基础。
The actual refactoring process is where both System 1 and System 2 thinking truly shine in tandem. You apply System 1 thinking for straightforward refactoring tasks within each bounded context. These might include simple code cleanup, renaming for clarity, or extracting obvious methods. For more complex tasks, you switch to System 2 thinking. This includes defining new interfaces, decoupling dependencies, and ensuring data consistency across the newly defined boundaries. The interplay between quick, intuitive decisions and deeper, more analytical thinking allows for efficient progress while maintaining the integrity of the refactoring effort.
实际的重构过程是系统 1 和系统 2 思维真正协同发挥光芒的地方。你用系统 1 思维处理每个限界上下文内的简单重构任务,这些任务可能包括简单的代码清理、为清晰而重命名,或提取明显的函数。对于更复杂的任务,你切换到系统 2 思维。这包括定义新接口、解耦依赖关系,以及确保在新定义的边界上数据的一致性。快速直觉决策与更深入、更分析性思维之间的相互作用,使得重构工作高效推进,同时保持重构工作的完整性。
Throughout the refactoring process, continuous review and adaptation are crucial. You regularly review the refactoring progress with your team, using System 1 thinking to identify quick wins and immediate improvements. At the same time, you employ System 2 thinking to address any emerging challenges or changes in requirements. This balanced approach ensures that you can make rapid progress while also adapting to the evolving needs of the project and catching any potential issues before they become significant problems.
在整个重构过程中,持续审查和调整至关重要。你定期与团队一起审查重构进度,用系统 1 思维识别快速见效和即时改进。同时,你运用系统 2 思维处理任何出现的挑战或需求变化。这种平衡方法确保你能快速推进,同时也能适应项目不断变化的需求,并在问题变得严重之前捕捉到任何潜在问题。
By understanding the dual systems of thinking and recognizing common cognitive biases, you can improve your decision-making process during refactoring. Leveraging System 1 for routine tasks and System 2 for complex problem-solving allows for a balanced and effective approach. Always remain vigilant of biases, seek diverse perspectives, and apply deliberate thinking to tackle the complexity inherent in refactoring.
通过理解思维的两种系统并认识到常见的认知偏差,你可以在重构过程中改进决策过程。利用系统 1 处理常规任务,系统 2 解决复杂问题,可以实现平衡有效的方法。始终警惕偏差,寻求多元视角,并运用刻意思考来应对重构中固有的复杂性。

Summary  摘要
In this chapter, you discovered tools to help understand and pragmatically approach complexity. You gained a comprehensive understanding of handling modern systems’ complexity by effectively separating and navigating the problem and solution spaces while mitigating biases in decision-making. You learned how to approach the complexity of modern systems, the importance of remaining in the problem space as long as possible, and how thinking about the solution changes from thinking about the problem. Additionally, you explored the differences between System 1 and System 2.
在这一章中,你发现了帮助理解和实用方法处理复杂性的工具。你通过有效分离和导航问题与解决方案空间,同时减轻决策中的偏差,获得了处理现代系统复杂性的全面理解。你学习了如何应对现代系统的复杂性,尽可能长时间地停留在问题空间的重要性,以及从思考问题到思考解决方案时思维方式的转变。此外,你还探索了系统 1 与系统 2 之间的区别。
In the next chapter, we will delve into context mapping and strategic patterns. You will learn how to identify and map the various contexts within your domain, understand the relationships between them, and apply strategic patterns to manage these contexts effectively. This will enable you to align your system’s design with its business goals, ensuring a more cohesive and adaptable architecture.
在下一章中,我们将深入探讨上下文映射和战略模式。您将学习如何识别和映射您领域内的各种上下文,理解它们之间的关系,并应用战略模式来有效管理这些上下文。这将使您能够使系统的设计与其业务目标保持一致,确保更具凝聚力和适应性的架构。
Chapter 3, Strategic Patterns
As you learned in previous chapters, the biggest challenge at the start of any project—whether it’s a greenfield project or a refactoring effort—is the language. By now, the importance of understanding the domain and defining a shared language to build knowledge should be evident. However, creating a ubiquitous language comes with hidden challenges, often stemming from human behavior.
如前几章所述,任何项目启动时最大的挑战——无论是全新项目还是重构工作——都是语言问题。此时,理解领域并定义构建知识的共同语言的重要性应当显而易见。然而,创建通用语言会带来隐藏的挑战,这些挑战往往源于人类行为。
Now that you know how to avoid these mistakes, you are ready to discover the patterns that domain-driven design gives us and learn how to use them during the refactoring of your system.
现在你已经知道如何避免这些错误,你已准备好发现领域驱动设计为我们提供的模式,并学习如何在系统重构过程中使用它们。
To do so, we’ll cover the following main topics in this chapter:
为此,本章将涵盖以下主要主题:
* Defining terms clearly  清晰定义术语
* Dividing the domain  划分领域
* Dealing with communication between bounded contexts
处理有界上下文之间的通信

Defining terms clearly will solve half of the problem
明确术语将解决一半问题
In his book, Evans makes clear the importance of using the ubiquitous language in conversation with domain experts, and with all team members. To ensure that the comprehension of the problem is clear and without ambiguity due to an incorrect translation from the domain language to the technical language, it is important that the language used in our code base is as close as possible to the domain model. That is because the product that we deploy in production uses the technical language, not the business language.
在书中, Evans 阐明了在与领域专家以及所有团队成员交流时使用通用语言的重要性。为了确保对问题的理解清晰且没有因领域语言到技术语言的错误翻译而产生的歧义,我们代码库中使用的语言应尽可能接近领域模型。这是因为我们部署到生产环境中的产品使用的是技术语言,而不是业务语言。
To achieve that, during the conversation between teammates, no one needs to translate terms from one language to another. Since the software does not cope with ambiguity, we should base the conversation on the domain model. We will explain the domain model concept better later in the What is a bounded context? section of this chapter.
为了实现这一点,在团队成员之间的交流中,不需要将一个语言的术语翻译成另一个语言。由于软件无法处理模糊性,我们应该基于领域模型进行交流。我们将在本章的“什么是限界上下文?”部分更详细地解释领域模型的概念。
Evans is uncompromising about this:
埃文斯在这个问题上毫不妥协:
“By using the model-based language pervasively and not being satisfied until it flows, we approach a model that is complete and comprehensible, made up of simple elements that combine to express complex ideas…
“通过广泛使用基于模型的语言,并且不满足于直到它流畅为止,我们接近一个完整且易于理解的模型,它由简单的元素组成,这些元素组合起来表达复杂的思想……
“…Domain experts should object to terms or structures that are awkward or inadequate to convey domain understanding; developers should watch for ambiguity or inconsistency that will trip up design”
“……领域专家应该反对那些表达领域理解时显得笨拙或不充分的术语或结构;开发者应该警惕会导致设计陷阱的模糊性或不一致性”
The ubiquitous language is not just a vocabulary; it is a rigorous language between all teammates who aim to remove all ambiguity and create a base to identify the boundaries around the business problem they have to solve.
通用语言不仅仅是一套词汇;它是所有致力于消除所有模糊性并创建一个识别业务问题边界基础的所有团队成员之间的一种严谨语言。
During refactoring, it’s important to understand the model underlying the software we are working on before starting to modify the code. Having a common model of the business that every teammate can understand is the key to obtaining a clear architecture for the solution. It helps us to clearly identify the boundaries around the business problem, and having a common language is the first step. Try to think about a customer model; it seems easy to create a model of our customer, just including all properties such as invoice data, personal data, delivery addresses, headquarters addresses, and so on. We would then have a complete model of our customer. Most of the software that you are working on probably has a model similar to this one, and this is the primary pain point when you have to modify the behavior of the program or implement a new feature.
在重构过程中,开始修改代码之前,理解我们正在处理的软件背后的模型非常重要。让每个团队成员都能理解的一个共同业务模型是获得解决方案清晰架构的关键。它帮助我们清晰地识别业务问题的边界,而拥有共同语言是第一步。试着思考一下客户模型;创建我们的客户模型似乎很容易,只需包括所有属性,如发票数据、个人数据、送货地址、总部地址等。然后我们就会拥有一个完整的客户模型。你正在处理的绝大多数软件可能都有一个与此类似的模型,而当你必须修改程序行为或实现新功能时,这就是主要的痛点。
Figure 3.1 shows the telephone game pattern in a real business situation. A domain expert explains their problem to an analyst, who explains the same (are you sure?) problem to an architect, and so on until it reaches the development team. They create a solution that will be deployed. Can you see the problem? Any person involved in this pattern has their own interpretation of the problem, which is different from that of the previous person in the line.
图 3.1 展示了在真实商业场景中的电话游戏模式。领域专家向分析师解释他们的问题,分析师又向架构师解释相同的问题(你确定吗?),如此传递下去直到开发团队。他们创建一个解决方案并部署。你能看出问题所在吗?这个模式中的每个人都对问题有自己的理解,这与链中前一个人的理解不同。
How can you avoid this mistake? The first and simplest solution could be to remove the line between business experts and developers and get these people to communicate directly. Unfortunately, they use different languages, and this type of communication is impossible.
你如何避免这个错误?第一个也是最简单的解决方案可能是消除业务专家和开发者之间的界限,并让这些人直接沟通。不幸的是,他们使用不同的语言,这种类型的沟通是不可能的。
Figure 3.2 explains this solution. Domain experts and the development team talk among themselves directly, without any mediator. In this case, the problem isn’t the loss of information, but the language. Each of them uses a different language and cannot understand what the other says.
图 3.2 解释了这个解决方案。领域专家和开发团队直接相互交流,没有任何中介。在这种情况下,问题不是信息丢失,而是语言。他们各自使用不同的语言,无法理解对方所说的话。
Finally, you can see the solution to the problem in Figure 3.3. Using a ubiquitous language, each member of the team understands the other, and together they can build a domain model that’s helpful for everyone.
最后,你可以在图 3.3 中看到问题的解决方案。使用通用语言,团队成员之间能够相互理解,并一起构建对每个人有帮助的领域模型。
Figure 3.3 – Common domain model
Having a model aligned with the business simplifies the refactor because now you and your business experts can understand each other without the need for translations or interpreters, and every new request that arrives will be perfectly aligned with your model. In addition, if the new request involves changing the model, you can rest easy knowing that changing the model will not affect the other functionalities of the system.
拥有与业务一致的模型可以简化重构,因为现在你可以和你的业务专家无需翻译或中介就能相互理解,并且每个新到达的请求都将与你的模型完美契合。此外,如果新请求涉及改变模型,你可以放心,因为改变模型不会影响系统的其他功能。
However, why do you need to create many models, and not just one, for your whole business? If the goal is creating software that can evolve, you need to create many small models, each of which is isolated from the other one. This is what bounded contexts are responsible for.
然而,为什么您需要为整个业务创建许多模型,而不仅仅是一个呢?如果目标是创建能够演进的软件,您需要创建许多小的模型,每个模型都与其他模型相互隔离。这就是限界上下文所负责的。
What is a bounded context?
什么是限界上下文?
A bounded context is a fundamental pattern of domain-driven design. It is the focus of strategic patterns and a central concept when you deal with large models because it allows you to split a big problem into smaller problems or a large model into smaller models.
限界上下文是领域驱动设计的一个基本模式。它是战略模式的核心,当你处理大型模型时也是一个中心概念,因为它能让你将一个大问题分解为小问题,或把一个大模型分解为小模型。
Having small models helps us solve business problems and maintain our code in the future. To identify the boundaries around this fine-grained model, you have to use the ubiquitous language discovered previously to identify the pivotal events that move the discussion around the business problem from one context to another.
拥有小模型有助于我们解决业务问题,并在未来维护代码。为了确定这个细粒度模型的边界,你必须使用先前发现的通用语言来识别那些将业务问题的讨论从一个上下文转移到另一个上下文的关键事件。
You have to keep in mind that the core of domain-driven design is about designing software based on a model, one that all the teammates can understand. When this model will not map the business flow anymore due to the increased complexity and the components involved in it, you are definitely moving outside of the model boundary. When you deal with the refactoring of an old project, it is important to identify these boundaries, because the first thing you have to do after discovering them is to remove the coupling between objects that belong to different bounded contexts. Removing these coupling enables you to modify part of the system without the fear of breaking others, and that is a fundamental step!
你必须牢记,领域驱动设计的核心是基于一个模型来设计软件,这个模型是所有团队成员都能理解的。当由于复杂性的增加和涉及到的组件增多,这个模型不再能够映射业务流程时,你肯定已经超出了模型的边界。在处理旧项目的重构时,识别这些边界非常重要,因为在发现它们之后,你首先要做的是消除属于不同限界上下文的对象之间的耦合。消除这些耦合使你能够修改系统的部分内容,而不用担心破坏其他部分,这是一个基本步骤!
Another element that you can use to draw boundaries between contexts is human behaviors. Back to the example of the sales order created, the behavior of the people involved in the payment system will be different from the people involved in the logistics department because they will have different tasks to perform. You have to capture these differences and use them to identify the boundaries of your contexts.
另一个可用于划分上下文界限的元素是人类行为。回到创建销售订单的例子,参与支付系统的人员的行为将与物流部门的人员不同,因为他们需要执行不同的任务。你必须捕捉这些差异,并利用它们来识别你的上下文界限。
Once you have split the whole domain into many different bounded contexts, you need to find how these contexts communicate with one another. Like in the real world, each part of the system contributes to the final success, and the only way to achieve this is collaboration.
一旦你已经将整个领域划分为许多不同的限界上下文,你需要找到这些上下文之间是如何相互通信的。就像在现实生活中,系统的每个部分都对最终的成功做出贡献,而实现这一点的唯一方式是协作。

Dividing the domain into meaningful boundaries
将领域划分为有意义的边界
The most obvious advantage of having a ubiquitous language is the ability to easily identify the boundaries around a business problem and split the domain into many subdomains. A business domain is the main area of activity of a company. In the example we will use in this book, the business domain is brewery management. The service that our hypothetical company provides is the production and selling of the best beer in the world! Easy.
使用通用语言的明显优势是能够轻松识别业务问题的边界并将领域划分为多个子域。业务领域是公司主要的活动区域。在本书中我们将使用的示例中,业务领域是酿酒厂管理。我们假设的公司提供的服务是全球最棒的啤酒的生产和销售!简单。
It is important to understand that the business domain is not a software application. The software provides the solution you create to help your customer manage their business. A business domain is generally big and complex. So, as you have already discovered, having just one model to describe the whole business is impossible, and it is probably the situation that you will find yourself in when approaching refactoring. You can see the problem of having a “one-size-fits-all” model. It is a constraint for every new request and creates a fear of changing anything in your code due to the strong coupling between the components of your legacy application.
重要的是要理解业务领域并不是一个软件应用。软件为你提供的解决方案是用来帮助客户管理他们的业务。业务领域通常很大且复杂。因此,正如你已经发现的,用一个模型来描述整个业务是不可能的,当你开始重构时,这很可能是你面临的情况。你可以看到使用“一刀切”模型的弊端。它对新请求施加了限制,并且由于遗留应用程序组件之间强耦合,导致你害怕更改代码中的任何内容。
As in the real world, a company achieves its business domain goals by splitting the business itself into multiple areas. Domain-driven design does the same by splitting the domain into multiple subdomains. A subdomain is a small part of the whole domain and focuses on a particular aspect of the business. It is an important strategic pattern within domain-driven design. Therefore, a single subdomain is not enough to guarantee the success of a company. It is a cog in a more complex system: the domain.
如同现实世界中公司通过将业务本身划分为多个领域来实现其业务领域目标一样,领域驱动设计也是通过将领域划分为多个子领域来实现这一目标。子领域是整个领域的一个小部分,专注于业务的某个特定方面。它是领域驱动设计中的一个重要战略模式。因此,单个子领域不足以保证公司的成功。它是更复杂系统——即领域——中的一个齿轮。
In a complex system, each gear is assembled so that the whole system can fulfill its task; not every gear is important in the same way. In the context of a wheel, if you break a spoke, you can continue pedaling and finish your ride. However, if you puncture the tire, you must stop your ride, repair the tire, and then finish your ride. Both the tire and spoke are part of the wheel, but the tire is more important than the spoke. Likewise, if the goal of your company is to produce the best beer, having a good warehouse system will be important to stock the beers before selling them, but less important than having a perfect production department. None of these departments on their own will make your brewery profitable; all of these, and probably others, are necessary to achieve the goal, but it is imperative to identify the responsibilities of each one.
在一个复杂系统中,每个齿轮被组装起来,以便整个系统能够完成其任务;并非每个齿轮都以相同的方式重要。在车轮的语境中,如果你弄断了一根辐条,你可以继续蹬车并完成骑行。然而,如果你扎破了轮胎,你必须停止骑行,修理轮胎,然后才能完成骑行。轮胎和辐条都是车轮的一部分,但轮胎比辐条更重要。同样地,如果贵公司的目标是酿造最好的啤酒,拥有一个良好的仓库系统对于在销售前储存啤酒很重要,但比拥有一个完美的生产部门要次要。这些部门中的任何一个单独存在都不会使你的啤酒厂盈利;所有这些,以及可能还有其他一些,都是实现目标所必需的,但必须明确每个部门的职责。
To identify the boundaries around these subdomains, you have to use the ubiquitous language discovered in the exploration phase with the domain experts and stakeholders. Any inconsistency in the ubiquitous language is a warning that something should be investigated more. That is because we could be talking about the same things but with different names, or we could be looking at a totally different thing that might belong to a different bounded context. You need to learn how to force your business experts to stay inside the problem space because you know how important this is. You need to identify whether you are talking about the customer for a sale order, or the customer for a delivery. You are certainly talking about a customer in either case, but in two different ways. That means having two different models, and, in this case, two different subdomains. You already know that a subdomain is a smaller area of knowledge or activity within a larger domain. Now you have also discovered that, as in the case of a cog or wheel, some subdomains are more important than others and there are different types of them. Splitting the whole domain into many subdomains means that you can create a smaller model and talk with specific domain experts to go deeply into the modeling. During the first part of the refactor, distilling a domain is extremely important to start with a good strategic design. The refactoring process is intended to improve the design, structure, and implementation of the software, as well as its non-functional attributes, without changing the functionalities.
要识别这些子域的边界,你必须使用在探索阶段与领域专家和利益相关者发现的通用语言。通用语言中的任何不一致都是需要进一步调查的警告。这是因为我们可能谈论的是同样的事情但使用不同的名称,或者我们可能关注的是完全不同的事情,这可能属于不同的限界上下文。你需要学会如何迫使你的业务专家保持在问题空间内,因为你知道这有多重要。你需要确定你是在谈论销售订单的客户,还是配送的客户。在任何一种情况下,你当然都在谈论客户,但方式不同。这意味着需要有两个不同的模型,在这种情况下,也有两个不同的子域。你已经知道子域是较大领域中一个较小的知识或活动区域。现在你也发现,就像齿轮一样,某些子域比其他子域更重要,并且它们有不同的类型。 将整个领域划分为多个子域意味着你可以创建一个更小的模型,并与特定领域的专家深入探讨建模问题。在重构的第一阶段,提炼领域至关重要,这有助于从良好的战略设计开始。重构过程旨在在不改变功能性的情况下,改进软件的设计、结构、实现及其非功能性属性。
Your goal is to reduce accidental complexity and improve code readability without side effects. Remember that you cannot transform a big ball of mud into a microservices solution in one step. Always keep Gall’s law in mind:
你的目标是减少偶然复杂度并提高代码可读性,而不产生副作用。记住,你不能一步将一团乱麻转变为微服务解决方案。始终牢记 Gall 定律:
“A complex system that works is invariably found to have evolved from a simple system that worked. The inverse proposition also appears to be true: a complex system designed from scratch never works and cannot be made to work. You have to start over, beginning with a working simple system.”
一个能够正常运行的复杂系统,往往是从一个能够运行的简单系统演变而来的。反命题似乎也成立:从头设计的复杂系统永远不会运行,也无法使其运行。你必须从头开始,从一个能够运行的简单系统着手。
Generally, refactoring involves implementing a set of standardized small-scale modifications where each change is a minor adjustment to the source code of a computer program. These adjustments typically maintain the software’s existing functionality or, at the very least, do not alter its adherence to functional specifications. The author of Refactoring To Patterns, Joshua Kerievsky, wrote the following:
通常,重构涉及实施一系列标准化的、小规模的修改,其中每次变更是对计算机程序源代码的微小调整。这些调整通常保持软件的现有功能,或者至少不会改变其遵循功能规范的情况。重构到模式(Refactoring To Patterns)的作者约书亚·凯里夫斯凯(Joshua Kerievsky)写道:
“By continuously improving the design of code, we make it easier and easier to work with. This is in sharp contrast to what typically happens: little refactoring and a great deal of attention paid to expediently add new features. If you get into the hygienic habit of refactoring continuously, you’ll find that it is easier to extend and maintain code.”
通过不断改进代码设计,我们让代码越来越易于使用。这与通常发生的情况形成鲜明对比:重构很少进行,而大量注意力都集中在快速添加新功能上。如果你养成持续重构的卫生习惯,你会发现扩展和维护代码会更容易。
Splitting the whole domain into many subdomains is the first step of this process and is called context mapping.
将整个领域划分为多个子域是此过程的第一步,称为上下文映射。
It’s important to clarify that dividing a domain into multiple subdomains doesn’t necessarily require creating multiple autonomous services. The implementation could take the form of a modular monolith or a microservices-based solution. What truly matters is ensuring that a bounded context remains self-contained and does not span across multiple services or modules.
重要的是要明确,将领域划分为多个子域并不一定需要创建多个自治服务。实现形式可以是模块化单体或基于微服务的解决方案。真正重要的是确保一个限界上下文保持自包含,并且不跨越多个服务或模块。
Context mapping  上下文映射
Context mapping is a technique used to visualize and understand the relationships and interactions between bounded contexts within a system. It involves creating a map that highlights how contexts relate to each other, identifies integration points, and exposes potential issues. This map becomes a critical tool in managing the complexity of large systems.
上下文映射是一种用于可视化和理解系统内限界上下文之间关系和交互的技术。它涉及创建一张地图,突出显示上下文如何相互关联,识别集成点,并揭示潜在问题。这张地图成为管理大型系统复杂性的关键工具。
Drawing this map is not an easy task, however, and you should follow a series of steps to execute in a loop until you and your team reach a consensus on the outcome.
绘制这张地图并非易事,然而,你应该遵循一系列步骤,并在一个循环中执行,直到你和你的团队就结果达成共识。
As a first step, identify the bounded contexts within your system. Each context should have a clear boundary and a specific domain model. Once you have your boundaries, you can move on to the next step, which could seem daunting at first. It involves defining how these contexts interact with each other. Are they dependent on each other? Do they share data or services?
第一步是识别系统中的边界上下文。每个上下文都应该有明确的边界和特定的领域模型。一旦你确定了边界,就可以进入下一步,这最初可能看起来令人望而生畏。它涉及定义这些上下文如何相互交互。它们是否相互依赖?它们是否共享数据或服务?
Once you overcome this task with a reasonable, understandable web of connections, you should try to highlight the points where contexts integrate or need to communicate.
一旦你通过一个合理且易于理解的连接网络克服了这项任务,你应该尝试突出上下文集成或需要通信的点。
Lastly, you should be able to draw a visual representation of the contexts and their relationships. At the end of this chapter, you will end up with a complete diagram that illustrates the flow of information and its dependencies, as shown in Figure 3.12. However, before going straight to it, let’s break it up into smaller steps so as to fully understand context mapping.
最后,你应该能够绘制出上下文及其关系的视觉表示。在本章结束时,你将得到一个完整的图表,它说明了信息的流动及其依赖关系,如图 3.12 所示。然而,在直接进入它之前,让我们将其分解为更小的步骤,以便充分理解上下文映射。
Firstly, Figure 3.4 shows how we could draw the context map of our ERP using the bounded contexts of customer, sales, warehouse, and shipping.
首先,图 3.4 展示了我们如何使用客户、销售、仓库和运输的限界上下文来绘制 ERP 的上下文地图。
Types of subdomains  子域类型
In our list of tasks to achieve a good mapping, the first step is to define specific domain models. However, what does that mean?
在我们的任务列表中,为了实现良好的映射,第一步是定义具体的领域模型。然而,这意味着什么呢?
It means that every bounded context fills a specific role in your architecture, and you have to determine the importance of each one. This involves identifying which bounded contexts represent your core business logic, which ones support that core, and which ones are more generic in nature. By doing this, you can prioritize your efforts and resources effectively.
这意味着每个限界上下文都在你的架构中扮演着特定的角色,你必须确定每个上下文的重要性。这包括识别哪些限界上下文代表你的核心业务逻辑,哪些支持这些核心逻辑,以及哪些更具有通用性质。通过这样做,你可以有效地优先考虑你的努力和资源。
To achieve this, you need to analyze each bounded context and categorize it into one of the various subdomain types. This categorization helps you understand the strategic significance of each part of your system. Subdomains represent specific areas within a domain. They correspond to individual bounded contexts with their own set of rules and logic.
要实现这一点,你需要分析每个限界上下文,并将其归类为各种子域类型中的一种。这种分类有助于你理解系统每个部分的战略意义。子域代表领域内的特定区域。它们对应具有自己规则和逻辑的独立限界上下文。
In context mapping, there are several types of subdomains you can choose from based on their role in your system. These are as follows:
在上下文映射中,你可以根据它们在系统中的角色选择几种子域。具体如下:
* Core subdomain  核心子域
* Supporting subdomain  支持子域
* Generic subdomain  通用子域
By identifying which type each of your bounded contexts falls into, you can make informed decisions about how to approach their development, integration, and maintenance. For instance, you would likely invest more resources and innovation into your core domain, while perhaps looking for off-the-shelf solutions for generic domains.
通过识别每个限界上下文属于哪种类型,你可以就如何处理它们的开发、集成和维护做出明智的决策。例如,你可能会在核心域上投入更多资源和创新,而对于通用域则可能寻找现成的解决方案。
This process of identification and categorization is crucial as it forms the foundation of your context map, guiding your overall architectural strategy and helping to align your technical efforts with your business priorities. Also, it deeply impacts how you structure your teams and the members within each one. For example, the team working on the core domain will probably be composed of the more experienced developers at first and maybe, at a later point, you will move some of them to other teams to share knowledge.
这种识别和分类的过程至关重要,因为它构成了你上下文地图的基础,指导你的整体架构策略,并帮助你将技术工作与业务优先级相匹配。此外,它还深刻影响你如何组织团队以及每个团队中的成员。例如,负责核心领域的团队最初可能由经验更丰富的开发人员组成,而稍后,你可能会将其中一些人调到其他团队以分享知识。
Now that you understand context maps, let us see what exactly they are and what purposes they serve.
现在你已经了解了上下文映射,让我们来看看它们具体是什么以及它们的作用是什么。
Core subdomain  核心子域
The core subdomain is the heart of your business. It is where your company’s unique value proposition lies and where you have a competitive advantage. This is the most critical and complex part of your system, requiring the most attention and resources. For our ERP, the sales system is the core domain, as it is central to the business’ operations and success.
核心子域是您业务的中心。它体现了您公司独特的价值主张,也是您拥有竞争优势的地方。这是您系统中最关键和最复杂的部分,需要最多的关注和资源。对于我们 ERP 系统来说,销售系统是核心领域,因为它对业务运营和成功至关重要。
Supporting subdomain  支持子域
Supporting subdomains, while important, are not the primary focus of the business. They complement and enable the core subdomain but don’t provide the main competitive advantage. These subdomains are necessary for the business to function smoothly but aren’t where the company differentiates itself. In our ERP example, a customer service module would be a supporting subdomain – it’s crucial for customer satisfaction but not the main business driver.
支持子域虽然重要,但并非业务的主要焦点。它们补充并支持核心子域,但并不提供主要的竞争优势。这些子域对于业务的顺利运行是必要的,但并不是公司实现差异化的地方。在我们的 ERP 示例中,客户服务模块就是一个支持子域——它对于客户满意度至关重要,但不是主要的业务驱动因素。
Generic subdomain  通用子域
Generic subdomains are common across many businesses and aren’t specific to your particular enterprise. These are often areas where reinventing the wheel isn’t necessary, and you can leverage existing solutions or outsource them. The invoice system is a good example of a generic subdomain – it is essential for monitoring revenue, but it’s not where a brewery would focus its innovative efforts.
通用子域在许多企业中都很常见,并且并非特定于你的企业。这些通常是无需重新发明轮子的领域,你可以利用现有解决方案或外包。发票系统就是一个通用子域的例子——它对于监控收入至关重要,但啤酒厂不会将创新的重点放在这里。
Figure 3.5 shows a context map with the definition of every subdomain.
Understanding these different types of domains is crucial for effective context mapping and overall system design. It helps in prioritizing development efforts, allocating resources efficiently, and making strategic decisions about system integration and evolution. By recognizing which parts of your system fall into which subdomain categories, you can focus your innovative efforts where they matter most while finding efficient solutions for less critical areas.
理解这些不同类型的子域对于有效的上下文映射和整体系统设计至关重要。它有助于确定开发工作的优先级,高效分配资源,并就系统集成和演进做出战略决策。通过识别系统哪些部分属于哪些子域类别,你可以在最关键的地方集中创新努力,同时在不太重要的领域找到高效的解决方案。
Subdomains change over time
子域会随时间变化
What we designed in this chapter is the first context map based on the knowledge acquired during the conversations with the brewery’s business experts. It tries to satisfy the business’ actual needs. Over time, the knowledge of the domain will improve, and the business flows will change with or without requests from the business experts. So, our bounded contexts or their importance in the domain could change accordingly. Last but not least, if you worked with your teams’ rotations, every member should be capable of taking on almost any subdomains.
本章我们设计的是基于与啤酒厂业务专家对话期间所获得的知识的第一张上下文地图。它试图满足业务的实际需求。随着时间的推移,领域知识会不断改进,业务流程也可能会随着业务专家的请求或不请求而发生变化。因此,我们的边界上下文或其在领域中的重要性可能会相应地发生变化。最后但同样重要的是,如果你与团队进行了轮岗,那么每个成员都应该能够承担几乎所有子领域的工作。

Dealing with communication between bounded contexts
处理有界上下文之间的通信
Now that you have a solid understanding of the importance of well-defined boundaries, we can move on to the last aspect of bounded contexts: communication. To build a cohesive system, these bounded contexts must interact effectively. That is why proper communication between bounded contexts is crucial. Strategic design offers some patterns to help you identify the best solutions based on our context of operation. Your goal here is to have a clear picture of how different parts of the system interact and relate with each other.
现在你已经对良好定义的边界的重要性有了扎实的理解,我们可以继续探讨有界上下文的最后一个方面:通信。为了构建一个协调的系统,这些有界上下文必须有效互动。这就是为什么有界上下文之间的适当通信至关重要。战略设计提供了一些模式,帮助你根据我们的操作环境识别最佳解决方案。你的目标是在这里清晰地了解系统不同部分如何互动和相互关联。
Importance of correct communication
正确沟通的重要性
Effective communication between bounded contexts ensures that the system functions as a unified whole. When bounded contexts fail to communicate correctly, inconsistencies and integration issues arise, leading to a fragmented system. Proper communication mechanisms help in the following ways:
限界上下文之间的有效沟通确保系统能够作为一个整体运行。当限界上下文无法正确沟通时,会出现不一致和集成问题,导致系统碎片化。正确的沟通机制有助于以下方面:
* Maintaining consistency: Ensuring that data and behavior are consistent across the system
保持一致性:确保数据和行为在整个系统中保持一致
* Enhancing flexibility: Allowing bounded contexts to evolve independently without breaking the system
增强灵活性:允许限界上下文独立演进而不破坏系统
* Reducing coupling: Minimizing dependencies between different parts of the system, making it easier to manage and refactor
减少耦合:最小化系统不同部分之间的依赖关系,使其更易于管理和重构
* Improving clarity: Providing clear interaction patterns, helping in understanding and maintaining the system
提高清晰度:提供清晰的交互模式,有助于理解和维护系统
Communication patterns  通信模式
These strategic patterns are high-level design strategies used to address and manage the relationships between bounded contexts. They provide a blueprint for handling integration, collaboration, and governance across contexts. Some of the most relevant include the following:
这些战略模式是用于处理和管理限界上下文之间关系的高级设计策略。它们为跨上下文处理集成、协作和治理提供了蓝图。其中一些最相关的包括以下:
* Shared kernel  共享内核
* Customer-supplier  客户-供应商
* Conformist  遵从者
* Anticorruption Layer (ACL)
反腐败层 (ACL)
* Open Host Service (OHS)  开放主机服务 (OHS)
* Published language  出版语言
* Separate ways  分道扬镳
Shared kernel  共享内核
In the shared kernel pattern, two or more bounded contexts share a portion of the same domain model. This shared part is managed collaboratively by the teams responsible for each context. This pattern is useful when contexts have strong interdependency and require a common understanding of specific aspects of the model.
在共享内核模式中,两个或多个限界上下文共享部分相同的领域模型。这个共享部分由负责每个上下文的团队共同管理。当上下文之间有强相互依赖性,并且需要模型特定方面的共同理解时,这种模式很有用。
Using our ERP as an example, consider the warehouse and sales contexts that share common details about the beer and stock levels. This shared kernel ensures that both contexts have a consistent understanding of product data, reducing the risk of discrepancies. The warehouse context manages stock levels, beer details, and warehouse locations, while the sales context handles customer orders, order processing, and fulfillment.
以我们的 ERP 系统为例,考虑仓库和销售这两个共享啤酒和库存水平等共同信息的上下文。这个共享内核确保两个上下文对产品数据有统一的理解,从而降低差异风险。仓库上下文管理库存水平、啤酒详情和仓库位置,而销售上下文处理客户订单、订单处理和交付。
The shared kernel in this scenario includes details about the beer such as SKU, description, and price, which are critical for both contexts to function correctly.
在这个场景中,共享内核包括啤酒的详细信息,如 SKU、描述和价格,这些信息对两个上下文都能正常运行至关重要。
Figure 3.6 – Shared kernel example
图 3.6 - 共享内核示例
Customer-supplier  客户-供应商
The customer-supplier pattern establishes a clear upstream-downstream relationship between contexts. The upstream context provides services or data, while the downstream context depends on those services. The supplier (upstream) must ensure that the customer (downstream) can rely on its services, fostering a collaborative relationship.
供应商-客户模式在上下文之间建立了明确的上下游关系。上游上下文提供服务或数据,而下游上下文依赖这些服务。供应商(上游)必须确保客户(下游)能够依赖其服务,从而建立合作关系。
For instance, the customer context (supplier) provides customer information to the sales context (customer). The sales context depends on accurate customer data to manage orders effectively. The sales context manages orders and payment processing, while the customer context handles plafonds and special categorization. The customer context must ensure that customer information is accurate and available in a timely manner for the sales context to function correctly.
例如,客户上下文(供应商)向销售上下文(客户)提供客户信息。销售上下文依赖于准确的客户数据来有效管理订单。销售上下文管理订单和支付处理,而客户上下文处理限额和特殊分类。客户上下文必须确保客户信息准确并及时提供给销售上下文,以使其正常运行。
Figure 3.7 – Customer-supplier example
图 3.7 – 供应商-客户示例
Conformist  遵从者
In the conformist pattern, the downstream context (conformist) adopts the model and communication protocols of the upstream context without influencing it. This pattern is used when the downstream context has little control over the upstream context and must conform to its way of working.
在遵从者模式中,下游上下文(遵从者)采用上游上下文的模型和通信协议,而不影响其。当下游上下文对上游上下文控制力较弱,必须遵循其工作方式时,使用此模式。
For example, a third-party payment processing service dictates the data format and interaction protocols, and the internal payments context must conform to these requirements. The payment processing service (external) provides payment gateways, transaction processing, and fraud detection, while the internal payment context manages internal payment flows, user payment data, and transaction records. The internal payment context must adapt to the protocols and data formats specified by the external payment processing service to ensure seamless integration.
例如,第三方支付处理服务规定了数据格式和交互协议,内部支付上下文必须遵守这些要求。支付处理服务(外部)提供支付网关、交易处理和欺诈检测,而内部支付上下文管理内部支付流程、用户支付数据和交易记录。内部支付上下文必须适应外部支付处理服务指定的协议和数据格式,以确保无缝集成。
ACL
The ACL pattern introduces a layer that translates and adapts between the models of two bounded contexts. This layer prevents the downstream context from being corrupted by the upstream context’s model, allowing each context to maintain its integrity.
ACL 模式引入了一层翻译和适配层,用于在两个有界上下文的模型之间进行转换。这一层防止下游上下文被上游上下文的模型污染,允许每个上下文保持其完整性。
In our ERP platform, the sales context might use an ACL to translate data from the legacy CRM system into its own model. This ensures that the sales context is not polluted by the outdated CRM model. The legacy CRM system manages customer relationships, historical data, and sales interactions, while the sales context handles current sales processes, customer interactions, and order management. The ACL translates CRM data into the format and structure required by the sales context, ensuring data integrity and consistency.
在我们的 ERP 平台中,销售上下文可能会使用访问控制列表(ACL)将遗留 CRM 系统的数据翻译成自己的模型。这确保了销售上下文不会被过时的 CRM 模型污染。遗留 CRM 系统管理客户关系、历史数据和销售互动,而销售上下文处理当前的销售流程、客户互动和订单管理。ACL 将 CRM 数据翻译成销售上下文所需的格式和结构,确保数据完整性和一致性。
Figure 3.9 – ACL example
图 3.9 – ACL 示例
OHS
The OHS pattern involves exposing a bounded context’s capabilities through a well-defined service interface, making it an open host for other contexts to interact with. This pattern promotes loose coupling and clear contracts between contexts.
OHS 模式通过一个定义良好的服务接口暴露有界上下文的能力,使其成为其他上下文交互的开放主机。这种模式促进了上下文之间的松散耦合和清晰的契约。
For instance, the shipping context might provide an OHS that allows other contexts, such as sales and warehouse, to request shipping services through a standard API. The shipping context manages shipping rates, carriers, and tracking information. The sales context requests shipping services for order fulfillment, and the warehouse context requests shipping information for stock transfers and replenishments. The shipping context exposes its services via an API, enabling other contexts to interact with it without tight coupling.
例如,在运输上下文中,可能会提供一个 OHS,允许其他上下文(如销售和仓库)通过标准 API 请求运输服务。运输上下文管理运输费率、承运商和跟踪信息。销售上下文为订单履行请求运输服务,仓库上下文为库存转移和补货请求运输信息。运输上下文通过 API 公开其服务,使其他上下文能够与其交互而不存在紧密耦合。
Figure 3.10 – OHS example
图 3.10 – OHS 示例
Published language  已发布的语言
The published language pattern entails defining a shared language (a set of common terms and data structures) that multiple bounded contexts use for communication. This shared language reduces misunderstandings and integration complexity.
已发布的语言模式涉及定义一个共享语言(一组通用术语和数据结构),多个限界上下文使用它进行通信。这种共享语言减少了误解和集成复杂性。
In a microservices architecture, a common event schema might be used for inter-service communication. This ensures that all services understand the event data consistently. For example, the sales context publishes order events when new orders are placed. The warehouse context consumes order events to update stock levels, and the invoice context consumes order events to generate invoices. The published language defines a common schema for order events, ensuring that all services can interpret the data correctly.
在微服务架构中,通常会使用一个通用的事件模式来进行服务间通信。这确保了所有服务都能一致地理解事件数据。例如,销售上下文在创建新订单时发布订单事件。仓库上下文消费订单事件来更新库存水平,而发票上下文消费订单事件来生成发票。发布语言定义了一个订单事件的通用模式,确保所有服务都能正确地解释数据。
Separate ways  分离方式
The separate ways pattern addresses the complexity that arises when two distinct parts of a system need to evolve independently. This pattern involves identifying bounded contexts within the domain that have minimal interaction and can be developed and maintained separately. By explicitly separating these contexts, teams can focus on the specific needs and rules of each domain area without being hindered by the intricacies of the others. This separation reduces coupling and allows for more agile and responsive development cycles, enabling each context to evolve at its own pace and in its own direction.
分离方式模式解决了系统两个不同部分需要独立演进时产生的复杂性。这种模式涉及在领域中识别具有最小交互的边界上下文,这些上下文可以独立开发和维护。通过明确分离这些上下文,团队可以专注于每个领域特定需求和规则,而不会被其他领域的复杂性所阻碍。这种分离减少了耦合,并允许更敏捷和响应迅速的开发周期,使每个上下文能够以自己的节奏和方向演进。
Final context map  最终上下文图
In Figure 3.12, you can see the complete context map of our ERP, describing the communication patterns between each bounded context. You can start with a pattern, such as conformist, and then change to OHS because you need to maintain a high level of separation between bounded contexts. When you need to communicate with external systems, you can choose to be conformist with them or to use an ACL to maintain your language inside your domain model. You are not forced to use just one of them; you have to use the right tool in the right place.
在图 3.12 中,你可以看到我们 ERP 的完整上下文图,描述了每个限界上下文之间的通信模式。你可以从一个模式开始,比如遵从型,然后切换到 OHS,因为你需要保持限界上下文之间的高度分离。当你需要与外部系统通信时,你可以选择遵从它们,或者使用 ACL 来在领域模型内部保持你的语言。你不必只使用其中一种;你必须在正确的位置使用正确的工具。
Figure 3.12 – Complete context map
图 3.12 – 完整的上下文图
Refactoring complex systems with domain-driven design principles requires careful consideration of how bounded contexts communicate. Proper communication ensures consistency, flexibility, and clarity, enabling the system to function cohesively. By leveraging strategic patterns such as shared kernel, customer-supplier, conformist, ACL, OHS, and published language, teams can manage the relationships and interactions between bounded contexts effectively.
使用领域驱动设计原则重构复杂系统需要仔细考虑有界上下文之间的通信方式。适当的通信确保一致性、灵活性和清晰性,使系统能够协同运作。通过利用共享内核、客户-供应商、遵从者、访问控制列表、操作手册和发布语言等策略性模式,团队可以有效地管理有界上下文之间的关系和交互。

Summary  摘要
In this chapter, you delved deep into the strategic patterns of domain-driven design, discovering how vital it is to establish a ubiquitous language to eliminate ambiguity and ensure clear communication among all team members.
在本章中,你深入探索了领域驱动设计的策略性模式,发现建立通用语言对于消除歧义和确保所有团队成员之间清晰沟通至关重要。
You learned that aligning the language used in your code with the domain models helps create a clear and comprehensible architecture, simplifying modifications and reducing errors. You learned how splitting large models into smaller, manageable bounded contexts is crucial for maintaining a system that can evolve without fear of unintended consequences. This approach allows you to isolate different business areas, making it easier to modify parts of your system without disrupting others. Finally, you were also introduced to several strategic patterns that help manage the relationships and interactions between these contexts. These include the shared kernel, customer-supplier, conformist, ACL, PHS, and published language patterns.
你了解到,将代码中使用的语言与领域模型保持一致有助于创建清晰易懂的架构,简化修改并减少错误。你学习了如何将大型模型拆分为更小、更易于管理的边界上下文,这对于维护一个能够无惧意外后果而演进的系统至关重要。这种方法使你能够隔离不同的业务领域,从而更容易地修改系统的部分内容而不影响其他部分。最后,你还接触到了几种帮助管理这些上下文之间关系和交互的战略模式。这些模式包括共享内核、客户-供应商、遵从者、访问控制列表(ACL)、渐进式发布(PHS)和发布语言模式。
Each of these patterns offers a blueprint for maintaining consistency, flexibility, and clarity across the system, ensuring it functions as a cohesive whole. Understanding these patterns equips you to identify the boundaries within your domain and effectively manage the complexity of large systems.
这些模式中的每一种都为在整个系统中保持一致性、灵活性和清晰性提供了蓝图,确保系统作为一个有机整体运行。理解这些模式使你能够识别领域内的边界,并有效地管理大型系统的复杂性。
In the next chapter, you will delve into tactical patterns, which will provide you with practical tools and techniques to implement the concepts you’ve learned so far.
在下一章中,你将深入战术模式,这将为你提供实用的工具和技术来实施你到目前为止学到的概念。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜流冰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值