DEV Community

Cover image for Building Software with Clean Architecture
Brandon Gautama
Brandon Gautama

Posted on

Building Software with Clean Architecture

What is software architecture?

It is the shape given to a software system. A software system is made up of individual components. What those components are, how they are arranged and the way they communicate with each other makes up its architecture.

Why clean architecture matters?

The Only Constant is Change! There are two types of values of a software system: functionality (behavior) and architecture (structure). Its functionality value comes from the features it supports, while its architectural value comes from its ability to evolve and adapt to change. That flexibility depends critically on the shape of the system, the arrangement of its components, and the way those components are interconnected.

A clean architecture facilitates the development, deployment, operation, and maintenance of the software system to support its lifecycle. A software system can work perfectly fine today and a good software architecture makes it easy to change if a new requirement comes in tomorrow. It is easy to develop, easy to maintain, and easy to deploy. On the other hand, a messy architecture is very resistant to change.

The ultimate goal is to minimize the lifetime cost of the system and to maximize programmer productivity. If you hold change as a constant, you will learn to adapt and manage its complexities well. Your software should reflect this principle and allow itself to evolve and adapt.

How to build software with clean architecture?

The strategy is to leave as many options open as possible, for as long as possible.

What are the options that we need to leave open? They are the details that don’t matter.

Software systems are made up of two major elements: policy and details. The policy encapsulates all the business rules and procedures. It is where the true value of the system lives. While the details are things that enable humans, other systems, and programmers to communicate with the policy, but do not impact the behavior of the policy. Examples of details are IO devices, databases, web systems, servers, frameworks, communication protocols, etc.

The goal of the architect is to create a shape for the system that recognizes policy as the most essential element of the system while making the details irrelevant to that policy. This allows decisions about those details to be delayed and deferred.

A clean software architecture produces software systems that have the following characteristics:

  • Independent of frameworks - The architecture does not depend on the existence of some library external libraries/frameworks. They are just tools and you should not force your system to the constraints of the specific frameworks.
  • Testable - The business rules can be tested without the UI, database, web server, or any other external element that are details.
  • Independent of the UI - The UI can change easily, without changing the rest of the system. A web UI could be substituted with a console UI without changing the business rules.
  • Independent of the database - You can swap out Oracle or SQL Server for Mongo, BigTable, CouchDB, etc. Your business rules are not bound to the database.
  • Independent of any external agency - Your business rules shouldn't know about the interfaces to the outside world.

Software Architecture

The concentric circles above represent different areas of software. 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: Source code dependencies must point only inward, toward higher-level policies.

Inner circles should never know anything the outer circles. Specifically, the name of something declared in an outer circle must not be mentioned by the code in an inner circle. That includes functions, classes, variables, or any other named software entity.

By the same token, data formats declared in an outer circle should not be used by an inner circle, especially if those formats are generated by a framework in an outer circle. We don’t want anything in an outer circle to impact the inner circles.

1. Entities

Entities are where the enterprise-wide Critical Business Rules lives. They can be used by many different applications in the enterprise, or they can just be the business objects of an 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.

2. Use Cases

The software in the use cases layer contains application-specific business rules. They orchestrate the flow of data to and from the entities, and direct those entities to use their Critical Business Rules to achieve the goals of the use case.

Any change in this layer should not affect the entities. We do not expect this layer to be affected by changes to externalities such as the database, the UI, or any of the common frameworks. However, we do expect that changes to the operation of the application will affect the use cases and, therefore, the software in this layer.

3. Interface Adapters

This layer contains adapters that convert data from the format most convenient for the use cases and entities, to the format most convenient for some external components such as the database or the web. It is this layer, for example, that contain the MVC architecture of a GUI. The presenters, views, and controllers all belong in this layer. 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.

No code inward of this circle should know anything at all about the database. If the database is a SQL database, then all SQL should be restricted to this layer.

This layer also contain 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.

4. Frameworks and Drivers

The outermost layer of the model is generally composed of frameworks and tools such as the database and the web framework. Generally you don’t write much code in this layer, other than glue code that communicates to the next circle inward.

The frameworks and drivers 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.

Conclusion

Conforming to these rules allow you to build a flexible system. By separating the software into layers and conforming to the Dependency Rule, you will create a system that is intrinsically testable and adaptable.

References: The content of this article is referencing concepts/ideas from the book Clean Architecture by uncle Bob (Robert C. Martin). It is a really great book that I recommend to further if you're interested about software architecture.

Clean Architecture: A Craftsman's Guide to Software Structure and Design (Robert C. Martin Series). Buy it here: https://amzn.to/3SJguhf

Top comments (0)