架构整洁之道

简介:

这篇文章是翻译(Uncle Bob Martin)的文章。原文在这:http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html。这篇文章作者尝试使用简单的观点将各种架构的共通之处和最终目标说清楚。全文要说清楚的就是一件事“如何写出整洁的架构”。作者希望在架构系统的时候只需要秉持最简单的两个观点(分层和依赖规则)开发,就能开发出干净整洁的系统架构。

以下是译文

clip_image001

 

过去几年间有许多关于系统架构的观点。比如:

1 六角架构(Hexagonal Architecture )。 这种架构是由Alistair Cockburn提出的,并由Steve Freeman和Nat Pryce在他们的书《Growing Object Oriented Software 》中提到。

2 洋葱架构(Onion Architecture )。提出者是Jeffrey Palermo。

3 尖叫架构(Screaming Architecture)。提出者是Uncle Bob(就是这篇文章的作者)。

DCI 架构。提出者是James Coplien和Trygve Reenskaug。

BCE 架构。提出者是Ivar Jacobson。在他的书《Object Oriented Software Engineering: A Use-Case Driven Approach》中有大量提及对这种架构的说明。

 

虽然这些架构在细节处都有一些变化,但是实际上,它们是非常相似的。它们的目标是一样的,将各种实体间的关系进行分离。它们分离操作的方法也是一样的,采用软件分层的方式。它们分的层中至少有一个业务逻辑层,并且有其他的接口层。

 

每一种架构一定能在写系统的业务逻辑的时候有以下特征:

1 与框架的分离。

框架决不能依赖一些有限制特征的库。这样就能保证你能像使用手边的工具一样简单地使用这些框架,而不会让你的系统业务逻辑在使用前就有一些强制性的约束。

2 可测试性。

业务逻辑必须能独立测试,不需要UI,数据库,Web服务器或者一些其他的外部条件。

3 与UI的分离。

UI必须能非常容易独立地修改。而不能在改变UI的同时需要改变系统其他部分。比如当把系统的UI从Web UI改成控制台UI,你并不需要改变任何业务逻辑的代码。

4 与数据库的分离。

能很方便地在Oracle,SQL Server,Mongo DB,BigTable,CouchDB或者其他数据库中进行切换和改变。业务逻辑决不能依赖这些数据库。

5 与外部结构的分离。

系统的业务逻辑并不需要知道任何外部的结构。

 

文章最上面的图就是将所有这些架构进行统一概括,提取出统一的观点。

依赖规则(The Dependency Rule)

同心圆代表的是不同层级的软件代码。通常当你更深一步思考构造你的系统的时候,你的系统就会在更高的层级。最外层的圈代表的是机制级别的系统。最内层的代表的是策略级别的系统。

最重要的一条规则是依赖规则(The Dependency Rule)。这条规则说的是:代码依赖只能使由外向内。换句话说,内层结构的代码不能包含有任何外层结构的信息。尤其是一些外层结构的名称不应该被内层结构的代码提到,比如函数名,类名,变量名,或者其他的系统实体的名称。

同样的,外层的数据结构不应该被内层代码使用,特别是那些由外部框架生成的数据结构。我们并不希望外部结构的任何东西会影响到内部结构。

实体层(Entities)

实体是用来封装公司的业务规则的。一个实体可以是一个带方法的对象,也可以是一些数据结构和函数。只要实体能被公司的不同业务逻辑部件使用,实体的具体表现形式是无所谓的。

或 许你并不是想写公司级的架构,而只是想写一个简单的应用,那么这里实体就是指的应用的业务逻辑对象。它们封装了最通用的规则,并且当外部环境变化的时候, 这些实体是最不需要被变化的。举例来说,比如在增加翻页需求或者是安全需求的时候,这些实体是最不应该被改变的。没有任何具体的应用需要改变实体层。

用户实例层(Use Cases)

这一层的软件结构包含了具体的应用业务逻辑。它实现了所有的用户实例。这些用户的实例由流入实体的数据流和流出实体的数据流实现,这些用户实例使得内层的实体能依靠实体内定义的业务逻辑规则来完成系统的用户需求。

我们不希望用户实例层的任何改变会影响到实体层。我们同样也不希望用户实例层会被外部的结构层,比如UI、数据库或者任何公共的框架,的改变而影响。这层应该是独立于这些概念的。

当然,必然发生的是应用的业务逻辑被修改会影响到用户实例层的代码和结构。如果用户的需求改变了,这层的部分当然会被修改。

接口适配层(Interface Adapters)

这 一层的软件结构的目的就是进行数据的转换,将便于用户实例和实体层操作的数据结构变化成为最便于外部结构(比如数据库或者Web)操作的数据结构。比如 GUI的MVC结构,表现器、视图器、控制器都是属于这个结构的。这层很可能是通过控制器将数据结构传给用户实例层,并且返回数据给表现器,视图器。

数据在这层会被转换,将便于实体层和用户实例层使用的数据转化成为持久层能使用的数据,比如数据库。这一层的代码并不需要知道任何数据库的信息。如果数据库是SQL数据库,那么,所有的SQL语言应当在这层被限制使用,特别是在这一层中与数据库有交互的代码部分。

当一些外部的服务需要与用户实例层和实体层进行交互的时候,这时候需要的数据转换也理所当然地放在这一层了。

框架和驱动层(Frameworks and Drivers)

最外层是由框架和使用工具组成的。比如数据库,Web框架等。通常你并不需要写很多代码就能达到与内层进行交互的行为。

这层表达的是所有的数据应该具体最终到达的地方。Web是数据的最终到达地,数据库也是数据的最终到达地。我们把这些东西放在最外层,它们几乎对整个系统的架构造不成什么影响。

 

只有四层?

答 案是否定的。这个分层模型是纲要性的。在具体实现中,你会发现你可能需要到比四层更多的层级。并没有任何规定说你必须只能实现这四个层级。但是,依赖规则 (The Dependency Rule)是必须遵守的:代码依赖只能使由外向内。越向内,抽象程度越高,越向外,细节信息越多。当你越向内设计的时候,你需要设计越高层面的策略。内部 层级比外部层级更抽象。

跨层调用

图片的右下角是一个如何跨层调用的例子。它演示了控制器和表现器如何和用户实例层进行交互。注意下流向,从控制器开始,通过用户实例层,然后向上执行到表现器。这里也需要注意它们的代码依赖,必须是向内依赖的。

我们通常使用依赖倒置原则(Dependency Inversion Principle)来处理这种情况。比如在JAVA中,我们会使用接口或者继承关系来保证代码会在制定的地方依赖倒置。

举例说明,假设用户实例需要调用表现器。但是这种调用是违背了依赖规则的:外部的逻辑名称不应该被内部提到。所以我们让用户实例层调用一个接口(这里叫做用户实例输出端口Use Case Output Port),然后让表现层在外部实现这个接口。

相同的方法可以使用在架构的所有跨层调用上。因此实际上我们能使用多种形式的代码依赖达到我们能让控制流按照依赖规则的反方向流动。

什么数据能跨层调用?

一 般跨层调用的数据是简单的数据结构。你可以使用数据结构或者是简单的数据传输流,又或者可以通过函数的参数来进行传递。你也可以将数据封装到一个 hashmap结构,或者一个对象中。数据传输最重要的事情是无依赖,简单。我们并不希望跨层传递的数据是实体,或者是数据表的行数据,理由是我们不希望 数据有任何形式的违反依赖规则。

例如,许多数据库框架对query查询返回行结构,我们叫它RowStructure。我们并不希望将这个RowStructure传递给内层结构,因为这个违反了依赖规则,它会强制让内层结构了解外层的结构。

总结

遵守这些简单的规则并不难,但是它们会解决你很多头疼的问题。将系统分层,遵守依赖规则,你就会自然写出可测试的系统了,所有附带的好处也会实现了。当任何外部的系统是独立的,比如数据库、web框架,你就能以最小的代价将它们进行替换。

作者简介

clip_image002

Robert C. Martin (Uncle Bob) , 8th Light公司的Master Craftsman, 获奖作家,著名的演说家,uber software geek。

它的著作有:

Designing Object Oriented c++ Applications using the Booch Method

Patterns Languages of Program Design 3(程序设计的模式语言)

More c++ Gems

Extreme Programming in Practice(解析极限编程)

Agile Software Development: Principles, Patterns, and Practices(敏捷软件开发:原则、模式与实践)

uml for java Programmers(UML:JAVA程序员指南)

Clean Code (代码整洁之道)

The Clean Coder(编码整洁之道:专业程序员的行为准则)

分类:  架构理论

本文转自快乐就好博客园博客,原文链接:http://www.cnblogs.com/happyday56/p/4403564.html,如需转载请自行联系原作者
相关文章
|
消息中间件 架构师 安全
重新认识架构 — 不只是软件设计
通常情况下,人们对架构的认知仅限于在软件工程中的定义:架构主要指软件系统的结构设计,比如常见的 SOLID 准则、DDD 架构。一个良好的软件架构可以帮助团队更有效地进行软件开发,降低维护成本,提高系统的可扩展性和可维护性。这里的架构定义有更多元化的理解:架构不仅是对软件开发设计和流程规范的定义,也包含了参与架构设计的人员、以及项目过程中和架构有关的活动,都可以称为架构。 从广义角度来理解架构,意味着更全面的思考和新的融合。
48 0
|
6月前
|
存储 设计模式 架构师
编码之道:从技术细节到系统架构的升华
【5月更文挑战第9天】 在编程的世界里,每一行代码都承载着功能与美学的双重使命。本文将探讨如何从关注技术细节出发,逐步深化对系统架构的理解,并在实践中实现从代码编写者到系统设计师的转变。通过分析具体案例,我们将揭示那些看似平凡的技术感悟如何在复杂系统的构建中发挥关键作用,以及这一过程中对软件开发者的启示。
68 3
|
6月前
|
算法
代码重构:优化之道
代码重构:优化之道
|
6月前
|
程序员 开发者
代码之禅:在软件开发中寻求简化之道
当面对错综复杂的系统和冗长的代码时,程序员们往往渴望找到一种简洁而高效的解决方式。本文探讨了如何在软件工程实践中追求简洁性,介绍了几种提升代码质量、优化开发流程的策略,并强调了持续学习与反思的重要性。通过一系列实用的技术感悟,文章旨在引导读者思考如何将“简化”作为编程哲学的一部分,以期达到技术上的精进和心智上的清晰。
|
消息中间件 架构师 安全
重新认识架构—不只是软件设计
结合自身经历阐述架构师定位、架构活动如何保障企业、组织实现商业价值。
重新认识架构—不只是软件设计
|
前端开发 测试技术 数据库
软件架构编年史:整洁架构
软件架构编年史:整洁架构
软件架构编年史:整洁架构
|
前端开发 开发者
架构整洁之道-01 设计与架构
设计:实现业务时的详细的设计,比如模块的依赖设计,业务逻辑设计,前端页面的设计。更偏向于细节内容的设计 - 架构:类似搭建房子一样,先有房子的形状、布局等,一个项目的架构那就是各个模块依赖关系,或者说结构。未来设计方向的一个框架。
146 0
|
消息中间件 存储 缓存
一文读懂架构整洁之道
相信大家都非常清楚,如何编写可读性强的代码是一个合格程序员的必修课。 我在之前的文章《谈谈什么是好的代码》中谈了一些自己对整洁代码的感悟,代码并不是独立存在的,成百上千个类的系统在企业应用中非常常见,如何将代码进行有效的组织,保持高可读性,高可维护性,则是一个好的架构需要考虑的事情。本文从原则切入,聊聊组件的分层和解耦,浅谈下Bob大叔提出的整洁架构,感兴趣的同学也可以发表下自己的看法。
6596 0
一文读懂架构整洁之道
|
设计模式 测试技术 程序员
代码整洁之道(一)最佳实践小结
Any fool can write code that a computer can understand. Good programmers write code that humans can understand. 普通的工程师堆砌代码,优秀的工程师优雅代码,卓越的工程师简化代码。如何写出优雅整洁易懂的代码是一门学问,也是软件工程实践里重要的一环。前段时间通读了三本经典书籍《代码整洁之道 》、《编写可读代码的艺术》、《重构:改善既有代码的设计》,本文将重点从注释、命名、方法、异常、单元测试等方面总结了一些代码整洁最佳实践。
341 0
|
设计模式 算法 程序员
代码大全2札记:软件架构中的设计
代码大全2札记:软件架构中的设计
159 0
下一篇
无影云桌面