良好架构的几个重要特征


在我看来,软件架构与建筑物的架构非常相似。你可以建造一个没有精心建筑设计的房子,但它永远不会是完美的。如果没有好的计划,你就无法建造一座大楼。在规划阶段,您需要注意几个想法:选择正确的墙壁,规划电力,水系统,所有房间,照明系统,空调和暖气等等。所以这是一项复杂,困难但必要的工作。
在软件架构上也是如此:你可以在没有适当架构的情况下实现小程序,但它们永远不会完美,你将无法建立和维护一个庞大的程序,因为它将成为一个有很多未知的大怪物,各种未知的功能和错误。在修复每个错误一段时间后,您可能掩盖聊其他五个错误。但是要规划正确的软件架构并不容易,需要考虑几个方面:主要功能,硬件要求(内存使用等),定义主要组件,代码的可重用性,稳定性,时序,内部通信,兼容性,可扩展性,可配置性等。等。
当您计划软件架构时,您实际上在做什么:根据要求,您将整个软件分成组件和子组件,规划其职责和接口,并规划组件之间的通信方式。
建筑的体系结构计划与软件体系结构之间还有一个很大的区别:由于建筑一旦构建就不经常变化,软件是一直发生变化:需求经常变化,新功能即将到来。因此,您需要在不进行大的更改的情况下扩展软件的方式来规划软件。为此,您需要找到一个真正的模块化架构。
我对优秀的软件架构有一个最喜欢的解释:一个漂亮的模块化软件架构就像宜家的家具(不,这里不是广告)。这些家具是从非常简单的模块(模块化组合和单一责任组件)构建的,它们在一些预定义的连接点(清晰的接口)上相互连接,并且以非常简单和非常清晰的方式记录(井)记录的用法)。此外,每个家具有几种变体,您可以选择玻璃门和木门,3或4个胸部版本,添加许多扩展,如额外的灯或内部镜子。所以它是开放的扩展,它是可配置的。所以我设计软件的目标始终是类似的结果。
在这里,我只是试图收集最好的软件架构的重点。

*模块化
您的软件需要通过定义良好的模块/组件构建。如果您的组件仍然很大,您可以将其拆分为所谓的子组件。如果是复杂的软件,您可以使用多级子组件。在使用此策略时,您将拥有大量可重用的组件。

*明确对组件的责任
您的每个组件都需要有明确的责任。你能用一句话描述它的责任是好的。如果你不得不使用“或”和“和”字样的情况下描述它,那么你的组件太大了,因为它应该被拆分。责任的好例子:“这个组件负责存储用户数据。” 但即使在此组件内部,也可以引入一些子组件,例如负责与数据库连接的组件。

*清晰的接口
定义的组件需要通过清晰的接口相互通信。每个接口都有一个名称,一个返回类型(它也可以是void),还可以选择一些参数。这是一种在私有和公共接口之间做出改变的良好做法。专用接口仅在同一组件内可用,公共接口也可用于其他组件。公共接口的数量应尽可能有限。每个公共接口都需要有详细记录。从长远来看,您应该避免更改或删除现有的接口。

*记录的行为
您的组件将被其他组件使用,因此可能由其他程序员使用。因此,应该以非常清晰的方式记录组件正在做什么以及它们的接口的预期行为是什么。您可以随时更改组件的内部行为(如何操作),但避免更改外部行为(正在执行的操作)。为此,您可以使用UML图表。

*容易明白​​​​​​​
我已经多次看到架构设计具有很长的派生链和组件之间复杂的连接。虽然他们能完美地运行工作,但没有人理解为什么以及如何使用它们。你应该避免这种解决方案。由于您的组件最有可能被其他开发人员使用,因此应该很容易理解其行为。

* 可配置
您的组件应该可以很好地配置,以便能够在多个环境中使用它。我使我的代码可配置的策略如下:代码中的所有魔术常量(路径,魔术字符串,幻数等)应该迁移到存储所有这些信息的配置类。然后应该能够通过配置文件从外部修改此信息。

*层架构
如果是复杂的软件,并非所有组件都应直接与所有其他组件通信。您可以引入一些其他限制,例如层。您应该将组件组织成层,只有一次可以直接相互通信,一个很好的例子是所谓的MVP(模型 - 视图 - 展示器)架构,它通常用于GUI应用程序。视图无法直接与模型通信,但展示层可以与它们进行通信。使用此解决方案,您的沟通方式将更加清晰,您可以更轻松地更改组件。

*清晰的调用顺序​​​​​​​
它应该以明确的方式定义组件如何相互通信。信息如何在它们之间流动。哪一个叫哪一个。为此,您可以使用UML序列图。

*精心设计的错误处理​​​​​​​
应根据常见概念处理整个软件的错误处理。有几种解决方案:使用特殊的返回值,异常或错误标志,但重要的是,您需要在所有组件中使用相同的解决方案。这使您更容易理解整个系统。