清洁架构:代码背后的概念
计算机系统的使用在社会中日益普及,且至关重要。从日常任务(例如通过电话订餐)到进行影像检查,都离不开软件。为了满足这种日益增长的需求,有必要在合理的成本范围内开发和维护软件,并在不损害现有软件的情况下促进其发展和优化。
软件工程是一门工程学科,涉及软件生产的各个方面,其主要活动包括软件的规范制定、开发、验证和演化(SOMMERVILLE,2010)。由于软件的抽象性,且不受物理定律的约束,这简化了软件工程。正如这种简化赋予开发人员以最佳方式构建应用程序的能力一样,缺乏约束也可能使软件变得复杂且难以维护。
正如物理建筑由砖块、混凝土或木材等较小的组件构成一样,软件建筑由软件组件构成,而软件组件又由其他软件组件构成,并且这两种类型的建筑背后都有一个架构,以确保其结构牢固安全。本文的一个关键软件工程概念是软件架构。程序或计算机系统的软件架构是系统的结构,涵盖软件组件、这些组件的外部可见属性以及它们之间的关系 (BASS; CLEMENTS; KAZMAN, 2012)。
软件开发过程中的变更不可避免,良好的架构旨在缩短执行这些变更的时间,从而减少财务成本和工作量。架构除了满足用户、开发者和所有者的即时需求外,还必须满足这些需求的长期期望 (MARTIN, 2017)。
正如建筑风格有古典主义、浪漫主义或巴洛克风格等不同风格一样,软件架构也存在客户端-服务器架构、洋葱架构和清洁架构等多种类型。然而,每种软件架构都有一个共同的目标,那就是将软件划分为多个层,至少有一层用于业务规则,还有一层用于用户界面和系统界面 (MARTIN, 2017)。
架构不仅要满足用户、开发者和所有者在特定时期的需求,还要能够长期满足这些期望。Robert MARTIN(2017)提出了“清洁架构”(Clean Architecture),旨在促进构建具有凝聚力、独立于技术、有利于代码复用的系统。接下来,我们将更详细地探讨这一架构。
清洁架构
清洁架构 (Clean Architecture) 的概念由 Robert C. Martin (MARTIN,2017) 在其著作《清洁架构:软件结构与设计工匠指南》(Clean Architecture: A Craftsman's Guide to Software Structure and Design) 中定义。在该架构中,系统可以分为两个主要元素:策略和细节。策略是业务规则和流程,而细节是执行策略所需的内容。(MARTIN,2017) 正是从这种划分开始,清洁架构开始与其他架构模式区分开来。架构师必须创建一种方法,使系统能够将策略识别为系统的主要元素,并将细节识别为与策略无关的内容。
在干净的架构中,没有必要在开发开始时选择数据库或框架,因为所有这些都是不会干扰策略的细节,因此可以随着时间的推移而改变。
层划分
清晰架构 (Clean Architecture) 的层级划分非常明确。该架构独立于框架,即包含业务规则的内部层不依赖于任何第三方库,这使得开发人员可以将框架作为工具使用,而无需调整系统以满足特定技术的规范。清晰架构的其他优势包括:可测试性、UI 独立性、数据库独立性以及对任何外部代理的独立性(业务规则不应该了解任何外部世界的接口)。
为了说明所有这些概念,我们创建了下图所示的图表。
图中的每一层代表软件的不同区域,最内层是策略,最外层是机制。
清洁架构 (Clean Architecture) 的主要规则是依赖规则 (Dependency Rule),该规则规定源代码的依赖关系只能向内,即指向最高层策略。也就是说,我们可以说最内层的元素不能包含任何关于最外层元素的信息。类、函数、变量、数据格式或任何在外层声明的实体都不能被内层代码提及。
最内层是实体层,它包含应用程序的业务目标,包含最通用、最高级别的规则。实体可以是一组数据结构和函数,也可以是具有方法的对象,只要该实体可以被多个应用程序使用即可。此层不得因最外层的更改而改变,也就是说,任何应用程序中的操作更改都不应影响此层。
用例层包含特定于应用程序的业务规则,用于对系统的所有用例进行分组和实现。用例组织实体之间的数据流,并指导实体应用关键业务规则以实现用例目标。此层也不应该受到最外层的影响,您的更改也不应该影响实体层。但是,如果用例的细节发生变化,该层中的某些代码将受到影响。
接口适配器层包含一组适配器,用于将数据转换为周围层最方便的格式。换句话说,它从数据库获取数据,并将其转换为实体层和用例最方便的格式。也可以进行反向转换,即从最内层到最外层的数据转换。演示器、视图和控制器都属于此层。
图的最外层通常由框架和数据库组成。该层包含与接口适配器层建立通信的代码。所有细节都位于这一层,Web 是一个细节,数据库也是一个细节。所有这些元素都位于最外层,以避免相互干扰的风险 (MARTIN, 2017)。
但如果各层如此独立,它们如何通信呢?依赖倒置原则解决了这个矛盾。Robert C. MARTIN(2017)解释说,你可以组织接口和继承关系,使源代码依赖关系在正确的位置与控制流相反。
如果用例需要与表示器通信,则此调用不能直接进行,因为这会违反依赖规则。因此,用例会从内层调用接口,并由外层的表示器进行实现。此技术可用于架构的所有层级之间。层间传输的数据可以是基本结构或简单的数据传输对象,这些数据只是函数调用的参数。为了避免违反依赖规则,不得传输数据库中的实体或记录。
结论
没有任何架构能够像“银弹”一样解决所有问题。而这并非“清洁架构”的初衷。
一旦应用程序基础构建完成,清晰架构 (Clean Architecture) 便可帮助您维护和演进应用程序,而无需投入太多成本(无论是物理成本还是时间成本)。这种优势源于其各层之间的独立性以及设计模式的持续运用。因此,对系统某一部分的更改通常不会干扰应用程序其余部分的运行。
另一方面,该系统需要一支更有经验的开发团队来开发。维护和构建软件需要掌握设计模式。与简单的 MVP 应用程序相比,它需要更长的时间才能看到初步成果,因此,与客户建立强有力的合作关系,让未来的收益清晰可见,这一点至关重要。
最后,结论是,对于那些倾向于发展并长期运行的应用程序来说,清洁架构 (Clean Architecture) 方法是一个不错的解决方案。然而,对于简单且不演进的系统来说,这种架构可能不值得投入精力,遵循更简单的架构模式更为明智。
参考
- SOMMERVILLE, Ian. 软件工程。第 9 版。英国哈洛:Addison-Wesley,2010 年。ISBN 978-0-13-703515-1。
- BASS, Len;CLEMENTS, Paul;KAZMAN, Rick。《软件架构实践》。第3版。[Sl]: Addison-Wesley Professional,2012年。ISBN 0321815734。
- MARTIN, Robert C. 整洁架构:软件结构与设计工匠指南。第 1 版。美国:Prentice Hall Press,2017 年。ISBN 0134494164。