本文是《软件体系结构编年史》(关于软件体系结构的一系列文章)的一部分。 在这些文章中,我写了关于软件架构的知识,对软件架构的看法以及如何使用知识。 如果您阅读本系列的前几篇文章,那么本文的内容可能更有意义。在
该系列的
上一篇文章中 ,我发布了一个概念图,其中显示了代码类型之间的关系。
但是在我看来,并不是所有事情都能很好地反映出来,我只是不知道如何做得更好。 这是一个共同的核心。
此外,我在这篇简短的文章中概述了一些想法。
在本系列最后一篇文章的信息图中,在图的最中心,我们看到了共同的核心。 它似乎位于域层内部和圆锥形区域的上方,圆锥形区域是有限的上下文。

尽管位置合适,但我并不是说公共核心取决于代码的其余部分,也不是公共核心是域级别内的另一层。
什么是通用核心?
DDD之
父 Eric Evans定义的通用核心是开发团队决定在几个有限的上下文之间划分的代码:
两个团队同意一起使用的领域模型的子集。 当然,除了模型的这一子集之外,公共核心还包括与模型的这一部分相关联的代码或数据库体系结构的子集。 这种明显的一般性材料具有特殊的地位,在没有咨询其他团队的情况下不得更改。
- “公共内核” ,来自Ward Cunningham的DDD Wiki
因此,它可以是任何类型的代码:域级代码,应用程序级代码,库...等等。

但是,在概念图的上下文中,我将其表示为子集和特定类型的代码。 在我的概念图中,公共核心包含域和应用程序级别的代码,这些代码在有限的上下文中共享,因此可以在受限的上下文之间进行通信。
例如,这意味着事件在一个或多个受限上下文中触发,并在其他受限上下文中侦听。 与这些事件一起,我们需要共享这些事件使用的所有数据类型,例如:实体标识符,值对象,枚举等。事件不应该直接使用诸如实体之类的复杂对象,因为它们可能很困难序列化/从队列反序列化,因此通用代码不应广泛分发。
当然,如果我们有一个多语言的微服务系统,那么公共核心应该是JSON,XML,YAML等形式的描述性内容,以便所有微服务都能理解。
结果,该公共核心与其余代码库,组件完全隔离。 这很棒,因为这样,尽管组件与公共核心相连,但彼此却分开了。 可以清楚地识别通用代码,并且可以轻松地将其检索到单独的库中。
如果我们决定将有限的上下文之一提取到与整体分离的微服务中,这也非常方便。 我们肯定知道什么是通用的,并且可以将通用核心简单地提取到库中,该库将安装在整体和微服务中。
因此,总而言之,在我的概念图中,应用程序核心取决于一个通用内核,该内核包含来自域和应用程序级别的代码,这些代码在有限的上下文之间共享。
语言不够时...
因此,我们具有所有同心层的应用程序代码,而应用程序核心取决于所有这些代码下的公共核心。
我们也可以说所有这些代码都取决于所使用的编程语言,但这是一个显而易见的事实,我们倾向于完全忽略它。
但是,出现了一个问题:“如果语言结构还不够呢?!” 好吧,很明显,我们自己创建了这些语言构造,从而弥补了该语言的缺陷。 但是,我有一些重要的后续问题:“如何以及在何处证明该代码的存在? 如何清楚地指示何时以及如何使用它?”
我看到并自己做的是一个名为Utils或Commons的程序包,此代码位于其中。 但是最后,我们最终将所有代码都转储到了那里,我们不知道将其放在哪里! 最终,将出于不同目的和易于使用的各种代码(包装在直接使用的适配器中)直接转储在那里。 该软件包没有概念意义,没有连贯性,没有连贯性,没有明确性,有很多歧义。
我要放弃公用程序和公用程序包!
所有软件包都必须具有概念上的凝聚力! 应该清楚何时以及如何使用该软件包! 没有歧义!
例如,如果应用程序以某种特殊方式与命令行界面进行交互,则可以将其放置在“ Acme / App / Infrastructure / Cli / SpecialCli”中,而不是在名称空间中放置“ Acme / Util / SpecialCli”。 这表示该程序包与CLI关联,是Acme App应用程序基础结构的一部分。 与App基础架构的隶属关系还表明,此包所对应的应用程序内核中有一个端口。
另外,如果我们认为该程序包是语言本身所缺少的,则可以将其放在适当的名称空间中,例如'Acme / PhpExtension / SpecialCli'。 这表明该程序包应被视为语言本身的一部分,因此,它的代码应像任何语言构造一样直接在代码库中使用。 当然,如果另一家公司依赖此软件包,则不直接依赖此软件包可能是合理的,但是创建端口/适配器以便他们可以将其交换为其他产品更为安全。 但是,如果我们拥有该程序包,则可以将其视为语言的一部分,因为用另一种替代程序替换它的风险并不大。 妥协永远是事情。
可以视为语言一部分的另一个示例是PHP中的唯一UUID。 很有可能在语言之外想象它们,因为每次都有一个新版本,并且在代码支持下是一场噩梦,但这是一个非常笼统的概念,一个广泛且足够一致的概念,成为语言的一部分。
那么,为什么不创建一个UUID实现并像PHP本身一样使用它,我们如何使用DateTime对象呢? 在我们控制实现的同时,我没有发现任何缺陷。
教义查询语言(DQL)呢? (Doctrine是PHP中的Hibernate端口)我们是否可以将DQL视为SQL,Elasticsearch QL或Mongo QL?
结论
因此,在宏级别,我看到了四种基本的代码类型,并且我认为在代码库的组织中清楚地显示它们是很重要的,以免造成很多麻烦。

对我来说,不可否认的事实是,
架构始终存在,唯一的问题是我们是否控制它?因此,让我们在概念图(我的地图或其他地图)上
根据架构的全部或部分
清楚地组织代码 。 最主要的是组织代码,以便项目通过代码的结构和组织显式报告其体系结构。