Clean Architecture¶
Usually, the principles of clean architecture are commonly analyzed based on a nice circular diagram (previously even using the term Onion Architecture, now somewhat forgotten), moving from the center to the outer boundaries and explaining the transformations that occur along the way. Circular diagrams look aesthetic and inspire a certain hope for their immaculate perfection and unwavering stability. In some illustrations, the multi-layered little circle is also cut through, first turning it inside out into a semicircle, and then into a linear cut.
Let's try to simplify everything a bit and do without graphic illustrations altogether.
To do this, let's first consider the reverse example - "dirty" architecture.
So, we want to create a completely new program. Let's not complicate the example; we want to write a simple C# program called "Tic-Tac-Toe" with a basic Command Line Interface (CLI), where the user's move input and the output of the resulting game board occur without a graphical interface, just using a simple bash script. The short program is written, works well, and pleases its owner.
The programmer who developed "Tic-Tac-Toe" was versatile and decided to redesign the program's interface from CLI to WPF. The modification didn't take much time, and very soon, the new Windows-style program delighted its creator. After some time, the developer used Blazor to create the same game but with a web interface so that it could be played in a browser.
After a while, the programmer discovered a small bug in the program's code. In some rare combinations on the game board, the game behaved incorrectly and outputted the wrong result. Fortunately, the error was simple, and fixing it in all three programs with three different interfaces (CLI, windowed, and web) did not take much time.
What are the main negative aspects of the demonstrated approach, the "dirty" architecture?
First — the game logic is intertwined with the interface logic. When changing the interface (an entity external to the game engine), it is necessary to overhaul everything. Second — when expanding the program's functionality, fixing errors, even with simple refactoring, you need to edit some identical entities in multiple places, which, of course, does not contribute to either speed or quality of work. Third — the game's core, its logic, is forced to know how different interfaces work, just for normal interaction with them, as it is the core that decides what the user sees within each specific moment of the game.
If these small, seemingly rough edges are multiplied by the number of entities exploited within one modern software product and the complexity is extrapolated from a pet project to a real business product, all these problems mentioned can indeed lead to the existing project being very expensive or almost impossible to modify and update.
Let's move on to the pure architecture. I remind you that clean architecture is not a panacea or a cure for all problems. There are many questions to which it does not provide an answer, and designing software using clean architecture approaches does not turn into a formal step-by-step procedure. Although clean architecture declares that the network and database are only external environments and of secondary importance, you probably won't be able to swiftly replace PostgreSQL with Redis or REST with gRPC if you suddenly want to. But you will definitely get additional layers of abstractions.
Designing our "Tic-Tac-Toe" game, clean architecture recommends starting with the so-called business logic. Business logic, simply put, is that part of our project that will be preserved, even if there are no communication networks, databases, or computers in the world. Banking, commerce, education, cartography, and thousands of other human inventions (including, by the way, "Tic-Tac-Toe") functioned perfectly well without CPUs, databases, and REST, using paper, parchment, goatskins, or cuneiform on wet clay.
The business logic knows nothing about the external world, uses names of variables, DTOs, computational schemes, and data structures convenient solely to itself. The business logic never refers directly to the database or network; it simply has no knowledge of databases or networks whatsoever. All that the business logic of the "Tic-Tac-Toe" game knows are the rules of playing "Tic-Tac-Toe."
Next come the so-called use cases - descriptions of the system's behavior when interacting with external entities (or actors) that can be people or other programs. Use cases, in turn, know about the business logic, use it, but know nothing about the layer above. It is important to remember that use cases are currently not as relevant as before, and, along with UML, RUP, and other entities aimed at simplifying business planning in programming, they are gradually losing their relevance. So, you may not separate the business logic and use cases.
Next is the layer of interfaces. In this layer, data is transformed from a format convenient for the business logic and use cases into a format suitable for external entities, such as databases or a user interface.
And, finally, the outermost layer - the link to the external world, with frameworks, interfaces, and databases.
The number of layers can vary, but the main rule of dependencies must always be followed: dependencies must always be inward-directed.
Go to RU version of this page.
codifycamera.com © CC BY-NC-SA 4.0 2024 — ∞ Mikhail Emelyanov, war4one@gmail.com