[翻译][架构设计]The Clean Architecture

原文地址:The Clean Architecture

The Clean Architecture

架构图:多层圆环

Over the last several years we’ve seen a whole range of ideas regarding the architecture of systems. These include:

  • Hexagonal Architecture (a.k.a. Ports and Adapters) by Alistair Cockburn and adopted by Steve Freeman, and Nat Pryce in their wonderful book Growing Object Oriented Software(六边形架构,又称Ports and Adapters——端口和适配器)
  • Onion Architecture by Jeffrey Palermo(洋葱架构)
  • Screaming Architecture(尖叫架构?) from a blog of mine last year
  • DCI (数据Data 场景Context 交互Interactions的简称)from James Coplien, and Trygve Reenskaug.
  • BCE by Ivar Jacobson from his book Object Oriented Software Engineering: A Use-Case Driven Approach

Though these architectures all vary somewhat in their details, they are very similar. They all have the same objective, which is the separation of concerns. They all achieve this separation by dividing the software into layers. Each has at least one layer for business rules, and another for interfaces.
(这些架构细节上各有不同,但目的都是关注点分离,通过将软件分层来实现,至少包含业务层和交互接口层)。

Each of these architectures produce systems that are:

  1. Independent of Frameworks. The architecture does not depend on the existence of some library of feature laden software. This allows you to use such frameworks as tools, rather than having to cram your system into their limited constraints.(独立于框架,架构不会依赖任何库提供的特性,这样你可以将这些库作为工具使用,又不会受到它们带给的限制)。

  2. Testable. The business rules can be tested without the UI, Database, Web Server, or any other external element.(可测试:业务逻辑可以不依赖UI、数据库等外部元素被测试)。

  3. Independent of UI. The UI can change easily, without changing the rest of the system. A Web UI could be replaced with a console UI, for example, without changing the business rules.(独立于UI:UI层可以在不修改其它系统模块的情况下被替换为不同的实现形式)。

  4. Independent of Database. You can swap out Oracle or SQL Server, for Mongo, BigTable, CouchDB, or something else. Your business rules are not bound to the database.(独立于DB:数据库的存储方式是可独立替换的)。

  5. Independent of any external agency. In fact your business rules simply don’t know anything at all about the outside world.(独立于任何外部代理:业务逻辑应该对外界一无所知)。

The Dependency Rule

The concentric circles represent different areas of software. In general, the further in you go, the higher level the software becomes. The outer circles are mechanisms. The inner circles are policies.(架构圆圈图中越外边越高层,内部是设计决策,外部是实现机制。)

The overriding rule that makes this architecture work is The Dependency Rule. This rule says that source code dependencies can only point inwards. Nothing in an inner circle can know anything at all about something in an outer circle. In particular, the name of something declared in an outer circle must not be mentioned by the code in the an inner circle. That includes, functions, classes. variables, or any other named software entity.(任何命名的软件实体,内部不会了解外部中的)。

By the same token, data formats used in an outer circle should not be used by an inner circle, especially if those formats are generate by a framework in an outer circle. We don’t want anything in an outer circle to impact the inner circles.(外部使用的数据格式,内部也不能引用,尤其是外部框架产生的)。

Entities

Entities encapsulate (封装)Enterprise wide business rules. An entity can be an object with methods, or it can be a set of data structures and functions. It doesn’t matter so long as the entities could be used by many different applications in the enterprise.

If you don’t have an enterprise, and are just writing a single application, then these entities are the business objects of the application. They encapsulate the most general and high-level rules. They are the least likely to change when something external changes. For example, you would not expect these objects to be affected by a change to page navigation, or security. No operational change to any particular application should affect the entity layer.
(实体封装了软件中最抽象/一般化、高层次的规则,它们最不受系统其它部分的影响)。

Use Cases

The software in this layer contains application specific business rules. It encapsulates and implements all of the use cases of the system. These use cases orchestrate the flow of data to and from the entities, and direct those entities to use their enterprise wide business rules to achieve the goals of the use case.
(用例层包含了软件功能相关的业务规则,实现了系统的所有使用操作。用例对象操纵entity,利用其提供的企业级业务规则来完成用例操作,用例对象传递数据给entity,或接受其返回的数据。)

We do not expect changes in this layer to affect the entities. We also do not expect this layer to be affected by changes to externalities such as the database, the UI, or any of the common frameworks. This layer is isolated from such concerns.
(use-case层的变化不应该影响entity,也不受UI、DB等其他部分的影响。)

We do, however, expect that changes to the operation of the application will affect the use-cases and therefore the software in this layer. If the details of a use-case change, then some code in this layer will certainly be affected.(软件的设计操作变化会影响use-case,及其实现代码。)

Interface Adapters

The software in this layer is a set of adapters that convert data from the format most convenient for the use cases and entities, to the format most convenient for some external agency such as the Database or the Web. It is this layer, for example, that will wholly contain the MVC architecture of a GUI. The Presenters, Views, and Controllers all belong in here. The models are likely just data structures that are passed from the controllers to the use cases, and then back from the use cases to the presenters and views.
(这层中的model要么是controller传递给use-case的数据结构,或者use-case传递给ppresenters、views的。)

Similarly, data is converted, in this layer, from the form most convenient for entities and use cases, into the form most convenient for whatever persistence framework is being used. i.e. The Database. No code inward of this circle should know anything at all about the database. If the database is a SQL database, then all the SQL should be restricted to this layer, and in particular to the parts of this layer that have to do with the database.

Also in this layer is any other adapter necessary to convert data from some external form, such as an external service, to the internal form used by the use cases and entities.
(接口适配层:将外部UI、DB所用到的适合它们的数据格式转换为entity、use-case所适合使用的model,或者反向转换出去到外部。)

Frameworks and Drivers

The outermost layer is generally composed of frameworks and tools such as the Database, the Web Framework, etc. Generally you don’t write much code in this layer other than glue code that communicates to the next circle inwards.

This layer is where all the details go. The Web is a detail. The database is a detail. We keep these things on the outside where they can do little harm.
(这里是各种工具、库的使用,包含软件中所有具体细节的实现,一般是各种粘合代码,向内部同相邻的层通信。)

Only Four Circles?

No, the circles are schematic. You may find that you need more than just these four. There’s no rule that says you must always have just these four. However, The Dependency Rule always applies. Source code dependencies always point inwards. As you move inwards the level of abstraction increases. The outermost circle is low level concrete detail. As you move inwards the software grows more abstract, and encapsulates higher level policies. The inner most circle is the most general.
(圆环图只是一个图解,着重展示了架构各层的依赖朝向,越是内部越抽象,层次更高,越是外部就越是具体,越是细节。)

Crossing boundaries

At the lower right of the diagram is an example of how we cross the circle boundaries. It shows the Controllers and Presenters communicating with the Use Cases in the next layer. Note the flow of control. It begins in the controller, moves through the use case, and then winds up executing in the presenter. Note also the source code dependencies. Each one of them points inwards towards the use cases.

We usually resolve this apparent contradiction by using the Dependency Inversion Principle. In a language like Java, for example, we would arrange interfaces and inheritance relationships such that the source code dependencies oppose the flow of control at just the right points across the boundary.

For example, consider that the use case needs to call the presenter. However, this call must not be direct because that would violate The Dependency Rule: No name in an outer circle can be mentioned by an inner circle. So we have the use case call an interface (Shown here as Use Case Output Port) in the inner circle, and have the presenter in the outer circle implement it.

The same technique is used to cross all the boundaries in the architectures. We take advantage of dynamic polymorphism to create source code dependencies that oppose the flow of control so that we can conform to The Dependency Rule no matter what direction the flow of control is going in.

架构图:多层圆环

上面架构图的右下角展示了一个控制流,当操作需要在相邻层之间发生时,内层定义接口,外层实现接口,以此满足依赖反转的原则。这样内层对外层就没有依赖了,保持其抽象和高层级,不收具体实现变化的影响。比如,内层收到外部不同实现返回的数据是内层定义好的。

Conclusion

Conforming to these simple rules is not hard, and will save you a lot of headaches going forward. By separating the software into layers, and conforming to The Dependency Rule, you will create a system that is intrinsically testable, with all the benefits that implies. When any of the external parts of the system become obsolete, like the database, or the web framework, you can replace those obsolete elements with a minimum of fuss.
(遵循以上架构准则,分层和依赖方向设计,就可以保持系统的可测试性,当外层任意实现需要更新时,内层都受到最小的影响。)

(本文使用Atom编写)

posted @ 2017-04-20 22:41  everhad  阅读(3048)  评论(0编辑  收藏  举报