

限界上下文的定义,需要从“限界”和“上下文”两个词的含义来理解。
限界就是领域的边界,而上下文则是语义环境
上下文表现了业务流程的场景片段,整个业务流程由诸多具有时序的活动组成,随着流程的进行,不同的活动需要不同的角色参与,并导致上下文因为某个活动的执行发生切换,形成了场景的边界。
因而,上下文其实是动态的业务流程被边界静态切分的产物。
限界上下文的边界就是领域模型的边界,它的目的就在于维护领域模型的一致性,这一目的与统一语言的作用重合,可以认为:统一语言在解空间的作用域针对每个限界上下文。
限界上下文和划分模块、划分子系统一样,是一种分而治之的手段,可以起到分离关注点的作用。
但限界上下文增加了一个要点,就是,它的目的还在于维护概念一致性。这也是限界上下文和传统方法的本质不同。
DDD认为,面对大规模的系统,全局概念一致性从根本上是不可能的。这是因为,人的认知能力是有限的。由于大型软件是团队协作开发的,因此这里其实是团队的认知能力。当系统规模增大时,团队规模也会相应增大,沟通难度会呈非线性增长。当系统达到一定规模,就超过了一个团队的认知能力,无法保证概念的一致性。
把大系统分解成若干子系统,每个子系统对应一个领域模型。每个模型的规模都不超过一个开发小组的认知负载。在每个子系统的内部实现概念的严格一致性,而不同系统内部之间则没有必要一致。
也就是说,不再追求全局一致性,而是退而求其次,只需追求局部的一致性,使概念不一致的问题得到合理管控,从而实现业务目标,这样就足够了。
限界上下文:用来封装通用语言和领域对象,提供上下文环境,保证在领域之内的一些术语、业务相关对象等有一个确切的含义,没有二义性。这个边界定义了模型的适用范围,使团队所有成员能够明确地知道什么应该在模型中实现,什么不应该在模型中实现。
设计微服务,可以先假定每个限界上下文对应一个微服务。然后,再综合考虑多方面的因素,决定是否需要进一步细分。
第一,不同的可伸缩性要求。
如果一个上下文里有些部分,需要随着使用情况,动态部署到更多的容器,比如“双十一”促销的时候。而别外部分性能要求比较稳定,不需要动态伸缩。那么,如果不同部分都混在一个微服务中,那么当扩展到更多容器的时候,成本就会比较高。可以考虑根据可伸缩性的不同,划分成两个微服务。
第二,不同的安全性要求。
比如,有些功能要接入互联网,有些部分在内网用,需要部署在防火墙的不同位置。这时候,需要划分成不同的微服务。
第三,技术异构性。
比如有些是Java开发,有些用node.js开发
微服务的划分,可以从功能性需求和非功能性需求两方面考虑。
从功能性方面考虑,微服务的划分应该有利于保证系统概念的一致性,更容易灵活扩展功能,而这些又要求开发团队顺畅的沟通协作。
根据限界上下文来划分模型,既考虑到了传统模块化思维中对业务概念的松耦合、高内聚的要求,又考虑到团队的认知负载和认知边界。
这样,一方面解决了团队协作和概念一致性问题。另一方面,每个限界上下文又是一个业务概念内聚的边界。在这个边界内部,就更容易建立可维护、易扩展的模型。
从另一个角度来说,合理的微服务划分,应该是对于多数需求变更,只需改动一个或少量的微服务。而划分不合理的话,对于多数业务需求,都要修改多个微服务。而限界上下文可以解决这个问题。
限界上下文为微服务的划分奠定了基础。然后,就可以再考虑性能、安全、可用性等非功能性需求,看是不是需要进一步划分。有时候,其实可以考虑把几个限界上下文合并到一个微服务里。极端情况下,所有上下文合并到一个服务,就又变成了单体。
这样做的话,至少保证微服务和限界上下文的划分不会产生“交错”的情况。也就是一个微服务包含了一个上下文的一部分,但是又包含了另一个上下文的另一部分,这很容易出现“分布式单体”了。