为啥 Web 架构应该是松耦合的?

Posted

技术标签:

【中文标题】为啥 Web 架构应该是松耦合的?【英文标题】:Why should a web architecture be loosely coupled?为什么 Web 架构应该是松耦合的? 【发布时间】:2011-02-21 13:20:06 【问题描述】:

当我查看 ASP.NET MVC 项目时,我每次都会看到松散耦合架构。

为了什么我需要在 Web 架构中进行松散耦合(如果我不进行单元测试)?

这有什么优点缺点

解耦层/类的主要原因是什么?

例如,如果我不想更改我的 DAL 怎么办?我的意思是我什么时候应该改变我的整个 DAL?!所以我可以将我的 DAL 耦合到 UI。这有什么不好?

【问题讨论】:

【参考方案1】:

以没有人讨论过的角度回应; 时间解耦。可以通过以下几种方式完成:

基于队列的架构,网络将消息放入队列并监听结果 避免阻塞操作,主要是通过使用异步模式或将延续绑定到操作回调的异步单子,让线程在等待 IO 时工作。示例:http://blogs.msdn.com/b/dsyme/archive/2007/10/11/introducing-f-asynchronous-workflows.aspx 或 http://en.wikibooks.org/wiki/Haskell/Continuation_passing_style 基于推送的架构(例如 AMQP basic_consume) 分叉连接模式 ...

使用上述方法时(除了 async monad),您通常会显式处理消息而不是方法调用。这导致了与消息传递如何工作相关的思考(处理它们的幂等性、用于在传输中存储它们的队列、附加到其信封的安全数据、处理程序而不是请求程序中的重试逻辑......)。

通过转向时间上解耦的面向消息的架构,您可以更轻松地扩展应用程序 - 特别是如果您主要进行发布-订阅(另请参阅事件驱动架构) - 任何事情都可以监听事件并做出反应它们并且您不会将集成器的实现绑定到初始调用站点。

将工作推送到队列的网站通常响应速度更快,因为它们不会让工作线程等待 IO 发生。从长远来看,它们的维护成本通常也更低。

对于不同类型的编译类型耦合(和其他指标),请浏览http://www.ndepend.com/Metrics.aspx 并自己阅读一些相关内容。

【讨论】:

【参考方案2】:

我认为其他答案中解释了“正确”的方式。但我现在会根据我自己的经验来写。

在决定架构时,您必须考虑几件事情。

一个。 客户

您是否有足够的时间以“正确”的方式制作所有内容(出色的架构、测试等...)?有时客户希望快速看到结果。我们可以抱怨时间短,产品不会达到最高标准,但归根结底是我们的问题。在这种情况下,我们向客户解释他会得到什么,并编写我们都知道的意大利面条代码。

客户有什么要求(在可靠性、可扩展性、可扩展性、速度方面)?我认为这是不言自明的。有时客户会规定“正确”的方式。我们可以为客户提供“正确”的方式,但最终客户会做出决定(当然取决于时间和金钱)。

系统开发后谁来支持?我想支持一个很好的解耦代码。因此,当我编写代码时,我会尽力使其“正确”。有时我可能会将视图和控制器结合起来,或者结合一些服务并对此感到满意。知道我自己的代码很容易支持它。

b. 项目

项目的规模是多少?有些项目太小了,任何复杂的架构都没有必要。

该软件未来是否有机会快速发展(更多功能)?这是最大的挑战之一。但是,如果软件发展壮大,就意味着它是成功的。您可能会有更多的资源可以使用。重构代码并使其“正确”相对容易。

项目是否可能存在可扩展性问题?就用户和数据而言,有些项目永远不会增长。我见过一些项目试图通过使用 Oracle RAC 数据库设置来看起来很严肃,而一个简单的嵌入式数据库就可以正常工作!

您是启动该项目还是从其他开发人员手中接手该项目?这是由谁将支持该软件以及该软件将发展的问题的组合。您可能会从其他开发人员那里获得意大利面条代码。你会有时间和资源让它“正确”吗?

c。 开发团队

团队是否有足够的经验来正确解耦?当我经验不足时,我尝试编写“正确”的代码。而我失败了。关键是要真正了解您的开发团队、他们的技能和知识。不要小看这个问题。当与经验不足的开发人员一起工作时,我通常会在架构上做出一些牺牲。将做出的牺牲是我所拥有的最有根据的猜测。架构中有一些点是可以牺牲的,而有些点是不能牺牲的。通常你之前做出的一个或多个牺牲会回来咬你。

开发人员是否有编写自动测试的经验?仅有自动测试是不够的。它们应该是完整的(尽可能)并且做得正确。如果您的测试很弱,那么您最好根本没有它们。你不会想靠在满是洞的墙上。

结论

我知道我们都想成为专业人士。作为专业人士,我们必须考虑所有事情。我们不能把时间和精力浪费在以“正确”的方式做事上。有时我们必须考虑其他因素(现实)并做出选择。最重要的是忍受它。

【讨论】:

【参考方案3】:

这完全取决于制作应用程序的意图以及商业利益。如果企业热衷于扩展它并且涉及足够的燃料(读取语料库),这给架构师足够的思考以使应用程序获得长期利益。

所以优点是:-

1) 如果您使用第三方控件/代码:始终编写 “包装器/适配器层” 以便无论出于何种原因,如果它不可用,您可以获取其他内容并更改适配器层,而不会干扰您的应用程序存储库代码。

2) 将特定的复杂功能封装在可能需要也可能不需要数据库请求的“服务层” 中:这是有益的,因为请求和响应保持不变(它肯定会随着时间而改变好吧),您始终可以在不更改输出的情况下处理该特定代码的性能。有了单元案例,我们还可以衡量代码的性能。

3) 让特定角色编写特定代码:如果我们创建了很多角色,团队中的人更容易专注于他们的特定存储库,而不是迷失在一堆不相关的代码中。

4) 专注 QA:如果我们有分层架构,它总是有助于更好地专注于 QA。

5) 查找/解决错误:使用分层架构并假设您有良好的日志记录,它总是可以节省查找错误并解决问题的时间。

缺点是:-

1) 使用这种框架设置应用程序需要额外的时间。所以“上市”会被推迟。

2) 如果你太热衷于技术,它可能会以过度杀戮而告终。

3) 额外的事务延迟:当数据通过各个层时,每个事务中都会增加额外的延迟。

关于更改 DAL:-

当然会有一段时间,性能优先于功能,届时您将不得不开始考虑导致 DAL 发生变化的数据提供者。

如果您将 DAL 与 UI 耦合,则每次更改 DAL(如果有的话,当有的话)时,您总是需要在生产环境中重新发布整个二进制文件。哪个有自己的问题(我回避在这里解释,如果您需要,我可以随时包括在内)

这就是原因,最初总是最好花时间确定应用程序何时会发生“自毁”。我的意思是应用程序的生命周期是什么,如果回答得好,剩下的一切都会到位。

【讨论】:

【参考方案4】:

耦合和解耦合类的主要原因是为了可扩展性。一个人的改变不应该影响另一个人。

如果您构建的应用程序当前正在使用 mysql 数据库来存储数据。现在我们有了新的要求,将数据存储在 MSSQL 作为他的后端系统。如果您构建与 MYSQL 库更集成的系统,您还剩下什么解决方案。为 MSSQL 重写整个应用程序。现在怎么样 我们基于 MSSQL 构建一个新的 DAL 并将 Dal 插入系统而不对系统(UI)进行任何更改。

应用程序正在调用基于接口的例程,并且接口没有实现。

尝试阅读有关 Unity 或 MEF 的内容,这些主题将为您提供很好的洞察力

【讨论】:

如果您不需要可扩展性怎么办?为什么要更换整个 DAL? 如果您不需要可扩展性,那么您可以使用传统方法。但在今天的范式中,人们必须始终考虑可扩展性。软件在不断发展;要求做改变。架构也可以。一个很好的例子是我们正在通过 xxx Merchant 处理我们的付款,明天我们想切换到另一个 Merchant。处理付款的过程紧密集成到系统中,这需要大量的工作来促进。 在松散耦合的架构中,更改将很容易实现,并且不会影响主应用程序,所有将更改的只是 DLL,我们不必重新编译主 UI 代码。 @Rookian,可扩展性并不总是意味着替换整个 DAL 或任何层,还可以无缝地向现有应用程序添加功能,或者仅更改应用程序的一部分而不影响其他部分工作正常。此外,解耦使项目之间的代码具有很好的可重用性(因此可以更快地创建类似的项目)。也许如果您熟悉此类架构以及它们为什么以这种方式完成,您就会回答自己。花点时间阅读一下这个主题。 感谢 @lvaylo 为该主题增加更多价值。【参考方案5】:

在理论上,松耦合有很多优点,但在实践中,恕我直言,很难做到正确。以下是一些优点:

系统可以在生命周期方面独立发展。

系统可以用不同的语言编写,并最终在不同的操作系统上运行。

系统可以(并且应该)由不同的团队构建。您可以外包系统的开发。事实上,这几乎是扩展软件开发组织的唯一途径。

这里有一些缺点:

一开始的工作比较多,如果做得不好,可能永远看不到它的好处。

定义 API/合同非常困难,需要非常有经验的开发人员。一开始很容易,但从长远来看很难。

松散耦合的泛化实际上会导致到处都是松散类型。除了使用明确定义的有意义的对象外,您可能会观察到“对象”参数或返回类型的使用增加,泛型类型添加到每个类或接口。这样做的坏处是一般开发人员可能会到处添加狂野的转换操作,假设类型位于所谓的松散耦合系统的两侧。

一些松散耦合技术基于接口定义的泛化,旨在避免直接依赖。请记住,一旦定义和发布,界面就应该是一成不变的。现在,这并不是我所说的松散耦合。 .NET 类,利用 JIT 和方法重载等技术可以成为更好的松散耦合工具。因此,这些接口和工厂无处不在的问题在于,它将导致类型、程序集、测试用例等的倍增……以及更多的工作和复杂性。与其简化事物,不如构建一个系统,而是构建多个系统。 “N 层系统是 N 倍的工作”:-)

松耦合以某种方式绕过了有史以来最强大的工具之一:编译器(C# 或其他)。这实际上就是它的全部目的,但它肯定有一些缺点,因为编译器所做的所有基础工作(类型检查等)都需要在其他地方(测试)完成,这将产生成本。

许多开箱即用的工具可能不再起作用。您将无法使用诸如 Visual Studio“转到定义”或“查找所有引用”之类的东西。

【讨论】:

+1 for "...如果你做得不好,你可能永远看不到它的好处。" - 可能是很多人不这样做的一个重要原因不明白它的好处。【参考方案6】:

对于任何不小的项目,它都会为您节省大量时间,我将非常小的定义为少于几千行代码(取决于语言)。

原因是,一旦您完成了超小型项目,每次更改或更新都会变得更难,因为它耦合得越紧密。松散耦合使您能够继续前进,添加功能,修复错误等。

在某些时候,我认为任何程序都成为维护、更新和添加的噩梦。设计越松散耦合,该点被延迟得越远。如果它是紧密耦合的,可能在大约 10,000 行代码之后它变得无法维护,如果不从头开始重写,添加一些功能变得不可能。

松散耦合允许它增长到 1,000,000 - 10,000,000 行代码,同时仍然能够在合理的时间内进行更改和添加新功能。

这些数字并不是从字面上理解的,因为它们只是虚构的,而是为了说明它在哪里变得有用。

如果您从不需要更新程序并且它相当简单,那么可以肯定,紧密耦合是可以的。以这种方式开始甚至可以,但要知道什么时候应该将内容分开,但是您仍然需要编写松散耦合代码的经验才能知道它在什么时候变得有益。

Enterprise Fizzbuzz 是一个故意幽默的例子,说明过度工程可能会过火,而且并非每个项目都需要相同级别的解耦。

MVC 通常被认为是一个很好的起点,因为大多数项目都会变得足够大,以至于它会有所帮助。当项目变得更大时,这种程度的解耦是不够的,M 部分需要自己拆分成几个层,等等。没有一种万能的方法,但 MVC 对大多数项目来说是一种很好的解耦方式。

【讨论】:

【参考方案7】:

分工,相当于人类的关注点分离。您的 html 大师应该能够独立于您的 SQL 女神工作。

前端的巨大变化应该能够在不破坏后端的情况下进行,反之亦然。换句话说,您应该只雇用一个人而不是两个人。

【讨论】:

【参考方案8】:

优点:

可扩展性 - 允许您扩展数据库访问层 可交换性 - 例如电子邮件提供商代码 可维护性 - 只需在一处更改代码 易于设置单元测试 - 您可以像数据库一样模拟对象

缺点:

可能会多出几行代码 一些额外的接口类

【讨论】:

【参考方案9】:

它将为您提供可扩展性。例如,如果您后面有服务层,则可以将其分隔在多个服务器中。此外,您将拥有更少的依赖关系,并且修改会更容易。代码支持也会更容易。

这里可以看到有趣的小文章:SOA - Loosely Coupled...What?

简短地说:

松耦合系统提供了许多优势,包括在运行时支持后期或动态绑定到其他组件,并且可以调解组件结构、安全模型、协议和语义方面的差异,从而抽象波动性......

【讨论】:

但是如果我不需要在运行时更改组件怎么办?我无法理解您对可扩展性的看法。 例如,如果您使用 SOA 方法,您可以将您的服务分开以在不同的服务器上工作。即使您不需要在运行时更改组件,您也会从松散耦合架构中获得优势。例如,您使用 MS SQL 服务器作为数据库,并且使用 ADO.NET 作为数据提供者与它进行交互。一旦您需要迁移到 Oracle 甚至任何其他类型的数据存储(甚至可能是 xml 文件......),您将需要更新所有处理它的模块。但是如果你有服务层,你只需要修改服务层。 所以一般来说你可以有一个规则 - 改变任何你想要的,但不是合同。【参考方案10】:

首先,您应该编写单元测试;)

假设您最终需要更改底层数据库。如果您的数据访问代码与您的业务逻辑紧密耦合,那么这可能是一项巨大的工作。使用松散耦合的代码,您的业务逻辑不会受到影响。

如果您决定编写一些命令行实用程序来利用您的后端组件怎么办?使用松散耦合的代码更容易为您的系统提供多个入口点。

【讨论】:

【参考方案11】:

当您的应用程序需要更改或增长时,松散耦合架构将为您提供帮助。任何不平凡的应用程序最终需要改变或发展。

如果您使用松散耦合的架构进行设计,那么当需求发生变化时,应该只会影响应用程序的一小部分。对于过于紧密耦合的架构,许多部分都需要更改,并且很难准确确定哪些部分会受到影响。

在我看来,TDD 的主要好处之一是有助于促进松散耦合的架构。

【讨论】:

【参考方案12】:

因为后面的内容可能很有用,即使它不与基于浏览器的 HTTP Web UI 进行通信。因此,您希望能够将其与特定 UI 断开连接。

【讨论】:

【参考方案13】:

松散耦合允许您在应用程序的一个区域进行更改而不会影响其他区域。从理论上讲,它允许您在不重建业务或 UI 层的情况下进行更改数据访问层之类的操作。

它肯定会使您的应用程序更灵活、更善于更改并且更易于维护(因为您不必担心应用程序的一个区域的更改会破坏另一个区域)。

【讨论】:

我会添加“更易于维护”。如果从长远来看它们不容易维护,那么你就做错了。 同上。松耦合,紧内聚始终是要走的路。这是我从 SE 课程中获得的少数有用信息之一。 如果我不需要解耦层怎么办?什么时候改变整个 DAL?我不关心理论上可能发生的事情。 您需要取得平衡。您可以将所有内容分离出来并依赖注入所有内容,但是如果您不打算更改它们,为什么要更改它们?通过将功能组合在一起,您可以提高整个应用程序的重用性。您可能永远不想更改 DAL,但如果您需要更改其工作方式或添加新功能,您可以在 1 个位置进行操作。 仅更改一个位置的事实仅适用于您不进行大更改的情况,对吧?

以上是关于为啥 Web 架构应该是松耦合的?的主要内容,如果未能解决你的问题,请参考以下文章

什么是微服务架构啊?

微服务架构

微服务架构

微服务架构概述

微服务之间调用的最佳设计

Scala微服务架构 一