Clean Architecture for Beginners

Developing applications and writing code is a rather exciting process and the result of such interesting development can be a messy code, representing a spaghetti architecture, which is difficult to understand and which needs some structuring.

What is “Clean Architecture”?

Architecture refers to the overall design of a project. It is the organization of code into classes, files, components, or modules, and how all of these groups of code relate to each other. Architecture determines where an application performs its core functionality and how that functionality interacts with other components, such as databases and the user interface.

In this context, clean architecture means organizing a project in such a way that it is easy to understand and can be easily changed as the project grows.

Key characteristics of clean architecture

When developing a large project, we need to be able to easily maintain it, changing individual components as needed. To do this, we need to separate files and classes into components that can be changed independently of each other. The picture below shows several interconnected “components”.

What do you need to do if you want to replace the scissors with a knife, as shown in the picture above? You need to untie the strings that go to the pen, the ink bottle, the tape, and the compass. Then you need to tie these items back to the knife. Maybe this will work with the knife, but what if the pen and tape need the scissors to work and won't work without them?

Let's consider another option.

Now, if we need to replace the scissors, we can just pull the scissor string out from under the stickers and add a new string tied to the knife. It's much easier. The stickers don't care because they didn't even have a string tied to them.

From the illustrations provided, it can be concluded that the architecture shown in the second image is much easier to change. Since there is no need to change application notes often, this system will be very easy to maintain. This same concept is an architecture that will make it easier to maintain and change your software.

The inner circle is the domain layer of your application. This is where you put your business rules. By “business” we don't necessarily mean a company. It just means the gist of what your application does, the core functionality of the code. A translation app does translations. An online store has products for sale. These business rules are fairly stable, since you're unlikely to change the gist of what your application does very often.

The outer circle is the infrastructure. It includes things like the user interface, database, web APIs, and frameworks. These things are more likely to change than the domain. For example, you are more likely to change the look of a UI button than the way a loan is calculated.

The boundary between the domain and the infrastructure is set up in such a way that the domain knows nothing about the infrastructure. This means that the UI and the database depend on business rules, but these rules are independent of the UI or the database. This makes it a plug-in architecture. It does not matter whether the UI is a web interface, a desktop application, or a mobile application. It also does not matter whether the data is stored using SQL, NoSQL, or in the cloud. The domain does not care. This makes it easy to change the infrastructure.

Let's talk about terminology

In the image above, we have represented Clean architecture as two circles. However, to better understand the principles of clean architecture, it is better to perform a small decomposition.

Here we subdivide the domain layer into entities and different use cases, and the adapter layer forms the boundary between the domain and the infrastructure layer. Since these terms can be a bit confusing, let's look at them separately.

Entities and Use Cases

An entity is a set of related business rules that are critical to the operation of an application. In an object-oriented programming language, the rules for an entity would be grouped as methods in a class. Even if there were no application, these rules would still exist. For example, charging 10% interest on a loan is a rule that might be imposed by a bank. This would be true whether the interest was calculated on paper or by computer.

It is important to understand that entities do not know anything about other layers and they do not depend on anything. That is, they do not use the names of any other classes or components that are in external layers.

Use cases are the business rules for a specific application. They tell you how to automate the system, and they define the behavior of the application. They interact with objects and depend on them, but they know nothing about the other layers. They don’t care whether it’s a web page or an iPhone app, and they don’t care whether the data is stored in the cloud or in a local SQLite database. This layer defines interfaces or contains abstract classes that outer layers can use.

Adapters and infrastructure

Adapters, also called interface adapters, are translators between the domain and the infrastructure. For example, they take input data from a GUI and repackage it into a form suitable for use cases and entities. They then take output data and repackage it into a form suitable for display in a GUI or storing in a database.

This layer contains all the I/O components: the user interface, the database, frameworks, devices, etc. This is the most unstable layer. Since this layer changes very frequently, it is kept as far away from the more stable domain layers as possible. Since they are kept separate, it is relatively easy to make changes or replace one component with another.

Principles of Clean Architecture Implementation

As a basis for implementing clean architecture, we will consider a set of SOLID principles. These are class-level principles, but have similar analogs that apply to components (groups of related classes).

First letter S – This is the Single Responsibility Principle (SRP). The SRP states that a class should only do one thing. It may have multiple methods, but they all work together to accomplish one primary task. A class should only have one reason to change. For example, if the Finance department has one requirement that will change a class, and the HR department has another requirement that will change the class in a different way, there are two reasons to change. The class should be split into two separate classes, each with only one reason to change.

Letter O – Open-Closed Principle (OCP). Open means open for extension. Closed means closed for modification. So you should be able to add functionality to a class or component, but you shouldn't have to change the existing functionality. You should make sure that each class or component has only one job, and then hide the more stable classes behind interfaces so that they don't get hurt when you have to change the less stable classes.

Liskov Substitution Principle (LSP). This is the letter L in the word SOLID. This principle means that lower-level classes or components can be replaced without affecting the behavior of higher-level classes and components. This can be done by implementing abstract classes or interfaces. For example, in Java, ArrayList and Linked List implement the List interface, so they can be replaced with each other.

Interface Separation Principle (ISP) – letter I. ISP uses an interface to isolate a class from other classes that use it. The interface exposes only the subset of methods that the dependent class needs. Thus, changes to other methods do not affect the dependent class.

And finally, the letter D – Dependency Inversion Principle (DIP). This principle means that less stable classes and components should depend on more stable ones, and not vice versa. If a stable class depends on an unstable class, then every time the unstable class changes, it also affects the stable class. So the direction of the dependency should be changed. We can use an abstract class or hide the stable class behind an interface.

So instead of a stable class, use a Volatile class like this:

    class StableClass {

        void myMethod(VolatileClass param) {

            param.doSomething();

        }

    }

You could create an interface that the Volatile class implements:

  class StableClass {

        interface StableClassInterface {

            void doSomething();

        }

        void myMethod(StableClassInterface param) {

            param.doSomething();

        }

    }

    

    class VolatileClass implements StableClass.StableClassInterface {

        @Override

        public void doSomething() {

        }

    }

This reverses the direction of the dependency. The Volatile class knows the name of the stable class, but the stable class knows nothing about the Volatile class.

It is worth noting that this is not the only way to solve the problem of the direction of dependence, but in this article we will not consider other methods.

Conclusion

In this article, we looked at the basics of the so-called clean architecture and the principles of its use in development. With the help of clean architecture, you can make the architecture of the project much more understandable for understanding and development.


In conclusion, I would like to remind you about the open lessons that will be held in the near future as part of the “Enterprise Architect” course:

  • August 15: The Role of the Corporate Architect in Product Transformation of Business. Sign up

  • August 20: Business Architecture: Key Objects. Sign up

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *