1-2 什么是子域
什么是子域
为了实现其业务领域的目标,公司必须在多个 子域 中运作。子域是一个细粒度的业务活动区域。公司的所有子域构成了它的业务领域:它为客户提供的服务。实现单个子域不足以让公司取得成功;它只是总体系统中的一个组成部分。这些子域必须彼此交互,以实现公司在其业务领域的目标。例如,星巴克最受认可的可能是它的咖啡,但建立一个成功的咖啡连锁店需要的不仅仅是知道如何制作好咖啡。你还必须在有效的地点购买或租赁房地产,雇用人员,并管理财务以及其他活动。这些子域中没有一个能单独形成一家盈利的公司。所有这些都是一家公司能够在其业务领域竞争的必要条件。
子域的类型
正如软件系统包含各种架构组件(数据库、前端应用、后端服务等)一样,子域也承担着不同的战略/业务价值。领域驱动设计区分出了三种类型的子域:核心、通用和支撑。让我们从公司战略的角度来看看它们有何不同。
核心子域
核心子域 是指一家公司与其竞争对手的差异化做法。这可能涉及发明新产品或服务,或通过优化现有流程降低成本。
让我们以优步为例。最初,该公司提供了一种新颖的交通方式:共享汽车。随着竞争对手的追赶,优步找到了优化和演进其核心业务的方法:比如,通过匹配同一方向的乘客来降低成本。
优步的核心子域影响其商业底线。这是该公司如何将自己与其竞争对手区分开来的方式。这是该公司为客户提供更好的服务和/或最大限度地提高其利润率的战略。为了保持竞争优势,核心子域涉及到发明、智能优化、业务知识或其他知识产权。
考虑另一个例子:谷歌搜索的排名算法。在撰写本文时,谷歌的广告平台占其利润的大部分。Google Ads 并不是一个子域,而是一个由多个子域组成的独立业务领域,这些子域在 Google 的母公司 Alphabet 所涉足的云计算服务 (Google Cloud Platform)、生产力和协作工具 (Google Workspaces) 以及其他领域中被运营。但谷歌搜索及其排名算法呢?虽然搜索引擎不是付费服务,但它是 Google Ads 最大的展示平台。它提供优秀搜索结果的能力是驱动流量的原因,因此,它是广告平台的一个重要组成部分。由于算法中的 bug 导致不理想的搜索结果或竞争对手推出了更好的搜索服务,这将会损害广告业务的收入。因此,对于谷歌来说,排名算法是一个核心子域。
复杂度。一个简单的核心子域,只能提供短暂的竞争优势。因此,核心子域天然是复杂的。继续以优步为例,该公司不仅通过共享汽车创造了一个新的市场空间,还通过有针对性地使用技术,颠覆了一个有几十年历史的大一统的设施--出租车行业。通过了解其业务领域,优步能够设计出一种更加可靠和透明的出行方式。一个公司的核心业务应该有着很高的进入壁垒;竞争对手应该很难复制或模仿该公司的解决方案。
竞争优势的来源。值得注意的是,核心子域不一定是技术性的。并非所有的业务问题都能通过算法或其他技术解决方案得到解决。一个公司的竞争优势可以来自于不同的来源。
例如,设想一家在线销售其产品的珠宝制造商。虽然网店很重要,但它并不是核心子域。珠宝设计才是。该公司可以使用已有的现成的网上商店引擎,但它不能将其珠宝的设计外包。设计才是客户购买珠宝制造商的产品并记住该品牌的原因。
作为一个更复杂的例子,设想一家专门从事欺诈 人工 检测的公司。该公司训练它的分析师去检查有问题的文件并标出潜在的欺诈案件。你正在构建分析师工作用的软件系统。这个软件系统是核心子域吗?不。核心子域是分析师正在做的工作。你正在构建的系统与欺诈分析无关,它只是显示文件并跟踪分析师的意见。
核心子域 VS 核心域
核心子域也被称为核心域。例如,在最初的领域驱动设计这本书中,Eric Evans 交替使用“核心子域”和“核心域”。尽管术语“核心域”经常被使用,但出于多种原因,我更喜欢使用“核心子域”。首先,它是一个 子域,我更愿意避免与 业务领域 混淆。其次,正如你将在第 11 章中学习到的那样,子域随着时间的推移而演化并改变其类型的情况并不少见。例如,核心子域可以变成通用子域。因此,说 "一个 通用 子域演变成了一个 核心 子域 "比说 "一个通用 子域 演变成了一个核心 域 "更直截了当。
通用子域
通用子域 是所有公司都在以相同方式进行的业务活动。与核心子域一样,通用子域通常很复杂且难以实现。然而,通用子域并不能为公司提供任何竞争优势。这里不需要创新或优化:经过实战检验的实施方案广泛存在,所有公司都在使用它们。
例如,大多数系统都需要对其用户进行认证和授权。与其发明一个专用的认证机制,不如使用一个现有的解决方案更加合理。这样的解决方案可能更加可靠和安全,因为它已经被许多有相同需求的其他公司测试过了。
回到珠宝制造商在线销售其产品的例子,珠宝设计是核心子域,但在线商店是通用子域。使用与竞争对手相同的在线零售平台——相同的通用解决方案——不会影响珠宝制造商的竞争优势。
支撑子域
顾名思义,支撑子域 支持公司的业务。然而,与核心子域相反,支撑子域并不提供任何竞争优势。
例如,考虑一家在线广告公司,其核心子域包括将广告与访问者相匹配,以优化广告效果以及最大限度地降低广告空间成本。然而,为了在这些领域获得成功,公司需要对其创意材料进行编目。公司存储和索引其物理创意材料的方式,如横幅和着陆页(landing pages),并不影响其利润。在该领域没有什么可以发明或优化的。另一方面,创意目录对于实施公司的广告管理和服务系统至关重要。这使得内容编目解决方案成为该公司的支撑子域之一。
支撑子域的显着特征是其解决方案业务逻辑的复杂程度。支撑子域很简单。它们的业务逻辑主要类似于数据输入屏幕和 ETL(提取、转换、加载)操作;也就是所谓的 CRUD(创建、读取、更新和删除)接口。这些活动领域不为公司提供任何竞争优势,因此不需要高的进入门槛。
子域的比较
现在我们对这三种类型的业务子域有了更深入的了解,让我们从其他角度来探讨它们的差异,看看它们是如何影响战略软件设计决策的。
竞争优势
只有核心子域才能为公司提供竞争优势。核心子域是公司区别于其竞争对手的战略。
根据定义,通用子域不能成为任何竞争优势的来源。这些是通用的解决方案——公司及其竞争对手使用的相同解决方案。
支撑子域的进入门槛低,也不能提供竞争优势。通常,公司不会介意竞争对手复制其支撑子域——这不会影响其在行业中的竞争力。相反,从战略上讲,公司更希望其支撑子域是通用的、现成的解决方案,从而消除了要设计和构建支撑子域实现的需求。你将在第 11 章中详细了解到支撑子域变成通用子域的情况,以及其他可能的子域间的转换。附录 A 将介绍这种情况的一个真实案例。
一个公司能够解决的问题越复杂,它所能提供的商业价值也就越大。这些复杂的问题并不仅限于向消费者提供服务。也可以是,例如,使企业更加优化和高效。比如,提供与竞争对手相同水平的服务,但运营成本更低,也是一种竞争优势。
复杂度
从更技术的角度来看,识别组织的子域很重要,因为不同类型的子域具有不同级别的复杂度。在设计软件时,我们必须选择能适应业务需求复杂度的工具和技术。因此,确定子域对于设计一个完善的软件解决方案至关重要。
支撑子域的业务逻辑很简单。一般是基本的 ETL 操作和 CRUD 接口,业务逻辑一目了然。通常,它不会超出验证输入或将数据从一种结构转换为另一种结构的复杂度范围。
通用子域则要复杂得多。别人投入时间和精力来解决这些问题肯定是有原因的。这些解决方案既不简单也不微不足道。例如,考虑一下加密算法或认证机制。
从知识可用性的角度来看,通用子域是“已知的未知”。这些是你知道的你不了解的事情。此外,这些知识很容易获得。你可以使用行业公认的最佳实践,或者,如果有必要,聘请专门从事该领域的顾问来帮助设计定制解决方案。
核心子域很复杂。它们应该尽可能地让竞争对手难以复制——公司的盈利能力取决于它。这就是为什么从战略上讲,公司将寻求解决复杂的问题作为他们的核心子域。
有时,区分核心和支撑子域可能是一个挑战。复杂性是一个有用的指导原则。想知道某个子域是否真的可以变成一个独立业务(side business)?问问是否会有人为它花自己的钱付费?如果是这样,这就是一个核心子域。类似的推理也适用于区分支撑子域和通用子域:捣鼓自己的实现,而不是集成一个外部的实现,会不会更简单、更便宜?如果是这样,这就是一个支撑子域。
从更技术的角度来看,识别核心子域非常重要,因为其复杂度会影响软件的设计。正如我们前面所讨论的,核心子域不一定与软件相关。识别软件相关核心子域的另一个有用的指导原则是:评估你需要在代码中建模和实现的业务逻辑的复杂度。业务逻辑是否类似于用于数据输入的 CRUD 接口,还是不得不实现由复杂业务规则和不变量(invariants)所编排的复杂算法或业务流程?前者是支撑子域的标志,而后者是典型的核心子域。
图 1-1. 代表了三种类型的子域在业务差异化和业务逻辑复杂度方面的相互作用。支撑子域和通用子域之间的交集是一个灰色区域:它可以走任何一条路。如果支撑子域的功能存在一个通用的解决方案,那么所产生的子域类型取决于整合通用解决方案的成本是否比从头开始实现该功能更简单和/或更便宜。
图 1-1. 三类子域的业务差异化和业务逻辑复杂度 易变性
如前所述,核心子域会经常变化。如果一个问题在第一次尝试时就能轻松解决,那么它可能不是一个好的竞争优势——竞争者会迅速赶上。因此,核心子域的解决方案不断涌现。不同的实现方案必须被尝试、完善和优化。而且,核心子域的工作永远没有已做完的那天。公司不断创新和演化核心子域。这些演化是以增加新功能或优化现有功能的形式出现的。无论哪种方式,其核心子域的不断演变对于一个公司保持领先于竞争对手至关重要。
与核心子域相反,支撑子域并不经常变化。它们不为公司提供任何竞争优势,因此,与投资于核心子域的相同努力相比,支撑子域的演变提供了微不足道的商业价值。
尽管有现成的解决方案,但通用子域也会随着时间而改变。这些变化会以安全补丁、bug 修正或针对一般问题的全新解决方案的形式出现。
解决方案的实现策略
核心子域为公司提供了与行业内其他参与者竞争的能力。这是一项对业务至关重要的责任,但这是否意味着支撑和通用子域并不重要?当然不是。所有子域都是公司在其业务领域上工作所需要的。子域就像基础的构建块:拿走一个,整个结构就可能坍塌。也就是说,我们可以利用不同类型子域的固有属性来选择实现的策略,以最有效的方式实现每种类型的子域。
核心子域必须在内部实施。它们不能被购买或采纳(adopted);这将破坏竞争优势的概念,因为公司的竞争对手也能做到这一点。
将核心子域的实施工作外包也是不明智的。它是一项战略投资。在核心子域上偷工减料不仅在短期内有风险,而且从长远来看会产生致命的后果:例如,一个无法支持公司目标的难以维护的代码库。应该指派组织中最具技术的人才从事其核心子领域的工作。此外,在内部实现核心子域可以使公司能更快地改变和演进解决方案,从而在更短的时间内建立竞争优势。
由于核心子域的需求预计会经常不断地变化,因此解决方案必须可维护且易于演进。所以,核心子域需要以最先进的工程技术来实现。
由于通用子域是很难但已经解决了的问题,所以购买现成的产品或采用开源的解决方案比投入时间和精力在内部实现它更有成本效益。
由于缺乏竞争优势,避免在内部实现支撑子域也是合理的。然而,与通用子域不同,很可能没有现成的解决方案可用。因此,一个公司可能别无选择,只能自己实现支撑子域。也就是说,由于支撑子域业务逻辑的简单性和变化的不频繁性,很容易出现偷工减料的情况。
支撑子域并不需要精心设计的模式或其他高级工程技术。一个快速应用开发框架就足以实现其业务逻辑,也不会引入意外的复杂性。
从人员配置的角度来看,支撑子域不需要高度熟练的技术能力,并提供了一个培训新人的好机会。把你团队中那些在处理复杂挑战方面富有经验的工程师留给核心子域。最后,业务逻辑的简单性使支撑子域成为外包的良好候选。
表 1-1. 总结了三种类型子域的不同方面。
表 1-1. 三种子域的区别
| 子域类型 | 竞争优势 | 复杂度 | 易变性 | 实现 | 问题 |
|---|---|---|---|---|---|
| 核心 | 是 | 高 | 高 | 内部 | 感兴趣的 |
| 通用 | 否 | 高 | 低 | 购买/采用 | 已解决的 |
| 支撑 | 否 | 低 | 低 | 内部/外包 | 明显的 |
识别子域的边界
正如你已经看到的,识别子域和它们的类型可以大大帮助你在构建软件解决方案时做出不同的设计决策。在后面的章节中,你会学到更多利用子域来简化软件设计过程的方法。不过,我们究竟如何识别子域和它们的边界呢?
子域及其类型是由公司的商业战略确定的:它的业务领域以及它如何做到差异化以与同一领域中的其他公司竞争。在绝大多数的软件项目中,子域以这样或那样的方式"就在那里了"。然而,这并不意味着识别它们的边界总是容易和直接的。如果你向一位 CEO 要一份他们公司的子域清单,你可能会收到一个白眼。他们并不了解这个概念。因此,你必须自己进行领域分析,以识别和归类起作用的子域。
一个好的起点是公司的部门和其他组织单位。例如,一家网上零售店可能包括仓储、客户服务、分拣、运输、质量控制和渠道管理部门等。然而,这些都是相对粗粒度的活动领域。以客户服务部门为例。可以合理地假设它将是一个支撑子域,甚至是一个通用子域,因为这个功能经常被外包给第三方供应商。但这些信息足以让我们做出合理的软件设计决策吗?
提炼子域
粗粒度的子域是一个很好的起点,但魔鬼就在细节中。我们必须确保我们不会遗漏隐藏在错综复杂的业务功能中的重要信息。让我们再回到客户服务部门的例子。如果我们调查它的内部运作,我们会发现一个典型的客户服务部门是由更细粒度的组件组成的,例如服务台系统、轮班管理和调度、电话系统等等。当被视为单个子域时,这些活动可以有不同的类型:服务台和电话系统是通用子域,而轮班管理则是支撑子域,然而一个公司可能会开发巧妙的算法,将工单转给过去成功处理过类似案例的专员去处理。路由算法需要分析面临的案例并从过去经验中识别出与之相似之处——这两者都是不简单的任务。由于路由算法使公司能够提供比其竞争对手更好的客户体验,所以路由算法是一个核心子域。这个例子在 图1-2. 中展示。
图 1-2. 分析一个疑似通用子域的内部运作,可以找到更细的核心子域、支撑子域和两个通用子域 另一方面,我们不能无限制地向下钻研,在越来越低的粒度水平上寻找洞见。你应该什么时候停止呢?
将子域作为有相关性的用例
从技术角度来看,子域类似于一组相互关联、连贯的用例。这样的用例集通常涉及相同的参与者、业务实体,并且它们都操作一组密切相关的数据。
考虑一下 图1-3. 所示的信用卡支付网关的用例图。这些用例被它们所处理的数据和所涉及的参与者紧密地结合在一起。因此,所有的用例都构成了信用卡支付子域。

图 1-3. 信用卡支付子域的用例图
你是否应该始终努力识别这种非常聚焦的子域边界?对于核心子域来说,这绝对是必要的。核心子域是最重要的、易变的和复杂的。我们必须尽可能地提炼它们,因为这将使我们能够提取所有的通用和支撑功能,并将精力投入到更有针对性的功能上。
对于支撑和通用子域来说,提炼的过程可以稍微放宽。如果进一步钻研并没有发现任何可以帮助你做出软件设计决策的新见解,那么这可能是一个停下来的好地方。例如,当所有拆分出的细粒度子域与原始子域的类型相同时,就是这种情况。
考虑一下 图1-4. 的例子。进一步提炼服务台系统子域的作用不大,因为它没有揭示任何新的战略信息,一个粗放的、现成的工具将被作为解决方案而使用。

图 1-4. 对服务台系统子域的提炼,揭示了通用的内部组件
识别子域时要考虑的另一个重要问题是我们是否需要所有的子域。
专注于本质
子域是一种缓解软件设计决策过程的工具。所有组织都可能拥有相当多的与软件无关的业务功能来推动他们的竞争优势。我们在本章前面讨论的珠宝制造商就是一个例子。
在寻找子域时,重要的是要确定与软件无关的业务功能,承认它们就是如此,并把重点放在与你所从事的软件系统有关的业务方面。
浙公网安备 33010602011771号