The Clean Architecture--一篇很不錯的關於架構的文章


    翻譯水平有限,見諒!

 

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

在過去的幾年里,我們已經看到了關於系統架構的一系列想法,包括:

 

 

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.

框架獨立。架構不依賴於一些滿載功能的軟件庫。這可以讓你像使用工具一樣使用這樣的框架,而不是把系統塞到他們有限的約束之中。

 

  1. Testable. The business rules can be tested without the UI, Database, Web Server, or any other external element.

可測試性。業務規則可以在沒有UI,數據庫,Web服務器,或者其他外部元素的情況下完成測試。

 

  1. 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的簡易修改。如,Web UI可以在不改變業務規則的基礎之上替換成控制台UI。

 

  1. 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.

數據庫獨立。業務規則不綁定的數據庫中,這樣你可以更換Oracle or SQL Server, for Mongo, BigTable, CouchDB,或者其他數據庫。

 

  1. Independent of any external agency. In fact your business rules simply don’t know anything at all about the outside world.

外部機制獨立。事實上業務規則根本不知道外層的事情。

 

The diagram at the top of this article is an attempt at integrating all these architectures into a single actionable idea.

本文上方的圖片嘗試着把這些架構整合到一個單一可執行的想法中。

 

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.

此層次的軟件包含了應用的特定業務規則。它整合並且實現了系統中需要的所有用例。這些用例協調着來往於實體之間的數據流,並且指引實體使用它們企業范圍內的業務規則實現用例的目標。

 

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.

我們不希望變動這層會影響到實體。也同樣不希望這層會受到外層變動的影響,如數據庫,UI,或者其他的通用框架。從這樣的想法觸發,這個層次應該是獨立的。

 

We do, however, expect that changes to the operation of the applicationwill 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.

但是,應用操作的改變仍然會影響到用例和這個層次的軟件。如果用例的細節改變了,那么這層的相關代碼當然也要變。

 

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.

這層的軟件是一系列的適配器,作用於將用例和實體方便使用的數據格式轉換成如數據庫或者Web等外層方便的數據格式。比如,這層包含全部的GUI的MVC架構。Presenters,Views,Controllers全部都屬於這層。模型可能是一種從控制層到用例層,又從用力曾返回給persistents和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.

相似的,數據從實體和用例層方便的形式轉換到持久層框架使用的方便的形式,即,數據庫。這層以里不會有代碼知道任何數據庫相關的東西。如果數據庫是SQL數據庫,那么所有的SQL應當被限制在這個層次中,特別的,這個層次不得不與數據庫進行交互。

 

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.

在這個層次,任何其他的適配器都需要將數據從外部形式(如外部服務)轉換成用例和實體使用的內部形式。

 

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.

最外層一般包含框架和工具,如數據庫Web框架等等。通常,這層不需要寫太多的和其他里層通信的膠水代碼。

 

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.

這層包含所有的細節,Web是細節,數據庫是細節,我們把這些東西放到外層可以減少對整體的傷害。

 

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.

不,這幾個環只是概要。可能你會發現你需要比這4個還要多的環。沒有規則知名一定要有這4個環。但是,依賴規則總是要被應用。源碼依賴總是指向內層。越往內層移動抽象的等級越高。最外層環是低抽象等級的具體細節。越往內層移動抽象的等級越高,也封裝了更高等級的策略。最內層是最通用的策略。

 

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.

圖的右下方是一個表示如何跨越環形界限的列子。它展現了Controllers和Presenters通過下一次的用戶進行交互的情形。注意控制流。它開始於Controller,移動穿越用例層,然后在Persenter層執行。同樣注意代碼依賴規則。他們中的每個都指向里層的用例。

 

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.

我們通常使用依賴倒置規則來解決這個明顯的矛盾。在一種語言中,比如Java,我們會安排接口和繼承關系,這樣源代碼依賴可以反向控制流在恰到好處的點跨越邊界。

 

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.

比如,用例需要調用persenter。然而,這個不能直接調用,因為會違反依賴規則:外層環的任何名字都不能在內層環提及。所以在里層環我們使用用例調用接口(這里展現為Use Case Output Port),並且在外層環實現它。

 

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.

相同的技術被用於跨越架構中的所有邊界。我們使用動態多態的優勢創建代碼依賴來反向控制流,這樣保證不管控制流是從哪個方向進來都滿足依賴規則。

 

What data crosses the boundaries.

什么數據跨越邊界

Typically the data that crosses the boundaries is simple data structures. You can use basic structs or simple Data Transfer objects if you like. Or the data can simply be arguments in function calls. Or you can pack it into a hashmap, or construct it into an object. The important thing is that isolated, simple, data structures are passed across the boundaries. We don’t want to cheat and pass Entities or Database rows. We don’t want the data structures to have any kind of dependency that violates The Dependency Rule.

通常跨越邊界的數據是簡單的數據結構。如果喜歡,可以使用基本數據結構或者簡單的數據傳輸對象。或者數據也可以簡單的是函數調用的參數。或者你可以打包成hashmap,或者構建一個對象。最重要的是獨立,簡單的數據結構在邊界見跨越。我們不應該欺騙性的傳輸實體或者數據庫結果集。我們不應該讓傳輸的數據結構含有違法依賴規則的某種依賴關系。

 

For example, many database frameworks return a convenient data format in response to a query. We might call this a RowStructure. We don’t want to pass that row structure inwards across a boundary. That would violateThe Dependency Rule because it would force an inner circle to know something about an outer circle.

例如,很多數據庫框架返回簡單的數據格式給查詢。我們稱之為RowStructure。我們不應該通過邊界傳輸這樣的結構到里層。這會違反依賴規則,因為它強制了內層環來知道外層的東西。

 

So when we pass data across a boundary, it is always in the form that is most convenient for the inner circle.

所以,我們跨界傳遞數據的時候,數據總是要以內層需要的最簡單的方式來傳遞。

 

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.

遵循這些簡單的規則並不困難,並且會為你省去很多前進中頭痛的事情。將軟件分層,並且遵循依賴規則,將保證你建立一個本質上可測試的系統,並且包含有我們闡述的優點。如果系統的外部模塊過時了,比如數據庫或者Web框架,你可以在投入最小的情況下來替換這些元素。

 

Uncle Bob Martin is 8th Light's Master Craftsman. He's an award winning author, renowned speaker, and über software geek since 1970.

Tweet Follow @unclebobmartin


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM