[翻譯][架構設計]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:html

  • 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.
(這些架構細節上各有不一樣,但目的都是關注點分離,經過將軟件分層來實現,至少包含業務層和交互接口層)。web

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層能夠在不修改其它系統模塊的狀況下被替換爲不一樣的實現形式)。app

  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.(獨立於任何外部代理:業務邏輯應該對外界一無所知)。ide

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編寫)