每次調試都必須clean
by Daniel Oliveira
丹尼爾·奧利維拉(Daniel Oliveira)
如何使用“ The Clean Architecture”每次編寫健壯的應用程序 (How to write robust apps every time, using “The Clean Architecture”)
As developers, we can’t keep from using external libraries and frameworks in our systems. The community’s hands build marvelous tools, and using them is only natural. However, everything has a downside.
作為開發人員,我們無法避免在系統中使用外部庫和框架。 社區的手在打造奇妙的工具,并且使用它們是自然而然的。 但是,一切都有缺點。
Careless teams and individuals can get in a dangerous situation by structuring their systems around the tools they use. Business rules get mixed up with implementation details. This can result in a brittle system, hard to extend and maintain. What should be a quick change in the GUI ends up turning into a bug hunt that lasts for hours. But it does not have to be like this.
粗心的團隊和個人可能會因圍繞使用的工具構建系統而陷入危險境地。 業務規則與實現細節混在一起。 這會導致系統脆弱,難以擴展和維護。 GUI中應該進行的快速更改最終變成了持續數小時的錯誤搜尋。 但是不必一定是這樣。
Software Architecture proposes models and rules to determine the structures (like classes, interfaces, and structs) in a system and how they relate to each other. These rules promote reusability and the separation of concerns for these elements. This makes it easy to change implementation details such as the DBMS or front-end library. Refactors and bug fixes affect as little parts of the system as possible. And adding new features becomes a breeze.
軟件體系結構提出了模型和規則,以確定系統中的結構(如類,接口和結構)以及它們之間的關系。 這些規則促進了可重用性以及這些元素的關注點分離。 這使得更改實施細節(例如DBMS或前端庫)變得容易。 重構和錯誤修復影響盡可能少的系統部分。 并且添加新功能變得輕而易舉。
In this article, I will explain an architecture model proposed in 2012 by Robert C. Martin, Uncle Bob. He is the author of classics like Clean Code and The Clean Coder. In October of this year, he’ll launch another book, Clean Architecture.
在本文中,我將解釋由Robert C. Martin和Bob叔叔 于2012年提出的架構模型 。 他是Clean Code和Clean Coder等經典著作的作者。 今年10月,他將發行另一本書《 清潔建筑》 。
The model has the same name as the book, and it’s built on simple concepts:
該模型與書名相同,它基于簡單的概念構建:
Divide the system’s composition into layers with distinct and well-defined roles. And restrain the relationships between entities in different layers. There’s nothing new in splitting your application in layers. But I chose this approach as it was the one that was the simplest to grasp and execute. And it makes testing use cases dead simple.
將系統的組成劃分為具有不同且定義明確的角色的層。 并限制不同層次實體之間的關系。 將應用程序分成幾層沒有什么新鮮的。 但是我選擇了這種方法,因為它是最容易掌握和執行的方法。 它使測試用例變得簡單。
We just have to make sure the Interactors work properly, and we’re good to go. Don’t worry if the word “Interactors” seemed alien to you, we will learn about them soon.
我們只需要確保Interactors可以正常工作,就可以了。 如果您對“ Interactors”一詞陌生,請不要擔心,我們將盡快了解它們。
From inside out, we are going to explore each of the layers a bit further. We’ll use a sample application that’s quite familiar to us: counters. It takes no time to understand, so we can focus on this article’s subject.
從內而外,我們將進一步探索每個圖層。 我們將使用一個我們非常熟悉的示例應用程序:計數器。 它不需要花時間來理解,因此我們可以專注于本文的主題。
You can find a demo of the app here, and the code samples will be in TypeScript. Some of the code gists below use React and Redux. Some knowledge about these solutions can help in understanding them. Yet, Clean Architecture’s concepts are much more universal. You will be able to understand it even without previous knowledge of the mentioned tools.
您可以在此處找到該應用程序的演示,并且代碼示例將在TypeScript中。 下面的一些代碼要點使用React和Redux。 有關這些解決方案的一些知識可以幫助理解它們。 但是,Clean Architecture的概念更為通用。 即使您以前不知道所提到的工具,也可以理解它。
實體 (Entities)
Entities are in the diagram as Enterprise Business Rules. Entities include business rules that are universal to a company. They represent entities that are basic to its area of operation. They are the components with the highest level of abstraction.
實體在圖中作為“企業業務規則”。 實體包括公司通用的業務規則。 它們代表了其運營領域的基礎實體。 它們是最高抽象級別的組件。
In our counters sample, there’s a very obvious Entity: the Counter
itself.
在我們的計數器樣本中,有一個非常明顯的實體: Counter
本身。
用例 (Use Cases)
Use Cases are pointed out as Application Business Rules. They represent each of the use cases of a single application.Each element of this layer provides an interface to the outer layer and act as a hub that communicates with other parts of the system. They’re responsible for the complete execution of the use cases and are commonly called Interactors.
用例被指出為應用程序業務規則。 它們代表單個應用程序的每個用例。該層的每個元素都提供了與外層的接口,并充當與系統其他部分進行通信的集線器。 他們負責用例的完整執行,通常稱為交互器。
In our sample, we have a Use Case for incrementing
or decrementing
our counter
:
在我們的示例中,我們有一個用例來incrementing
或decrementing
counter
:
Note that the factory function for ChangeCounterInteractor
receives a parameter of the type CounterGateway
. We will discuss the existence of this type will later in the article. But we can say that Gateways are what stands between Use Cases and the next layer.
請注意, ChangeCounterInteractor
的工廠函數接收類型為CounterGateway
的參數。 我們將在本文后面討論這種類型的存在。 但是我們可以說網關是介于用例和下一層之間的東西。
接口適配器 (Interface Adapters)
This layer consists of the boundary between the system’s business rules and the tools that allow it to interact with the external world, like databases and graphical interfaces. Elements in this layer act as mediators, receiving data from one layer and passing it forward to the other, adapting the data as needed.
該層由系統的業務規則和允許其與外部世界進行交互的工具(例如數據庫和圖形界面)之間的邊界組成。 該層中的元素充當中介者,從一個層接收數據并將其轉發給另一層,并根據需要調整數據。
In our sample, we have several Interface Adapters. One of them is the React component that presents the Counter
and its controls to increment
and decrement
:
在我們的示例中,我們有幾個接口適配器。 其中之一是React組件,它提供Counter
及其increment
和decrement
控件:
Note that the component does not use a Counter
instance to present its value, but an instance of CounterViewData
instead. We’ve made this change to decouple presenting logic from business data. An example of this is the logic of exhibition of the counter based on the view mode (Roman or Hindu-Arabic numerals). An implementation of CounterViewData
follows below:
請注意,該組件不使用Counter
實例來顯示其值,而是使用CounterViewData
的實例。 我們進行了此更改,以使呈現邏輯與業務數據脫鉤 。 一個例子是基于視圖模式(羅馬或印度阿拉伯數字)的柜臺展示邏輯。 CounterViewData
的實現如下:
Another example of an Interface Adapter would be our application’s Redux implementation. Modules responsible for requests to a server and the use of local storage would also live inside this layer.
接口適配器的另一個示例是我們應用程序的Redux實現。 負責服務器請求和本地存儲使用的模塊也將駐留在此層中。
框架和驅動 (Frameworks and Drivers)
The tools your system uses to communicate with the external world compose the outermost layer. We don’t usually write code in this layer, that includes libraries such as React/Redux, browser APIs, etc.
系統與外部世界進行通信所使用的工具構成了最外層。 我們通常不會在這一層中編寫代碼,包括諸如React / Redux,瀏覽器API之類的庫。
依賴規則 (The Dependency Rule)
This division into layers has two main goals. One of them is to make clear the responsibilities of each part of the system. The other is to make sure that each of them fills their roles as independently from each other as possible. For this to happen, there’s a rule that states how the elements should depend on each other:
這種劃分有兩個主要目標。 其中一項是明確系統各部分的職責。 另一個是確保他們每個人都盡可能獨立地扮演自己的角色。 為了做到這一點,有一條規則規定了元素應該如何相互依賴:
An element must not depend on any element belonging to a layer outside its own.
元素不得依賴于屬于其自身外部圖層的任何元素。
For example, an element in the Use Cases layer can’t have any knowledge about any class or module related to GUI or data persistence. Likewise, an Entity can’t know which Use Cases make use of it.
例如,“用例”層中的元素不具有與GUI或數據持久性相關的任何類或模塊的任何知識。 同樣,實體不知道哪些用例在使用它。
This rule may have raised questions in your head. Take a Use Case, for example. It’s triggered as result of user interaction with the UI. Its execution involves the update in some persistent data storage such as a database. How can the Interactor make the relevant calls to the update routines without depending on an Interface Adapter that’s responsible for data persistence?
這條規則可能使您產生疑問。 以一個用例為例。 它是由于用戶與UI交互而觸發的。 它的執行涉及某些持久性數據存儲(例如數據庫)中的更新。 交互器如何在不依賴于負責數據持久性的接口適配器的情況下對更新例程進行相關調用?
The answer lies in an element that we’ve mentioned before: Gateways. They’re responsible for establishing the interface needed by the Use Cases to do their jobs. Once they’ve established this interface, it’s up to the Interface Adapters to fulfill their side of the contract, as shown in the diagram above. We have the CounterGateway
interface and a concrete implementation using Redux below:
答案在于我們之前提到的元素: Gateways 。 他們負責建立用例完成工作所需的接口。 一旦他們建立了這個接口,就由接口適配器來履行其合同,如上圖所示。 我們具有CounterGateway
接口和以下使用Redux的具體實現:
您可能不需要它 (You may not need it)
Of course, this sample application was somewhat over complicated for an increment/decrement counter app. And I’d like to make clear that you do not need all this for a small project or prototype. But trust me, as your application gets bigger you’ll want to maximize reusability and maintainability. Good software architecture makes projects resistant to the passing of time.
當然,對于遞增/遞減計數器應用程序,此示例應用程序有些復雜。 我想明確指出,對于一個小型項目或原型,您不需要所有這些。 但是請相信我,隨著您的應用程序變得更大,您將需要最大程度地提高可重用性和可維護性。 良好的軟件體系結構使項目可以抵抗時間的流逝。
好吧...那又如何呢? (Okay… So what?)
With this article, we discovered an approach to decouple our systems’ entities. This makes them easier to maintain and extend. For example, to build the same application using Vue.js, we would only have to rewrite CounterPage
and CounterWidget
components. The source code of the sample application is in the link below:
通過本文,我們發現了一種分離系統實體的方法。 這使它們更易于維護和擴展。 例如,要使用Vue.js構建相同的應用程序,我們只需要重寫CounterPage
和CounterWidget
組件。 示例應用程序的源代碼在下面的鏈接中:
Valbrand/counter-clean-architectureContribute to counter-clean-architecture development by creating an account on GitHub.github.com
Valbrand / counter-clean-architecture 通過在GitHub上創建一個帳戶來促進反清潔架構的開發。 github.com
This story was translated to Portuguese by me! It is available here.
我把這個故事翻譯成葡萄牙語! 在這里可用。
What pros and cons do you see in this approach? Have you used something similar in production? Share your experiences in the responses. If you like the article, please clap for me!
您在這種方法中看到什么利弊? 您在生產中使用過類似的東西嗎? 在回應中分享您的經驗。 如果您喜歡這篇文章,請為我鼓掌!
翻譯自: https://www.freecodecamp.org/news/how-to-write-robust-apps-consistently-with-the-clean-architecture-9bdca93e17b/
每次調試都必須clean