作者|钟静接续上一篇《??当我们谈论DDD时我们在谈论什么??》《关系》,《矛盾论》,毕达哥拉斯DDD的哲学意义(上)说“模型驱动设计”和两个重要的模式“实体”和“值对象”,既其中统称为“域对象”。在领域建模过程中,建立领域对象之间的“关联”也很重要。《DDD》Section5.1对此有专门的讨论。不过,与实体不同,艾未未并不把联想当成一种正式的“模式”。真可惜,因为关联至少与实体一样重要。你为什么这么说?这里说几句哲理的话。前面提到了毛老师的《实践论》,这里就说说老爷子的另一部杰作《实践论》。这篇论文的第一部分“两种宇宙观”提到了两个认识论体系:“形而上学”和“唯物辩证法”。前者是错误的,后者是正确的。形而上学认为事物的发展是静止的,受外因驱动,孤立的;唯物辩证法认为事物的发展是动态的,受内在因素的驱动,是相互联系的(还记得中学政治课背过吗?)。前两点我们后面再说,这里先说“连接”。《矛盾论》引用列宁的话:“要真正认识一件事,我们必须把它的各个方面、所有联系和‘中介’都把握清楚,研究清楚。我们永远不可能完全做到这一点,但这个要求的全面性可以防止我们犯错误并防止僵化。”这就强调只有充分理解事物之间的联系,才能充分理解事物。在DDD中,领域(事物)的概念是以实体、值对象、聚合、模块等形式来表达的。有的小伙伴认为在识别了领域中的主要聚合或实体之后,领域建模就完成了,而没有他们之间的关系。这样的模型实际上是不完整的。那么,如果我们认识到这一点,识别出关联,我们还应该进一步识别出关联的哪些信息呢?我们先来看古老的毕达哥拉斯学派。这个学派最早对古希腊的数学进行了系统的研究。他们发现了无理数,然后将揭开无理数秘密的队员扔进了大海。毕达哥拉斯认为世界的本源是“数”。宇宙的和谐来自数字的和谐。数的和谐体现在十组对立中:一与多、奇与偶、左与右、阴与阳、动与静、曲与直、明与暗、善与恶、方与长、限与无穷。在这十组关系中,最基本的是“一与多”。也就是说,只有把握了“一与多”,才能把握“数”,进而把握世界。从毕达哥拉斯的理论中,我们或许可以得到这样的启发(嗯~~我承认有点牵强):在领域模型中,对关联进行建模首先要考虑的是数量关系。即“一对一”、“一对多”、“多对多”等。存在性(强制性或可选性)做的细一点也可以考虑。很多建模者在建模时忽视了明确定量关系,从而限制了对领域知识的深入理解。数量关系的认识看似简单,但我们发现60%到70%的初学者在实践中都会犯错。只有经过一段时间的练习才能完全掌握。另外,如前所述,除了这里提到的实例之间的关联之外,还应该考虑类型之间的关联(即泛化)。掌握泛化关系是领域建模技术从初级阶段迈向中级阶段的门槛,也是高级建模技术的关键。要想熟练掌握这门技术,除了在项目中实践之外,还可以参考《分析模式》。《DDD》的后半部分,有一些使用泛化的high-level例子,但是前面讲模型驱动设计的章节,都没有提到泛化,忽略了建模的一个重要手段,可以看作是书中的一个漏洞。模型演化、辩证法和演化论如前所述,唯物辩证法认为事物的发展是动态的、受内因驱动的、相互联系的;并讨论了“连接”。本节首先讨论“动力学”。事物的发展变化是永恒的。因此,我们会继续强调,与其期望一次构建领域模型和架构,不如构建团队的架构演进能力。?的第8章到第13章对模型重构的方法进行了深入的探讨。该模型必须继续发展。大多数人听到这个说法都会点头。谁不知道“唯一不变的就是变化”?然而,在这一点上,说和做之间是有距离的。如果你真的想实现模型的进化,你不仅需要上面《DDD》中的建模技巧,还需要对重构、TDD(或者至少是自动化测试)和持续集成有扎实的把握。第三种。”此外,还需要掌握架构演进和数据库演进的几种模式,建立多维度的指标体系,使用工具量化架构保护等。但是,我们中的很多人,即使在接受了DDD,急于学习建模技巧(这本身并没有错),对模型演进根本不感兴趣。这样的DDD往往半途而废。这是因为如果模型(以及整个软件系统)不能进化,然后软件和模型会逐渐不一致,最后模型变成废纸,一切又回到原来的样子,这背后又可以回到团队乃至企业文化的问题上。衡量一个企业的文化,不是怎么说,而是怎么做。说完“动力”,再说“内驱”。《矛盾论》强调“唯物辩证法认为,外因是条件对于变化,内因是变化的基础,外因通过内因起作用。”内因在前,外因在后。然而形而上学只看到外因,也能改变事物,但只是量变。内因能引起质变。也就是说,事物本身不可避免地包含着内部矛盾,这种矛盾的发展变化会导致事物在一定的外部条件下发生质的变化。联系到模型的演化,我们从《DDD》中的相关例子可以看出,随着对领域知识理解的加深,模型的重构往往不是多加几个实体,少几个关联,而是更多几个层次的抽象,甚至打破和重组模型的核心部分。因此,对于这一点,我们要有充分的准备,知道这是复杂系统模型演化过程中的必然;还要未雨绸缪,掌握相关的建模和架构演进技术。不过不要害怕,掌握了相关技巧后,再复杂的改造也总能小步快跑,稳步前进。上面已经反复提到了架构演化。其实《DDD》和《演进式架构》是两本书。两者的侧重点不同,一个侧重于领域建模,一个侧重于系统架构的演进。然而,在实践中,我们经常将两者结合起来。下面说一下演化架构的原理,这超出了原书的范围。“演化架构”强调增量的、多维的、面向的架构变化过程。我们主要解释这三个关键词。《演进式架构》(BuildingEvolutionaryArchitectures)和“TheoryofEvolution”(进化论)中的“Evolution”和“evolution”其实是同一个英文词根。有人把《TheroyofEvolution》译成《TheoryofEvolution》,也有人译成《TheoryofEvolution》。《演进式架构》的译者耍了个花招,各取一个字,变成了“进化”,其实意思是一样的。因此,进化架构实际上调用了进化的隐喻。达尔文的《物种起源》将进化论概括为遗传、变异和适者生存。本书的第一部分首先讨论“人工选择”,例如狗和金鱼的驯化;后来它扩展到自然选择。比较进化架构和进化理论揭示了一些有趣的共同点。将软件系统比作活的有机体。不影响系统架构的增量修改等同于生物“继承”。对架构的实质性修改对应于生物“突变”。变异后的系统需要经过各种验证,看是否符合人们的需求。这实际上是一个“人工选择”的过程。满足需求的架构得以延续,不适应的架构将被淘汰或进一步变异。这就是进化架构中的“指导”,也是“适者生存”。达尔文指出,物种的进化总是渐进的,不会在短时间内发生剧烈变化。这是进化架构中的“增量”变化。生物体在适应环境时,必须适应多种因素:捕食能力、躲避天敌的能力、适应气候的能力、抵抗病虫害的能力和繁殖能力。各种因素必须适应才能生存。同样,系统必须适应各种因素:功能正确性、可扩展性、可维护性、性能、安全性等等。这就是演化架构中提到的“多维性”。上面的类比可以促使我们更深入地思考演化架构。至于具体的技术,大家可以参考原著。BoundedContext与人类认知能力的局限虽然哲学家可能是人类历史上最具争议的群体,但有一个观点是大多数哲学家都认同的:人类的认知能力是有限的。从孟子的“性命有限,知之无限”,到康德的“物自身不可知”,再到辩证唯物主义的“人只能知相对真理”,都说明了这一点。那么,这与限界上下文有什么关系呢?如果问同事什么是限界上下文,经常会听到这样的回答:“业务功能的边界”、“业务领域的边界”等等。这种说法虽然是正确的,但它是关于结果的,而不是原因;它是表象,而不是本质。因为聚合、模块等也可以说是一种“业务功能边界”。所以上面的回答没有抓住重点。《DDD》第14章“维护模型完整性”中介绍了限界上下文。眼尖的同学可能会问:为什么这一章的名字不叫“划分功能边界”呢?这里的“诚信”到底是什么意思?让我们继续阅读原文。本章开头段落中给出的示例是两个团队共享一个Charge对象。但两个团队提到的Charge背后的商业理念其实是不一样的。两队一开始都没有意识到这个问题。都去改了这个类,然后程序就崩溃了。然后作者说“模型最基本的要求是它应该是内部一致的,术语总是具有相同的含义,并且不包含矛盾的规则......”。因此,本章作者要解决的其实是系统的一致性问题。本章标题中的“诚信”是Integrity一词的翻译。Integrity固然是“正直”的意思,但也包括“统一”、“稳健”等含义。因此,将本章标题翻译为“MaintainingModelUnity”更为准确。翻译成“完整性”很容易产生误导。保持系统的一致性,长期以来一直被IT界的前辈所重视。比如布鲁克斯先生在70年代写的《人月神话》中就强调过。然而,以往的专家总是下意识地认为,对于一个复杂的系统,总有办法实现团队理解的全局一致性。《人月神话》中列举了几种方法。然而,《DDD》指出,“在理想的世界中,我们可以拥有一个覆盖整个企业领域的单一模型。这个模型将是统一的,没有任何冲突或重叠的术语定义”但是“大型系统领域模型的完全统一它是既不可行也不符合成本效益。”为什么“不可行”?答案是人类认知能力的局限性。既然大型软件是靠团队合作开发的,那么这里的认知能力也应该引申为群体的认知能力。也就是说,它包括个体的认知能力、群体的协作能力以及两者之间的互动。系统越复杂,识别起来就越困难。当系统的复杂度达到一定程度,超过了一个团队的认知能力,系统的一致性就得不到保证。解决办法是分而治之,把一个“理想”的大模型分成几个小模型,每个小模型不超过团队的认知能力。因此,每个小模型内部都可以保证严格的一致性,不需要和另一个模型保持一致。只需要就模型之间的接口达成一致。也就是说,当我们理解了人类认知能力的局限性后,不再追求全局一致性,而是退而求其次,取而代之的是局部一致性,这样就可以对系统的正确性进行整体管理,实现业务目标,这就足够了。概念的连贯性是通过语义的连贯性来表达的,因此作者引用了语言学术语“语境”。在日常用语中,人们经常随时切换上下文,这可能不会影响特定场景下的交流。但是在计算机软件中,一个元素要么属于上下文,要么不属于上下文,这个边界必须是明确的。为了强调这个边界的重要性,它被称为“有界上下文”。语境的具体划分方法仍需围绕领域概念的内聚和耦合关系展开。所以,划分的结果,当然代表了一个“领域边界”或者“功能边界”。如上所述,这是结果而不是原因。根据敏捷组织理论,一个开发团队的规模最好在5到9人之间(这是根据心理学研究得出的)。那么,boundedcontext的规模一般就是这样的开发团队能够掌握的规模。知道人类认知的局限性,使我们能够对世界保持一种谦虚而敬畏的态度。这也有助于我们理解限界上下文要解决的问题,划分的方法,以及它与团队的关系。最终,它使我们能够正确划分上下文并管理复杂系统的一致性。在本系列文章的最后一篇中,我们将继续探讨“核心领域”、“统一语言”,并对全文进行总结。
