假设有一个农业机械零件的批发商。他们建立了一个 B2B 网上商店,供经销商和机器维修公司订购。在他们无处不在的统一语言与术语中,订单代表了这个自动化流程:它使客户能够挑选产品,应用正确的折扣,并将其推送到 送货。 如果这个批发商与竞争对手合并:他们是老牌企业,拥有稳固的客户群和庞大的目录。后者也有一个订购系统,但它更传统:客户打电话,客户经理输入订单,应用任意折扣,然后将其推送到送货。 合并后的公司仍然只有一个 Sales销售 子域,但它现在有两个 Sales Bounded Contexts销售上下文。它们两个模型中都有像 Order 和 Discount 这样的概念,这些概念的含义基本相同。两个批发商的员工就订单或折扣达成一致。但是他们有不同的使用流程,他们在表单中输入不同的信息,并且有不同的业务规则。 在技术意义上,差异体现在对象设计、方法、工作流、应用折扣的逻辑、数据库表示和一些统一语言与术语中。不过,它运行得更深入:对于软件设计人员来说,要在任一有界上下文中都富有成效,他们必须了解这两种模型之间的许多区别:有界上下文代表可理解边界。( 上下文为王 ) 在一个完美设计的系统中,我们理想的有界上下文通常会与子域的边界很好地对齐。但有界上下文实际上是遵循系统演进的。 系统随着公司组织发展。不幸的是,这个发展过程中呈现的新概念经常不以符合我们设计的方式出现,我们对变得更加不一致的代码感到不舒服了,只要我们有时间就想要统一这些新旧概念并制作干净的抽象,因为我们应该创建一个设计良好的系统。 子域与有界上下文区别 上面的例子简单地表明,单个子域实际可以由多个有界上下文表示。 领域与有界上下文区别:有界上下文可能与应用或服务边界一致,也可能不一致。同样,它们可能与领域边界对齐,也可能不对齐。领域存在于问题空间中。领域是组织如何看待其活动和专业领域的方式;而有界上下文是属于解决方案空间的一部分,它们是经过深思熟虑的设计选择。 作为系统设计师,您选择这些边界来管理系统的可理解性,通过使用不同的模型来解决领域的不同方面。 对于上面案例,系统设计者可以:
- 合并两个销售上下文,
- 将一个迁移到另一个里面,
- 建立一个新的销售上下文来取代两者,
- 推迟这项努力,
- 或者不做任何事情并保留现有的两个上下文。
权衡 权衡设计选择的后果是:当开发人员需要帮助解决问题时,他们必须让其他开发人员跟上进度。每个开发人员在另一个有界上下文中工作时,都希望他们必须进行上下文切换。毕竟,它们的术语和概念彼此不同,即使它们共享相似的术语。上下文切换是有代价的,如果您整天处理不同的项目,您可能已经体验到了这种代价。但是在这里,因为上下文显然是有界的,所以这并没有引起很多问题。有时,通过向具有相似上下文背景(但有界上下文不同)的另一位开发人员解释问题,解决方案变得显而易见。 一般 IT 系统中的多个有界上下文 交易系统是一个极端的例子,您不会遇到许多环境,其中具有 20 个有界上下文的单个子域是有意义的。但是在许多常见情况下,您应该考虑拆分域。如果在您的公司中,个人客户和企业客户的定价规则不同,那么在单个域模型中统一这些规则的努力可能会花费更多。或者在薪资系统中,受薪员工和计时员工的规则和流程不同,您最好拆分此域。 总结 正确的上下文边界遵循业务的轮廓。不同的区域在不同的时间以不同的速度变化。随着时间的推移,看起来相似的东西可能会以令人惊讶和出人意料的方式产生分歧(如果有机会的话)。将概念压缩到单个模型中是有限制的。通过使其服务于两种不同的业务需求并持续承担协调成本,您正在使模型复杂化。这是一种隐藏的依赖债务。 我们可以在这里推导出两种启发式方法:
- 限界上下文/有界上下文不应该服务于设计师的感性和对完美的需求,而应该提供商业机会。
- 变化率启发式:考虑组织有界上下文,以便它们管理以相同速度变化的相关概念。