Peter Streef

Clean Architecture

Andromeda

As part of my mission to write better software I researched to subject of Clean Architecture. After reading the book by Uncle Bob I tried out some of the more practical advise.

🌌 What is architecture

In the context of software development, architecture refers to the high-level design of a system that outlines its components, interactions, and dependencies. The goal of architecture is to reduce the complexity of the system, making it easier to develop, maintain, and scale.

Good architecture is an exercise in trade-offs, balancing competing goals and constraints to achieve the desired outcomes. By limiting the options and defining clear boundaries between components, architecture helps to prevent “analysis paralysis” and decision-making overload, allowing developers to focus on the most critical aspects of the system.

Tabs vs Spaces? Who cares, pick 1 and stick with it.

Me - in this blog post

As pointed out before in Naming Things 60-80% of a developers time is spend on understanding the system. This leaves a lot of room for optimization and potential productivity increases. Architecture plays a big role in how easy a system is understood.

The primary purpose of architecture is to support the life cycle of the system. Good architecture makes the system easy to understand, easy to develop, easy to maintain, and easy to deploy. The ultimate goal is to minimize the lifetime cost of the system and to maximize programmer productivity.

The eclipse foundation

In summary, the primary objective of architecture is to optimize the use of human resources to build and maintain a system by simplifying its structure and dependencies.

What it is not

It’s important to understand that architecture is not about the specific technologies or tools used to build a system. These are implementation details that can be addressed at a later stage of development. Instead, architecture focuses on the broader structure and design of the system, including its components, interactions, and dependencies. By separating these concerns, architecture enables developers to make informed decisions about how to implement the system using appropriate technologies and tools.

🔌 Ports & Adaptors

In Ports & Adaptors architecture, the idea is to separate the domain code from the infrastructure code and connect them via ports. Ports act as a bridge between the domain and infrastructure, allowing the domain code to remain independent of the infrastructure implementation.

Ports

Ports are interfaces that define how the domain code interacts with the outside world. There are two types of ports:

  • Input ports: These ports are used by external actors to interact with the system. They define the interface for receiving requests from external systems.
  • Output ports: These ports are used by the system to interact with external actors. They define the interface for sending side-effects to external systems.

Adaptors

Adapters are implementations of the ports that bridge the gap between the domain code and the infrastructure. They are responsible for translating the data from the infrastructure into a format that the domain code can understand and vice versa.

There are two types of adapters:

  • Inbound adapters: These adapters are responsible for receiving requests from external systems and translating them into a format that the domain code can understand.
  • Outbound adapters: These adapters are responsible for translating the data from the domain code into a format that external systems can understand.

Domain

The domain layer contains the business logic of the system. It is where the rules and behaviors that define the system are implemented. Further segregation of the domain layer can also improve the encapsulation of different parts of the business domain. This can be achieved by breaking down the domain layer into smaller, more specific subdomains, each with their own set of rules and behaviors.

By doing so, each subdomain can be developed and maintained independently, without affecting the rest of the system. This also makes it easier to reason about the system as a whole, as each subdomain can be treated as a separate entity.

Infrastructure

The infrastructure layer contains the code that interacts with external systems, such as databases, APIs, and message queues. These are the implementation details that make the system work. The infrastructure layer can consist of several modules, such as:

  • Web: This module consists of the API implementation that transforms HTTP requests into responses based on the domain business logic.
  • Event: This module consists of both consumers and publishers of events.
  • Database: This module implements repositories and persists the data to an actual database.

By isolating the functionality of each module, changes made to one module won’t affect the functionality of the other modules. For example, changes to the web interface won’t affect the business logic of the system. This helps improve the maintainability of the system, making it easier to exchange specific implementations for others.

⚖️ Benefits & trade-offs

There are several benefits to using Ports & Adaptors architecture in software development:

  • Flexibility: By separating the domain code from the infrastructure code, you can more easily switch out different technologies or components without affecting the overall architecture. For example, you can replace a database with a message queue or switch from a REST API to a GraphQL API without having to modify the core domain logic.

  • Testability: Ports & Adaptors architecture enables you to write more comprehensive and targeted tests, as you can isolate the domain logic from the infrastructure. This makes it easier to test the system at different levels of abstraction, from unit tests for the domain logic to integration tests for the infrastructure components.

  • Maintainability: Separating the domain code from the infrastructure code makes it easier to maintain and update the system over time. Changes to the infrastructure code, such as upgrading a library or adding a new feature, will have minimal impact on the core domain logic. This makes it easier to evolve the system as business needs change.

But with all architectural choices there are also trade-offs:

  • Complexity: One of the main trade-offs is that implementing the architecture can increase the complexity of the codebase. This is because the architecture involves creating separate layers for input/output operations and business logic, which can require additional code to translate between the two layers. This can make the codebase more difficult to understand and maintain, especially for developers who are new to the codebase.

  • Upfront cost: Ports and Adapters architecture can lead to more development time upfront. This is because designing the architecture requires careful consideration of the various components and how they will interact with each other. This can take more time than simply writing code in a more ad-hoc manner.

  • Knowledge: Finally, implementing the Ports and Adapters architecture can require additional knowledge and training for developers who are not familiar with the architecture. This can increase the learning curve for new developers and may require additional training resources to ensure that everyone is on the same page.

Overall, Ports & Adaptors architecture is a powerful tool for creating maintainable, scalable, and flexible systems. While it may require some upfront design and planning, the benefits can be significant in the long run, especially for larger systems with complex business logic and multiple external interfaces.

⌨️ “Soft”ware

The term “software” is derived from the word “soft” which implies its malleability. Unlike hardware, which is rigid and inflexible, software can be modified, updated, and improved to meet changing requirements. In fact, if an application is not easily changeable, it can hardly be called software at all.

Firmware, on the other hand, is a type of software that is designed to run on specific hardware, such as a microcontroller or a router. It is used to provide low-level control and management of hardware components, such as booting up the device or managing input/output operations.

While programming skills are required to write software, creating quality software that is maintainable, scalable, and robust requires a different level of expertise.

Everyone can learn to be a programmer, but creating software is a totally different ball game that only a fraction will truly understand.

Me again - this blog

📐 Proof of Concept

Implementing Ports & Adaptors architecture in a simple microservice is a great way to test its effectiveness. However, it is important to keep in mind that the advantages may not be immediately apparent in a small system.

To truly evaluate the benefits of Ports & Adaptors architecture, it is important to implement it in larger systems with complex business logic and multiple external interfaces. This will allow you to see how the architecture helps to simplify the codebase and make it more maintainable.

💡 Conclusion

As part of your mission to write better software, you can start by exploring the subject of Clean Architecture. By reading Uncle Bob’s book and applying the practical advice provided, you can gain a deeper understanding of how to create a maintainable, scalable, and flexible system.

Architecture plays a vital role in reducing the complexity of the system, making it easier to develop, understand, and maintain. With good architecture, you can minimize the lifetime cost of the system and maximize programmer productivity.

Ports & Adaptors architecture is a powerful tool for achieving these goals. By separating the domain code from the infrastructure code and connecting them via ports, you can create a system that is easy to understand, easy to develop, and easy to maintain.

If you’re interested in learning more about Ports & Adaptors architecture, there are many resources available online. Start by reading “The Missing Chapter” in the Clean Architecture book and exploring the various articles and blog posts that have been written about it. Remember, good architecture is an exercise in trade-offs, balancing competing goals and constraints to achieve the desired outcomes.