关于设计和构建自适应的社会—技术系统(adaptive, socio-technical systems)的第二个视角,涉及领域驱动设计(Domain-Driven Design,DDD)。正如 Eric Evans 在其著作《Domain-Driven Design: Tackling Complexity in the Heart of Software》[2.1] 中所解释的那样,DDD 聚焦于基于领域模型来设计软件。DDD 的核心思想是:要构建更好的软件,其设计必须与业务领域、业务需求以及业务战略保持一致。在直接投入开发一个满足用户需求的技术解决方案之前,首先有必要理解问题领域,而这正是 DDD 特别有价值的地方。
通过协作获取领域知识
DDD 的一个关键部分,是领域专家与开发团队之间的协作,通过分析问题领域来获得共享的领域知识。所谓问题领域(problem domain)或业务领域(business domain),指的是一个组织的范围或关注区域。在第 1 章“用 Wardley Mapping 制定业务战略”中介绍的会议活动策划解决方案示例里,问题领域或业务领域就是会议策划。领域知识是通过一种共享的、面向业务领域的语言来描述的——也就是统一语言(ubiquitous language,图 2.1),这种语言不包含任何技术术语。
图 2.1 通过与领域专家协作获取领域知识
DDD 带来了许多新术语,需要花一些时间去掌握和理解。走上 DDD(以及 Wardley Mapping!)的学习之路,可能会让人感到相当不知所措。然而,DDD 为战略规划中的协作提供了一套词汇体系,因此很值得投入精力去学习。在这个背景下,将 DDD 与 Wardley Mapping 结合起来,会在以下几个方面非常有帮助:
- 利用 Wardley Map 的语境化可视化能力,可以为进入 DDD 提供一个易于跟随的入口。
- DDD 帮助组织应用 Wardley Mapping 的教义原则,使其获得处理战略问题的组织适应力,并能够快速适应变化。
- 第 3 章“使用战略性领域驱动设计设计解决方案空间”将讨论如何把限界上下文(bounded contexts)映射到 Wardley Map 的演进阶段上。
领域驱动设计的模式与实践
DDD 包含一系列由战略设计与战术设计构成的模式与实践。图 2.2 展示了为了配合 DDD 而调整过的 Wardley Map:在地图的 y 轴上额外加入了一层。这个层并不是 Wardley Map 官方组成部分。相反,它只是为了提供一条易于跟随的路径,帮助读者进入战略设计与战术设计的领域:从上方的战略设计模式开始,再逐步往下进入战术设计模式。如果这一层让你感到困惑多于帮助,你完全可以忽略它。
图 2.2 作为价值链一部分的战略设计与战术设计
战略设计与战术设计提供了一套模式和实践,用于分析和发现问题领域,并设计与实现一个尽可能贴合问题领域的软件解决方案。y 轴这一额外层的顶部,暗示应从战略设计的问题空间开始。在与 Wardley Mapping 的关联中,问题领域或业务领域由用户及其用户需求构成。即便如此,两者也并不彼此冗余。在战略设计的问题空间中,分析问题领域并发现子域至关重要。本章聚焦于战略设计的问题空间。
再往下走,图 2.2 就切换到了战略设计的解决方案空间。问题空间关注的是“要解决哪些问题”,而解决方案空间则关注“如何解决这些问题”。战略设计的解决方案空间,关心的是做出高层设计决策,将系统拆分为模块化组件(即限界上下文),并映射它们之间的集成关系(即上下文映射,context maps)。
再往下一步,就进入了战术设计模式阶段。战术设计模式支持的是底层设计决策;这些决策的目的,是设计并实现一个尽可能贴合问题领域的解决方案。战术设计模式为在代码中实现领域模型提供了构建模块。战略设计聚焦于分析、发现、拆分和映射等活动,而战术设计的核心活动则是设计与实现。尽管图 2.2 将战术设计作为新增 y 轴层的一部分纳入其中,但它通常并不会在 Wardley Map 中体现为价值链组件。它出现在图中,仅仅是为了在视觉上说明它的分类位置。
如果跳过战略设计的模式与实践,直接进入战术设计,就会带来一种风险:在对问题领域理解尚浅的情况下就去实现解决方案,并且把投入花在那些不提供差异化价值的部分上。因此,更明智的做法是先从战略设计开始,以获取所需的领域知识,并识别开发工作应优先投入的方向。战略设计帮助组织分析并理解问题领域,发现核心域,从而知道应该在何处进行最具战略意义的投入。
发现子域并映射其演进阶段
对业务领域进行提炼,可以通过把广泛而抽象的业务领域划分成更小、更具体的部分——也就是划分成子域——来降低复杂性并提升理解。子域是问题领域的子部分;然而,并不是所有子域都一样。有些子域相较其他子域,对业务具有更高的战略价值,这一点体现在它们的类型上:核心型(core)、支撑型(supporting)和通用型(generic)(图 2.3)。识别这些不同类型,有助于组织找出各个子域,并为其战略投资与开发工作排序优先级。发现子域,会把一个庞大的领域拆分成更小、更易管理的部分,并帮助识别出那些最值得进行战略投入的部分——也就是核心域。
图 2.3 子域类型及其解决方案的典型演进阶段
核心域
核心域是一个组织问题领域中最关键、对业务至关重要的部分。它通常为客户提供最多的价值,并使组织区别于竞争对手,从而赋予组织竞争优势。根据 Michael Porter 的观点,组织可以通过差异化优势或成本优势来实现竞争优势 [2.2]。竞争优势使公司能够在其所处市场中有效竞争,并维持长期成功。
一个问题领域可以包含一个,或者有时包含多个核心域。核心域通常较为复杂,因此竞争对手很难复制或模仿它。它也往往变化得相当频繁。核心域是组织最希望进行战略性投入的地方,也是最有机会进行创新的地方。反过来,核心域也正是 DDD 努力重点理解并细致建模的对象。从战略上说,它体现了业务的目的(“为什么”),正如 Wardley 战略循环中所描述的那样。
核心域是那类通常会被评估为应当内部构建的软件子域。最初,它的解决方案通常主要位于 Wardley Map 的 genesis 或 custom-built 演进阶段,因为它的差异化特征仍在被探索之中。然而,由于商业环境是动态变化的,核心域本身也会发生演进。随着核心域逐渐成熟,并在市场中确立地位,它可以演进到 product 阶段,甚至可能最终变成 commodity。此外,随着核心域不断演进,它会变得越来越标准化。到了这个时候,许多公司都可能提供相似的服务,因此核心域相较市场中的其他产品或服务,其差异化程度会下降。
图 2.4 展示了:随着核心域沿着 Wardley Map 的光谱向右侧演进,其差异化优势会逐渐降低,但成本优势则可能上升。实现成本优势,意味着企业能够以低于竞争对手的成本提供产品或服务。组织可以通过降低浪费成本(例如缺陷、不必要功能投入以及等待时间),或者降低偏差成本来实现降本;偏差成本包括那些由于未能达到预期标准、需求或用户预期结果而产生的成本。
图 2.4 一个不断演进的核心域:差异化优势下降,而成本优势上升
根据 Wardley 的教义原则,一切都是暂时的,今天的核心域不会永远保持为核心。由于组织身处一个快速变化的商业环境之中,核心域在未来某个时点可能会变得过时,或者被新的事物所替代。这一原则鼓励组织对变化保持警觉,并始终保持灵活与适应性,以在市场中维持竞争力。
在会议活动策划解决方案的语境下,诸如征文征稿管理、投稿处理、议题评审以及日程编排等用户需求,都属于核心域(图 2.5)。它们代表了该组织区别于竞争对手的差异化点,并在实现其此前定义的“帮助策划会议内容”这一目的中发挥着重要作用。如果对这些会议活动策划解决方案的部分采用现成产品、直接购买,或者外包给 utility 供应商,就可能会限制组织形成差异化的能力。相反,在内部为核心域定制构建软件,可以使组织交付一种专业化的、具备差异化特征的解决方案,从而形成竞争差异。这些核心域本身体现了复杂性,因为其解决方案中的业务逻辑超出了简单的 create–read–update–delete(CRUD) 模式,而且其所强制执行的业务规则,也不仅仅是基础输入校验那么简单。
图 2.5 会议活动策划示例中的核心型、支撑型和通用型子域
支撑型子域
支撑型子域用于支撑核心域。支撑型子域本身并不提供竞争优势,通常比核心域更简单,变化频率也更低。它也可能同样存在于竞争对手的产品或服务中。从本质上说,支撑型子域是专业化的,但不具备差异化。如果市场上存在高度可定制的产品或开源软件解决方案,那么对于支撑型子域而言,购买或使用现成产品是一个很好的做法。在这种情况下,支撑型子域通常主要处于 product + rental 演进阶段。如果需要一种更高程度、且无法产品化的专业化,那么为支撑型子域定制开发软件也是合理的——此时它会落入 custom-built 演进阶段。不过,在这种情况下,投入水平不应过高。支撑型子域对于组织成功是必要的,但它并不提供竞争优势。
在前述会议活动策划解决方案的例子中,与讲者进行沟通——例如通过消息回答问题——可以是一个支撑型子域的候选项(见图 2.5)。消息子域并不会为组织带来竞争优势,但它通过促进会议组织者与讲者在会议策划过程中的互动,支撑了核心域的成功。该子域的解决方案,也就是消息的来回发送,通常允许采用比较简单的 CRUD 方式,并只需简单的输入校验,其业务逻辑也相对简单。如果需要一定程度的专业化,那么一个简单的定制解决方案,例如基于 CRUD 的消息子域实现,辅以直接明了的输入校验和最少量的业务逻辑,就是完全合适的。
通用型子域
通用型子域是许多业务系统都会具备的一类子域(不只是竞争对手的问题领域中存在),例如认证或支付处理。这类子域广泛存在于众多业务系统中。因此,通用型子域并不是业务核心,也不会为业务提供竞争优势,但业务又离不开它们。这样的子域既不专业化,也不具差异化。它们本身可能很复杂,但它们的解决方案早已由别人构建出来。它们通常变化不频繁,且相当稳定。对于通用型子域,购买现成产品、使用开源软件,或者外包给 utility 供应商,都是合理的选择。相应地,通用型子域的解决方案通常主要位于 product + rental 或 commodity + utility 演进阶段。
对于会议活动策划解决方案这个例子而言,通过注册与登录来确保安全访问,就是一个潜在的通用型子域候选项(图 2.5)。这个子域不是业务核心,但会议活动策划解决方案如果没有注册与认证,就无法安全运行。很多业务系统都需要同样的注册与认证子域。它的解决方案包含复杂的业务逻辑,但市场上已经可以轻松获得若干满足这一需求的产品或服务。推荐的实践是:对此子域采用开源解决方案,或者将其外包给云托管的托管服务。此外,把这一职责卸载给现有解决方案,也使组织能够把开发精力集中在自己的核心域上。
表 2.1 总结了行业实践中针对每类子域的常见倾向;这些内容应被视为用于指导评估的启发式经验,而不是严格规定。
表 2.1 各子域类型的特征与启发式总结
图 2.5 中映射到各子域类型的演进阶段,以及演进特征(见表 1.1),都可以帮助组织初步判断某个特定子域属于哪一类。不过需要注意的是,系统中的每个组件始终处于变化状态,并且会随时间不断演进——子域也不例外。
结合子域类型与演进阶段做出 Build-or-Buy 决策
Wardley Mapping 强调,每个演进阶段都有不同的特征。不同特征要求在相应演进阶段采用不同方法。Wardley 建议:对于处于 genesis 和 custom-built 阶段的组件,应采用敏捷方法在内部构建;对于处于 product + rental 阶段的组件,应采用精益方法购买现成产品或使用开源方案;对于处于 commodity 阶段的组件,则应将其外包给 utility 供应商。1 这一教义原则可以通过引入 DDD 中的子域类型而得到进一步丰富。
- Simon Wardley 建议,在处理 commodity 演进阶段的组件时采用 Six Sigma 方法,这一点在“针对不同演进阶段使用合适的方法”这一教义原则中已有讨论。
DDD 强调,问题领域中的所有子域并不具有同等的战略价值——有些子域对业务差异化的贡献,显著高于其他子域。再次强调,具备差异化特征的核心域需要高强度的战略投入,并且是内部构建的强候选项;而那些不具差异化的子域,则很适合利用现有解决方案,除非它们要求极高程度的专业化。随着时间推移,核心域可能会从 custom-built 演进到 product 阶段,甚至最终变成 commodity。
如果仅仅根据某个价值链组件在演进轴上的位置来做“买还是建”(buy-versus-build)决策,就有可能忽略它对于业务的潜在关键性。例如,一个云服务提供商不会仅仅因为云服务通常已经是 commodity、理论上应当外包,就把自己的云服务(或者底层数据中心)外包给另一家云服务商。相反,云服务提供商更可能选择在内部构建自己的云服务,因为这些能力对于其业务而言属于核心且关键——即便随着其作为 utility 服务存在,其差异化程度可能已经下降(见图 2.4)。把核心域外包出去,会限制云服务提供商的差异化机会,并削弱其竞争优势。2 相反,当一个组织在为那些并非业务核心的 commodity 自行定制开发时,往往就会导致战略投入上的低效。
2. 尽管为了保持战略控制并支持差异化,通常更适合在内部构建核心域,但某些组织由于约束条件或战略选择,也可能会依赖现成产品或 SaaS 产品来覆盖其核心域的一部分。
现成产品和开源软件解决方案,未必天然就能满足组织的全部需求,但它们通常提供配置与定制能力。然而,如果对现成产品进行超出其核心用途的过度定制,成本可能会很高,并且会带来诸多风险,例如失去标准化、降低灵活性、受限于升级、出现性能问题、引入偶发复杂性等等。随着过度定制的发生,它们原本在效率上的优势也可能下降。相比对现成产品进行过度定制,一种替代方案是:将其使用范围限制在其设计之初所针对的场景内,而对那些现成产品未提供的功能,另行开发定制解决方案。因此,build-or-buy 决策有时并不是“建或买”这种二元选择,而是“建 + 买”。
内部构建 vs. Custom-Built 演进阶段
有时候,组织自己在内部构建的组件,究竟应当映射到哪里,会成为一个容易令人困惑的问题。一个直观的做法,是把它们映射到 custom-built 演进阶段。如果它们的市场仍在形成中、用户将它们视为新兴事物、由于新颖性和缺乏标准化而需要探索,或者它们需要持续创新来维持差异化,那么这么做是合理的。
然而,如果一个组织的核心域已经被感知为定义清晰、稳定并广泛存在,那么这些组件通常应被映射到 product 或 commodity 演进阶段,而不应仅仅因为组织选择在内部构建它们,就被视为 custom-built。换句话说,组件是否在内部构建,并不自动决定它处于 custom-built 阶段。演进阶段反映的是市场成熟度与用户感知,而不是内部开发决策。
除了映射出的演进阶段与子域类型之外,还可以通过颜色编码或图案的方式,在 Wardley Map 中标注每个组件当前所采用的方法(build、buy、outsource),如图 2.6 所示。
图 2.6 结合演进阶段与子域类型,可视化 build–buy–outsource 决策
将 build–buy–outsource 决策与演进阶段、子域类型结合起来进行可视化,有助于团队批判性地评估:当前在定制开发上的投入,是否真的花得值得。值得提出的关键问题包括:我们是否正在为那些不属于核心域的组件进行定制开发?对于不具差异化的支撑型子域,其专业化程度是否真的足以证明定制方案是合理的?
小结
本章介绍了与 Wardley Mapping 相结合的战略设计问题空间,如图 2.7 所总结的那样。
图 2.7 与 Wardley Mapping 结合的战略性 DDD 问题空间概览
在战略设计的问题空间中,领域专家与开发团队共同分析问题领域。与 Wardley Map 的价值链相联系,用户及其用户需求不仅构成了地图的锚点,也从 DDD 视角反映了问题领域。问题领域由若干子域构成。并非所有子域在业务差异化方面都同等重要。具备差异化特征的核心域,是问题领域中对业务至关重要的子域,它为组织提供竞争优势。
在本章中,第 1 章创建的会议活动策划解决方案 Wardley Map,被补充进了战略设计中的模式。本章分析了问题领域,并发现了其相应的核心型、支撑型与通用型子域。将子域类型映射到 Wardley Map 的演进阶段,有助于为战略投入排序优先级,并支持对子域解决方案做出 build–buy–outsource 决策。说到解决方案,下一章将讨论战略设计的解决方案空间。