当前位置: 首页 > 科技观察

构建前瞻性应用架构的最佳实践_0

时间:2023-03-21 19:27:36 科技观察

【.com速译】不知道大家有没有听过“软件架构师讨厌意大利面条”这句话?是指软件架构师在设计应用系统时,应在匹配业务理念的基础上,制定清晰的架构和流程,避免各种逻辑纠缠,模块和层级关系定义不清,各种功能相互交织,从而形成“难以运维的“意大利面条式架构”(spaghettiarchitecture)。下面,我将总结一些你应该遵循的良好的应用程序架构实践,以便你构建一个结构化和可扩展的应用程序架构。为什么应用程序架构如此重要?通常,一个应用程序架构包括构成应用程序的所有软件模块、组件、内部/外部系统以及它们之间的交互。显然,一个结构良好的应用程序架构可以确保您的应用程序能够根据业务和需求按预期扩展。用户需求。同时,一个好的架构不仅可以满足合理地隔离不同的功能概念,同时也形成了良好的内部/外部依赖。相反,如下图所示,如果在初期设计时针对各种需求和后期变更忽略了应用架构的合理构建和维护,则会导致不同组件之间的依赖关系错综复杂,甚至难以同步和管理.那么在实际项目中,面食式架构会给我们的系统带来哪些危害呢?糟糕的服务抽象:如果核心业务概念没有被适当地隔离和抽象,那么服务就会在不同的系统中。将各种业务规则分散在其中,从而降低代码的结构化程度和可重用性。难以管理的依赖性:当组件没有被正确隔离时,对系统的任何修改或替换都会产生滚雪球效应。换句话说,对某个部分的更改将影响与其关联的所有依赖项。死板而缓慢的遗留系统:如果系统本身复杂且不灵活,我们将需要更长的时间来适应新的业务变化。而且,如果使用的技术已经过时,随着时间的推移,核心数据和系统将对过时技术积累很深的依赖,更新技术就更难了。如何构建可扩展的应用架构?为了构建可靠且可扩展的应用程序架构,您需要基于严格的定义原则和完善的设计理念。显然,我们的目标不仅是为了支持业务快速增长和大规模扩展的需求,还要降低部署难度,避免高昂的代码维护成本。因此,我们可以从以下方面考虑应用程序架构的设计:所有项目参与者之间的共识。支持定义和规划。不断地做出改变。管理系统的复杂性。控制和降低风险。最小化技术债务(这是任何前瞻性应用程序架构的最终目标)。在这里,我们介绍一个架构画布的概念。作为支持和加速架构设计的多层框架,它促进了可重用服务和组件的抽象。通过保留相对独立的生命周期,架构画布可以最大限度地减少变更的影响,从而使应用程序架构更易于维护和扩展。架构画布的逻辑组成如上图所示。其中,从下到上分别是:基础层:在这一层,可以实现所有可重用的非功能性需求。例如:连接到外部系统,或使用可重用UI模式和主题库扩展现有框架服务。核心层:在这一层,可以实现各种核心业务服务。例如:围绕业务概念的各种服务、业务规则、业务实体、业务事务和业务组件。您需要使这些服务独立于目标系统,并从底层服务中抽象出任何可能的集成信息。可以看出,通过基础层和核心层,你已经隔离了所有可重用的服务或组件。最终用户层:在这一层中,您可以使用基础层和核心层的服务来支持用户界面和与用户交互的过程。值得注意的是,为了保证整个生命周期的独立性,本层模块不应该为其他模块提供服务。架构验证为了确保设计架构的合理性,避免“意大利面条”未完成的结果,我将提供一些您可以遵循的指导方针和建议。1.不要跨越三个层次向上引用。鉴于上面提到的结构分层,我们显然不应该让与业务无关的基础服务依赖于核心业务;我们也不应该让可重用服务依赖于各种最终用户界面。此外,向上引用往往会创建一个集群。如下图所示,在这个集群中,任意两个有直接或间接链接关系的模块都存在循环依赖。上图中,由于模块B可以间接影响模块A,模块A也可以间接影响模块B,这是一组相互依赖的模块。此外,如果您有另一个正在使用核心服务B的最终用户模块(EU2),那么它就会依赖于整个集群。可以看出,它们在运行时,不仅会占用大量不必要的资源,还会间接受到集群中某些模块变化的影响。2.避免绕过最终用户之间的引用为了确保适当的隔离并避免最终用户具有不同的生命周期,最终用户模块不应提供可重用的服务。下图展示了最终用户之间的旁路引用关系。也就是说,如果EU1最后调用了EU2,就意味着EU1不能独立于EU2,同时也不能独立于EU2之下层级结构中的集群。3.避免核心模块和基础模块之间的循环引用如果你能遵循前面提到的两条规则,那么你就不必担心最终用户模块之间可能出现的循环引用。相反,我们应该专注于避免核心模块和基础模块之间可能的循环引用。此类模块之间的循环引用主要是由于:一些业务概念没有被正确抽象出来,对代码管理造成不好的影响。如上图所示,循环引用多发生在以下两种情况:根据两个概念之间既定的关系,如果一个模块的逻辑位置发生变化,它的单向依赖就会被打破。例如,合同是由客户创建的,但客户的存在并不需要对合同的引用。4.补充建议核心模块不要有前端过滤条件:如果要实现一个服务,可能需要加一些过滤条件进行单元测试。但是作为开发者,一旦代码测试完成,应该及时去掉测试的过滤条件。如果出于某种原因您仍然需要使用测试过滤器来支持某些回归或BDD(行为驱动开发)测试,则需要将它们移动到最终用户的测试模块中。毕竟,在核心模块上保留测试过滤器是非常危险的。基于风险控制的考虑,它们只能存在于测试环境中,不能存在于生产环境中。所有实体都应该以只读方式发布:通过这种做法,您可以防止消费者简单地创建、更新或删除数据库中的记录。在核心服务层面,您应该抽象出需要与其他系统集成的组件,例如业务交易、验证、规范化和审计。在实际项目中,正确的做法是将所有业务事务的实现发布给用户,同时提供安全合适的抽象服务。避免在基层使用业务逻辑:有时很想在这一层实施各种业务规则。但事实上,我们应该确保它是业务不可知的,并且可以在任何应用程序域中重复使用。不要在基础层添加核心业务实体:要与业务无关,基础模块不应包含与业务相关的实体。但是,它们可以通过拥有非业务实体来支持应用程序的某些非功能需求。例如:如果您需要创建一个公共服务来审计所有交易,您可以创建一个审计实体。毕竟,软件应用程序的主要业务可能不是审计,而是销售产品、引入新客户或更改合同。使用架构画布的应用程序组合在讨论应用程序组合之前,让我声明一下:这里的“应用程序”与我们通常在业务上下文中所指的含义不同。在此上下文中,我们使用术语“应用程序”来指代开发环境中的最小部署单元。它可用于管理所有环境,也可用于管理业务应用程序、IT用户、安全集合和应用程序独立模块。为了识别一个应用程序属于上面的哪一层,你应该对目标应用程序进行深入的分析和模块化的解构。例如:如果应用程序要有一个最终用户模块,那么它必须处于最终用户级别。以下是一组可以确保前瞻性架构设计的参考规则:规则1:从模块的架构画布指南开始我们应该按照上面给出的建议对模块进行适当的分层。规则2:隔离公共服务模块正确就位后,我们就可以开始设计应用程序了。如前所述,如果“最终用户应用程序2”上有一个模块使用了“最终用户应用程序1”上的某个模块,那么我们应该隔离公共核心应用程序以避免依赖。如下图所示,如果两个应用想要共享和交互,需要通过公共的应用服务来实现,同时又要相互隔离。规则3:不要混淆所有者角色如果一个应用程序有多个所有者,不明确的职责会使变更的内容和管理复杂化。我们可以通过所有权的聚合和拆分,为每个应用明确设置一个所有者(如下图所示)。规则四:区分参与者角色和所有者角色与所有者角色类似,参与者也有自己不同的节奏。示例:有一个门户网站提供不同的保险服务。它的所有业务线都在同一个应用程序中,因此任何一项业务(例如汽车保险业务)的任何变化都不能独立于其他业务。因此,决定整个应用发布周期的实际上是最慢的业务线。如下图所示,我们需要让每个参与者通过在每个业务线创建单独的应用程序来估计他们的交付速度。在此基础上,根据项目的具体需求,我们既可以将不同参与者的任务相互隔离,也可以通过内容共享加强他们的协作。原标题:ApplicationArchitecture:BestPracticesforfuture-proofingYourApps,作者:FranciscoMenezes