Robert Martin 就是我们常说的Bob大叔,是码界的骨灰级人物了,在4年前提出了所谓的简洁架构,值得回顾反思一下,看看是否可以借鉴到微服务中呢?


大叔在文中介绍了一下几种知名的架构思想:


  • Alistair Cockburn 的Hexagonal Architecture

  • Jeffrey Palermo 的 Onion Architecture

  • Screaming Architecture 在Bob 大叔的博客上

  • DCI 是 James Coplien, 和 Trygve Reenskaug提出的架构模型

  • BCE 是 Ivar Jacobson 在其著作 Object Oriented Software Engineering: A Use-Case Driven Approach 提出的


尽管这些架构在细节上有各种各样的不同,大叔认为是相似的,都有着相同的目标就是——关注点分离,通过关注点分离把软件分成若干层,系统都是这样的:


  1. 独立的框架。架构不依赖于功能丰富的软件库,把框架作为工具而不是系统的约束。

  2. 可测性. 商务逻辑可以不依赖TUI, 数据库, Web , 或其他外部元素就可以测试。

  3. 独立的UI. 无需改变系统的其他部分就可以轻松地改变,例如 一个 A Web UI 换成控制台UI,而无需改变业务逻辑。

  4. 独立的数据库.业务逻辑不与数据库绑定,可以在各种数据库间切换例如 Oracle 和SQL ,Mongo与 BigTable、 CouchDB等。

  5. 外部代理的独立性. 事实上,业务逻辑需要简化到无需知道外面的世界。


因此,大叔提出的简洁架构试图将这些架构集成为一种简单的表达形式。



这一架构工作的最高原则就是依赖原则。这一原则说明源代码依赖指向内部的,内圆不知道外圆的一切, 特别地,外圆中声明的东西不需要被内圆中的代码涉及,包括函数,类,变量以及其他的软件实体。同心圆代表了软件的不同领域。一般地,越深入负责,软件的层次越多。外圆代表机制,内圆代表策略。同样的,外圆中的数据格式也不应被内圆使用,尤其是那些被外圆中的框架所生成的数据格式,并不希望外圆影响到内圆。


实体 (Entities)


实体封装了企业级的业务逻辑。一个实体可以是一个带有方法的对象,或者一个数据结构和函数的集合,实体可以被企业内的多个应用使用的。如果没有企业只是写单个应用的话,这些实体就是应用的业务对象。他们在外部变化时改动最少,例如,不希望页面导航的改变影响到实体对象的改变或者安全性。应用的操作性改变不应该影响实体层。


用例 (Use cases)


这一层的软件包含了应用相关的特定业务逻辑,封装了所以的系统用例。这些用例编排了实体之间的数据流,目标是将实体指向企业层面的业务规则。同样不希望这一层影响到实体,也不希望这一层被外部元素所影响例如 数据库, UI,  或其他通用框架。然而,希望应用操作的改变影响这一层的用例,如果一个用例的实现细节改变了,这一层的一些代码一定受到影响。


接口适配器 (Interface Adapters)


该层的软件是一组适配器的集合,这些适配器将数据转换成用例和实体方便使用的格式,以及一些外部代理方便使用的格式例如数据库或者Web。例如,一个包含MVC架构的图形界面,Presenters, Views, 和 Controllers 都位于该层。models就像数据结构一些从controllers传递到use cases,然后从用例返回到presenters 和 views。


类似的,来自实体和用例的数据会被转换到驻留框架,例如数据库。这一层没有向内的代码来感知外部的数据库。如果数据库是一个SQL 数据库的话, 那么所有SQL被限制在该层,这一层中特殊的部分处理数据库。这一层中还有其他一些适配器转换外部服务的数据到内部使用的用例和实体。


框架与驱动(Frameworks and Drivers)


最外层油框架和工具组成,如数据库,Web框架等。 一般地,不需要写大量的代码就可以和内部的圆进行通信了。这一层细节密布,Web 是细节实现,数据是另一种细节,把他们保持在外可以减少伤害。


大叔的简洁架构只有四层么?绝对不是的,这些圆不过是示意而言,可以远多于4层的。但依赖原则总是适用的,最外圈总是底层的具体实现。


右下角的框图展示了是如何跨越边界的,描绘了Controllers 和Presenters 如何与下一层的用例通信。注意一下控制流,开始于controller, 穿过用例在presenter中执行。这也是源代码依赖,向内执行用例。这就是通常使用的DIP,在Java中,可以通过接口和继承关系来实现跨边界的控制流,动态的多态性可以跨越这一架构的所有边界。跨越边界的典型数据是简单的数据结构。可以使用基本结构或者简单的数据传输对象,或者函数的调用参数,重要的是相互隔离。例如,很多数据库框架都在查询时返回一个数据集, 最好不要让它跨边界传递,它违反了依赖原则即内圆知道了外圆的事情。


回顾


通过将软件分层,遵守依赖原则,形成内在的可测性,隔离外部的元素并具备可替代性,如此而已。


简洁架构更像是一种指导性的原则,核心同样是关注点分离和分层感知,没有摆脱企业级应用架构的经典观念。


如果联想一下复变函数中的保角变换,这 Clean Architecture 就会变成我们熟知的有趣模样了.......




微信扫一扫
关注该公众号

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐