软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

在这篇文章中,我将写:

  • 统一语言
  • 4 1 架构视图模型
  • 架构决策记录
  • C4模型
  • 依赖关系图
  • 应用地图

统一语言

我们可以使用 UML 创建几个图表,我们可以将它们分为两类:

  • 行为 UML 图活动图用例图交互概览图时序图状态机图通讯图时序图
  • 结构 UML 图类图对象图组件图复合结构图部署图封装图剖面图

我不会详细介绍每种图表类型,因为在这篇文章中涵盖的内容太多了,而且有大量资源记录了这些图表类型。要了解有关每种类型的更多信息,您可以查看上面指向某些Visual Paradigm 指南的每个链接,或查看此博客文章。

总而言之,UML 很酷,很有趣,我们可以很好地表达它,我们可以很容易地用它勾勒出一些想法并与同事讨论。

然而,要使用 UML 记录整个应用程序架构,我们需要使用多种类型的图表。此外,如果我们试图用一个单一的类图来表达整个应用程序,我们就是在自找麻烦。

UML 类图的良好用法示例是记录设计模式:

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

来源: https: //java-design-patterns.com/patterns/strategy

这很好,这实际上很棒!它可以表达类、接口、可用性和继承关系、数据和行为。它还简洁易读,而且因为它很小,所以创建速度也很快。

然而,下面的例子不是很有用……它太大了,所以会让人感到困惑和难以理解。此外,创建它会花费很多时间,以至于当我们完成时,它可能已经过时了,因为在此期间有人会对代码进行更改。

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

来源: https: //knowhow.visual-paradigm.com

因此,我们可以而且应该使用 UML,但对于应该使用它的情况:描述模式、应用程序的小部分的详细信息,或应用程序的高粒度视图(不使用类图)的低细节。

但问题仍然存在,我们如何记录完整的应用程序?!

4 1 架构视图模型

4 1 架构视图模型由 Philippe Kruchten 创建并于 1995 年发表在他题为“架构蓝图——软件架构的“4 1”视图模型”的论文中。

这种可视化软件应用程序架构的方式基于应用程序的 5 个视图/视角,告诉我们可以使用哪些图表来记录每个视图。

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

  1. 逻辑/结构视图
    关注系统提供的功能以及代码如何设计以提供此类功能;
  2. 实现/开发人员视图
    描绘代码、组件、模块和包的静态组织;
  3. 流程/行为视图
    关注系统的运行时行为,系统进程如何通信、并发、同步、性能等;
  4. 部署/物理视图
    说明应用程序的物理组织,它是关于“什么代码在什么硬件上运行”;
  5. 用例/场景视图
    整个体系结构在一些用例的帮助下进行了解释,这些用例只是交互序列。部分架构是从此类用例演变而来的。

重要的是要注意4 1 架构视图模型并不强制我们使用所有提到的图表,甚至不是所有视图。我们总是需要了解工具,并根据需要使用不多不少。

架构决策记录

架构决策记录 (ADR)实际上并不是记录应用程序架构的当前或未来状态,而是记录导致它的原因。它们特别重要,因为它们打算告诉其他人,以及我们未来的自己,为什么这个架构是现在的样子

ADR 是有关已做出的架构决策的日志条目,这些决策导致架构现在或将来的状态。它们包含描述体系结构的图表背后的原因。

首先,我们需要了解一些人工制品:

  • 架构上重要的需求(ASR):对软件系统架构有可衡量影响的需求;
  • 架构决策(AD):解决重要需求的软件设计选择;
  • Architecture Decision Record ( ADR ):一份记录重要架构决策及其上下文和结果的文档;
  • 架构决策日志(ADL:为特定项目(或组织)创建和维护的所有 ADR 的集合;
  • 架构知识管理(AKM):所有先前概念的更高领域。

我看过一些用于创建 ADR 的模板,我在其中看到了一些不错的东西,所以我创建了自己的模板。您可以,也许也应该创建您自己的,对您和您的团队有意义的。

对我来说,模板最重要的是它很简单,而且里面有一些文档可以帮助填写,甚至可以帮助做出务实和公正的决定。

使用 ADR 的最佳方式不仅仅是在讨论和做出决定后编写的文件。最好的办法是将其用作讨论的起点,作为 RFC征求意见稿),这是我们提交给团队/部门其他成员的想法/提案,以征求他们的意见/意见/批准。真正的目的是用它来开始讨论、集思广益、做出可能的最佳决策,并将提案文件本身用作决策日志条目 (ADR)。事实上,ADR 是事先写好的,并不意味着它是不可变的,它必须随着讨论的展开而更新/改进。我发现特别重要的是,将所有正在考虑的选项都写下来,并附上它们的优缺点,以引发讨论和做出明确的决定。

C4模型

C4 模型是由 Simon Brown 引入的,它是迄今为止我遇到的关于软件架构文档的最佳想法。我会用自己的话快速解释主要思想,尽管使用他自己的示例图。

这个想法是使用 4 种不同的粒度(或缩放)级别来记录软件架构:

  • 第 1 级:系统上下文图
  • 第 2 级:容器图
  • 第 3 级:组件图
  • 第 4 级:代码图

级别 1:系统上下文图

这是最高粒度的图表。它没有什么细节,但其主要目标是描述应用程序所在的环境。因此,它将由一个用于整个应用程序的盒子组成,并且将被其他盒子包围,这些盒子指的是应用程序与之交互的外部系统和用户

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

第二层:容器图

现在,我们放大我们的应用程序,上图中的蓝色方块映射到下图中的虚线方块。

在此粒度级别,我们将看到应用程序的容器,其中容器是应用程序的任何独立技术部分,例如移动应用程序、API 或数据库。它还记录了使用的主要技术以及容器如何通信

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

第 3 级:组件图

组件图向我们展示了一个容器内的组件。在这种情况下,每个组件都是应用程序的一个模块,不仅限于领域模块(即计费、用户……),还包括纯功能模块(即电子邮件、短信……)。所以这张图向我们展示了容器的主要齿轮以及这些齿轮之间的关系

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

第 4 级:代码

最细粒度的图表,旨在描述组件内部的代码结构。对于这个级别,我们使用带有类级别工件的 UML 图。

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

要了解更多信息,您可以在此处和此处阅读 Simon Brown 自己对此的解释,甚至可以在此处观看他的讨论。

还缺什么

我认为 C4 模型是记录应用程序架构的好方法,在一定程度上理解应用程序的架构很棒,但我仍然觉得它不够,虽然我花了一些时间来指出缺少的东西.

我在这些图中看到了三个限制:

  1. 除了一些例外,比如 Simon Brown 的structurizr,它们需要手动制作,而不是自动制作,也不是直接从代码中提取,这意味着它们可能不会反映实际代码,而是我们当前对它的理解;
  2. 它们并不能完全帮助我们了解我们的应用程序代码库中的错误,关于混杂的代码关系和糟糕的结构,这会影响模块化和封装,这对任何工程产品都是必不可少的;
  3. 它们无助于我们从整体上理解我们的代码库、应用程序齿轮可以做什么以及它们如何相互交互。

我发现了两类图表可以帮助我们解决这个问题。

依赖关系图

依赖关系图有助于告诉我们代码库中不同类型代码中存在的依赖关系。

这里至关重要的是,这些图表是直接从代码自动生成的,否则图表只会反映我们认为代码的样子,如果那是准确的,我们就不会真的需要这种类型的文档。

此外,也许比图表本身更重要的是,在我们预定义的依赖性规则发生中断的情况下,使用这些依赖性分析来停止构建的能力。因此,用于生成这些图表的工具也应该可用作测试工具并包含在我们的 CI 管道中,就像单元测试一样,防止不需要的依赖关系到达生产环境,从而维护和强制模块化,这反过来有助于实现高可变性率,因此功能开发速度很快。

层依赖关系图

该图的目的是可视化并确保每一层中的代码只能依赖于它内部或下面的层。

因此,在下图中我们可以看到,例如,基础设施层作为最上面的外层之一,可以依赖于任何其他层。另一方面,Domain 层作为最上层的中心层,只能依赖于下面的层,即 SharedKernel-Domain(它也是 Domain 的一部分)和 PhpExtension(其代码被用作语言本身的一部分)。

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

deptrachttps://github.com/hgraca/explicit-architecture-php生成的层依赖图

类依赖关系图

Layer dependency diagram 分析层与层之间的依赖关系,但在一个层内仍然存在不能发生的依赖关系。

类依赖关系图有助于分析我们代码库中不同类型类之间的依赖关系,特别是当它们位于同一层时。

例如,如果我们希望我们的事件是可序列化的,以便我们可以将它们放入队列中,我们可能不希望它们包含实体,因为反序列化它并使用 ORM 持久化它会有问题。事件依赖于服务也是没有意义的。使用这种类型的图表,或者更准确地说,使用测试依赖关系的工具,我们可以轻松检测到此类情况并防止它们进入生产环境。

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

组件依赖图

组件是一个领域模块,一个包含应用层和领域层的模块。例如,组件可以是包含所有用例和领域逻辑的“计费”。

组件可以映射到 DDD 有界上下文和/或微服务,这意味着它们必须在物理上和时间上与其他组件完全解耦。如果我们有一个具有完全解耦组件的单体应用程序,那么将它转换为微服务架构将相当容易(代码方面)。

此外,将相同的解耦要求应用于其他非领域明智的模块,我们可以保证我们可以轻松替换任何模块。

组件依赖关系图旨在确保应用程序组件和模块是解耦的。

请注意,在下图中,同一层中的模块(具有相同颜色的节点)是如何相互不知晓的,至少是直接的。

特别重要的是这两个组件(用户和博客,中蓝色)是分离的。如果这个应用程序有一个微服务架构,这两个组件就是微服务。

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

deptrac为https://github.com/hgraca/explicit-architecture-php生成的组件依赖图

应用地图

大约一年前,我意识到我在这些文档选项中还遗漏了一些其他东西:所有这些图表,它们告诉我们应用程序的构建块是什么,哪些块相互交互以及它们是如何相关的,但它们并没有不要告诉我们他们做什么,也不要告诉我们他们如何以及何时彼此互动。为此,我们需要从用户的角度非常了解应用程序,或者从开发人员的角度了解代码库。前面的图并没有告诉我们应用程序中有哪些用例,也没有告诉我们哪些用例触发了哪些事件,也没有告诉我们这些事件的后果是什么。如果我们向产品负责人展示这些图表,他会发现它们对他的角色几乎毫无用处。

所以我想出了一个新的文档图的想法,我称之为Application Map,它可以取代 C4 模型组件图。

应用地图旨在成为真正的应用地图,定义其“城市”(组件)、“地方道路”(用例)、“高速公路”(事件)等。

模块和组件之间的区别在于,模块是应用程序的任何模块化部分,而组件是应用程序的领域模块。因此,虽然 ORM 是应用程序的一个模块,但它不是一个组件,因为它只处理技术问题。另一方面,“计费”模块是一个组件,因为它处理领域问题。

Application Map 首先定义应用程序的组件,领域模块,如“Billing”、“User”、“Company”、“Orders”、“Products”等。对于一个简单的博客应用程序,我们可以有两个组件,“用户”和“博客”组件:

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

在每个组件中,我们定义了可以向它们发出的命令。“User”组件可以创建和删除用户,而“Blog”组件可以创建和删除帖子,以及对帖子创建评论。

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

接下来,在每个组件中,我们列出所有相关服务。这些服务是相关的,因为,例如,它们触发事件或直接由另一个组件使用。这很重要,因为应用程序映射应该使组件之间的连接以及它们的含义和任何后续副作用可见,为此我们需要公开连接到其他组件的服务及其名称(应该表达它们的作用).

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

在服务之后,我们列出了每个组件中的所有事件侦听器,即使它们实际上没有被使用,这很方便,因为我们可以检测到它并修复任何需要修复的内容或删除未使用的代码。

我所说的侦听器是指一个类,其公共方法全部仅由一种类型的事件独立触发,它们专注于事件。

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

我们还将列出每个组件中的事件订阅者,原因与列出侦听器的原因完全相同。

事件订阅者类似于事件监听器,只是它的公共方法由不同的事件触发,它们专注于一个复合任务,订阅者的一个例子可以是一个监听不同框架事件的类,以控制何时开始,提交或回滚请求事务。

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

此时,我们在地图中拥有所有组件及其功能。这是非常有价值的,因为它告诉我们,或者任何非技术人员,每个组件可以做什么。

然而,它仍然没有告诉我们所有这些功能是如何相互关联的,例如“用户创建博客文章会发生什么?”。

为了实现这一点,第一步是列出触发特定功能时组件中发生的情况。

在下图中,我们可以看到删除帖子(“DeletePost”)会触发 PostService 中的 deletePost() 方法,该方法也是由侦听通知用户已删除的事件的侦听器触发的。这告诉我们,我们的应用程序删除帖子是由于用户的直接命令或帖子作者已被删除。

在 User 组件中,我们可以看到创建帖子时,其作者会自动订阅该帖子主题(标签)。

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

现在我们有了组件内流的信息,但是我们还缺少跨组件流的信息,所以让我们添加被触发和监听的事件:

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

例如,我们可以看到:

  • 删除用户将触发一个事件,该事件将删除用户的帖子;
  • 创建帖子将触发事件,该事件将导致作者订阅帖子主题并提高作者评级;
  • 从任何用例中删除帖子都会触发一个事件,该事件将导致降低该作者的评级。

有了我们地图中的所有这些信息,我们就可以对其进行导航。任何技术人员或非技术人员都可以清楚地看到当应用程序的任何用例被触发时会发生什么。这可以帮助我们澄清我们的代码,以及我们对应用程序行为的想法。

但是,在大型应用程序中使用时,此图仍然会存在与前面提到的图相同的问题:

  1. 这是一个人工制品,需要花费大量的精力和时间才能完成,而且还需要保持更新;
  2. 我们最终仍然会得到一个包含很多线条的大图,这不是最易读的。

要解决第一个问题,我们需要能够按需从代码生成图表。这将使创建这样的图表变得毫不费力,消除了维护它的需要,并且几乎可以立即创建它。

为了解决第二个问题,我们需要能够有选择地只生成图表的一部分。例如,通过提供我们想要分析的用例的名称,这将导致只生成图表中与给定用例以某种方式相关的部分。

前段时间我开始创建它,我到了只缺少组件内部流程的地步,但它列出了所有命令、服务、侦听器、订阅者和事件。由于缺少信息,它仍然处于 alpha 阶段,还因为它在需要分析的代码库方面不灵活,但是,从我目前工作的公司的代码库来看,它可以生成如下内容:

软件架构(20)-4+1架构模型-u0026C4模型-u0026统一语言(简述软件架构模型)

如果您对该项目感到好奇,可以在此处查看,但请注意,它仍处于 alpha 阶段,它只是一个概念证明,我已经几个月没有研究它了。如果您觉得这是一个有价值的项目并且您有空闲时间来贡献,请告诉我,我会尽力让您跟上进度并创建您可以接手的任务以将其提升到一个新的水平。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

(0)
上一篇 2023年4月23日 上午10:14
下一篇 2023年4月23日 上午10:30

相关推荐