软件体系结构:你需要了解的5种模式

分层模式

分层模式可能是最著名的软件体系结构模式之一。许多开发人员使用它,却不知道它的名称。这样做的目的是将你的代码划分为“层”,其中每个层都有一定的责任,并向更高层提供服务。

没有预先定义的层数,但你最常看到的是这些层:

· 表示层或UI层

· 应用层

· 业务或域层

· 持久化或数据访问层

· 数据库层

其思想是用户通过执行一些操作(例如,单击一个按钮)在表示层中启动一段代码。然后,表示层调用底层,即应用层。然后我们进入业务层,最后,持久化层将所有内容存储在数据库中。因此,较高层依赖并调用较低层。

你将看到这方面的变化,这取决于应用程序的复杂性。一些应用程序可能忽略了应用程序层,而另一些应用程序则添加了缓存层。甚至可以将两个层合并为一个。例如,ActiveRecord模式将业务层和持久层结合起来。

层责任

如前所述,每一层都有自己的责任。表示层包含应用程序的图形设计以及处理用户交互的任何代码。你不应该添加不特定于此层中的用户界面的逻辑。业务层是你要解决的业务问题的模型和逻辑的放置地方。应用层位于表示层和业务层之间。一方面,它提供了一个抽象化,这样表示层就不需要知道业务层了。理论上,你可以更改表示层的技术堆栈,而无需更改应用程序中的任何其他内容(例如,从WinForms更改为WPF)。另一方面,应用层提供了一个放置某些不适合于业务或表示层的协调逻辑的地方。

最后,持久化层包含访问数据库层的代码。数据库层是底层数据库技术(例如SQLServer、MongoDB)。持久化层是操作数据库的一组代码:SQL语句、连接细节等等。

优势

· 大多数开发人员都熟悉这种模式。

· 它提供了一种简单的方法来编写组织良好的和可测试应用

缺点

· 它倾向于导致单块应用程序,这些应用程序之后很难分离。

· 开发人员常常发现自己编写了大量代码来通过不同的层,而没有在这些层中增加任何价值。如果你所做的只是编写一个简单的CRUD应用程序,那么分层模式可能对你来说太过了。

理想应用

· 标准业务应用程序,不仅仅是CRUD操作。

微内核

当应用程序有一组核心职责和一组可互换的部件时,微内核模式或插件模式非常有用。微内核将提供应用程序的入口点和一般流程,而不用知道不同的插件正在做什么。

例如,任务调度程序。微内核可以包含调度和触发任务的所有逻辑,而插件包含特定的任务。只要插件遵循预定义的API,微内核就可以触发它们,而不需要知道实现细节。

另一个例子是工作流。工作流的实现包含了一些概念,比如不同步骤的顺序、评估步骤的结果、决定下一步是什么等等。这些步骤的具体实现对工作流的核心代码不太重要。

优势

· 这种模式提供了极大的灵活性和可扩展性。

· 有些实现允许在应用程序运行时添加插件。

· 微内核和插件可以由不同的团队开发。

缺点

· 很难决定哪些属于微内核,哪些不属于微内核。

· 预定义的API可能不适合未来的插件。

理想应用

· 从不同来源获取数据、转换数据并将其写入不同目的地的应用程序。

· 工作流应用。

· 任务和作业调度应用程序。

CQRS是缩写词命令和查询责任隔离。这种模式的核心概念是,应用程序具有必须完全分离的读操作和写操作。这也意味着用于写操作(命令)的模型将不同于读模型(查询)。此外,数据将存储在不同的地点。在关系数据库中,这意味着将有命令模型的表和Read模型的表。有些实现甚至将不同的模型存储在完全不同的数据库中,例如命令模型的SQLServer和读取模型的MongoDB。

这种模式通常与事件源相结合,我们将在下面讨论。

它到底是怎么工作的?当用户执行操作时,应用程序向命令服务发送命令。命令服务从命令数据库中检索所需的任何数据,进行必要的操作并将其存储在数据库中。然后,它通知读取服务,以便可以更新读取模型。下面可以看到这种流动。

当应用程序需要向用户显示数据时,它可以通过调用Read服务来检索读取模型,如下所示。

优势

· 命令模型可以关注业务逻辑和验证,而读取模型可以根据特定场景定制。

· 你可以避免复杂的查询(例如,SQL中的联接),这使得读取更具有表现性。

缺点

· 保持命令和读取模型保持同步可能变得非常复杂。

理想应用

· 需要大量读取的应用程序

· 复杂域应用

事件源

正如我前面提到的,CQRS经常与事件来源密切相关。这是一种模式,你不用将模型的当前状态存储在数据库中,而是存储发生在模型上的事件。因此,当客户的名称发生更改时,你不会将该值存储在“name”列中。你将使用新值存储“NameChanged”事件(可能也存储旧值)。

当需要检索模型时,检索其存储的所有事件,并将它们重新应用于新对象。下面的例子应该更加清楚。

你可以看到,我们在添加发票201805时出错了。我们没有更改行,而是增加了两行:第一行是取消错误的行,然后是新的和正确的行。这就是事件源的工作原理。你永远不会删除事件,因为它们不可否认地发生在过去。为了纠正情况,我们添加了新的事件。

另外,请注意我们是如何拥有一个具有总价值的单元格的。这只是上面单元格中所有值的总和。在Excel中,它会自动更新,因此你可以说它与其他单元格同步。它是读取模型,为用户提供了一个简单的视图。

事件源通常与CQRS相结合,快速读取模型可以显着地提高应用程序的响应时间。

优势

· 这种软件体系结构模式可以提供一个即时的审计日志。每个事件都表示在某个时间点对数据的操作。

缺点

· 它需要一些规则,因为你不能仅仅用数据库中的简单编辑来修复错误的数据。

· 更改事件的结构不是一项简单的任务。例如,如果添加属性,数据库仍然包含没有该数据的事件。你的代码需要优雅地处理这些丢失的数据。

理想应用

· 需要将事件发布到外部系统

· 将与CQRS一起建造

· 具有复杂域

· 需要数据更改的审计日志

微型服务

当你将应用程序编写为一组微服务时,你实际上是在编写多个将协同工作的应用程序。每个微服务都有自己独特的职责,团队可以独立于其他微服务开发它们。他们之间唯一的依赖就是沟通。当微服务相互通信时,你必须确保它们之间发送的消息保持向后兼容。

图表解释:

在上面的图表中,应用程序调用一个中央API,该API将调用转发到正确的微服务。在本例中,为用户配置文件、库存、订单和支付提供了单独的服务。你可以想象这是一个应用程序,用户可以在其中订购一些东西。单独的微服务也可以相互调用。例如,付款服务可能会在付款成功时通知订单服务。然后,订单服务可以调用库存服务来调整库存。

对于微型服务的规模还没有明确的规定。在前面的示例中,用户配置文件服务可能负责用户的用户名和密码等数据,但也负责家庭地址、化身图像、收藏夹等。还可以选择将所有这些责任分成更小的微型服务。

优势

· 你可以分别编写、维护和部署每个微服务。

· 微服务体系结构应该更容易扩展,因为你只能扩展需要缩放的微服务。没有必要扩展应用程序中使用频率较低的部分。

· 重写应用程序的部分更容易,因为它们更小,也更少耦合到其他部分。

缺点

· 与你可能预期的相反,最初编写结构良好的Monolith并将其分解为微服务实际上更容易一些。对于微服务,有了很多额外的关注点:交流、协调、向后兼容性、日志记录等等。没有必要的技能来编写结构良好的Monolith的团队可能会很难编写一套好的微服务。

· 用户的单个操作可以通过多个微服务。有更多的失败点,当某些事情确实出错时,可能需要更多的时间来找出问题所在。

理想应用

· 某些部分将大量使用并需要缩放的应用程序

· 为其他几个应用程序提供功能的服务

· 如果组合成一个单点,应用程序就会变得非常复杂

· 清空的申请有界上下文可以定义

总结

我已经解释了几种软件架构模式,以及它们的优缺点。将这些模式中的几种组合在一起也并不少见。它们并不总是相互排斥的。例如,你可以有几个微服务,其中一些使用分层模式,而另一些使用CQRS和事件源。

重要的是,没有一种解决方案在任何地方都有效。当我们问应用程序使用哪种模式时,我只能说“这取决于具体情况。”你应该权衡一下解决方案的利弊,再做出一个明智的决定。

原文标题《Software Architecture: The 5 Patterns You Need to Know》

作者:Peter Morlion

译者:lemon

不代表云加社区观点,更多详情请查看原文链接

原文链接:https://dzone.com/articles/software-architecture-the-5-patterns-you-need-to-k

原文作者:Peter Morlion

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SeanCheney的专栏

《Python分布式计算》 第7章 测试和调试分布式应用 (Distributed Computing with Python)概述常见错误——时钟和时间常见错误——软件环境常见问题——许可和环境常见

无论大小的分布式应用,测试和调试的难度都非常大。因为是分布在网络中的,各台机器可能十分不同,地理位置也可能不同。 进一步的,使用的电脑可能有不同的用户账户、不同...

27050
来自专栏腾讯Bugly的专栏

《手Q Android线程死锁监控与自动化分析实践》

手Q每个版本上线以后研发同学都会收到各种问题反馈。在跟进手Q内部用户反馈的问题时,发现多例问题,其表象和原因如下:

1.1K80
来自专栏Java进阶干货

用Redis轻松实现秒杀系统

用上这三招,不论秒杀时负载多大,都能轻松应对。更好的是,Redis能够满足上述三点。因此,用Redis就能轻松实现秒杀系统。

59110
来自专栏智能计算时代

物联网IEC 61499 101标准介绍

PLC 基本上,PLC是一种业界用于控制不同系统的输入和输出的小型计算机。通常,输入是按钮和传感器,输出是电机。如果您有Informatic背景,您可以将PLC...

35550
来自专栏运维一切

关于docker的存储驱动 原

#背景 一直以来我的业务都是跑在aufs+ext4的存储驱动结构上,看上去没有什么问题,直到业务报告: 在高并发场景下,aufs因为锁争抢的原因,导致cpu高负...

16520
来自专栏极客猴

爬虫与反爬虫的博弈

近来这两三个月,我陆续将自己学到的爬虫技术分享出来。以标准网络库 urllib 的用法起笔,接着介绍各种内容提供工具,再到后续的 scrapy 爬虫框架系列。我...

23220
来自专栏Java架构师学习

通过 Java 线程堆栈进行性能瓶颈分析

30860
来自专栏三丰SanFeng

负载均衡 - 综述

1 什么是负载均衡 网络的各个核心部件随着业务量的提高、访问量和数据流量的快速增长,其处理能力和计算强度也相应增大,使得单一设备根本无法承担。在此情况下,如果扔...

31080
来自专栏CDN及云技术分享

微型分布式架构设计范例

设计该系统初衷是基于描绘业务(或机器集群)存储模型,分析代理缓存服务器磁盘存储与回源率的关系。

1K280
来自专栏JAVA高级架构

如何设计一个麻雀般的微型分布式架构?

设计该系统初衷是基于描绘业务(或机器集群)存储模型,分析代理缓存服务器磁盘存储与回源率的关系。系统意义是在腾讯云成本优化过程中,量化指导机房设备扩容。前半部分是...

12630

扫码关注云+社区

领取腾讯云代金券