Decoupling from infrastructure

Updated on @September 10, 2023

Separating infrastructure concerns from the core application logic leads to a domain model that can be developed by applying Domain-Driven Design (DDD).

It also leads to application code that is very easy to test and to develop applying Test-Driven Development (TDD). These tests are more stable and run faster than the average framework-inspired functional tests.

Developing your application in a domain-driven and test-driven way is already a great attribute of any software system. But separating infrastructure from domain by applying these design patterns gives us more advantages. We can start using a standard set of layers: Domain, Application, and Infrastructure. And on top of that, we can easily apply the Ports and Adapters Pattern (Hexagonal Architecture).

This is an excellent way of standardizing our high-level architecture, making it easier for everybody to understand the code, take care of it, and continue developing it.

Decoupling from infrastructure is a safe bet if the application is supposed to live longer than two years. Upgrading to the next version of your framework, migrating to a different storage system, or switching to another payment provider won’t cost as much as it would if core and infrastructure code were mixed. Dependencies on external systems will always be isolated; if a change has to be made, you’ll know immediately where to make it.

But… What is core code? We’ll define core code by introducing two rules:

Rule 1: No dependencies on external systems

Core code doesn’t directly depend on external systems or code written for interacting with a specific type of external system.

An external system lives outside the application, like a database, some remote web service, the file system, the system’s clock, etc.

In general, abstraction is the go-to solution to eliminate dependencies on external systems. Creating a complete abstraction for services that rely on external systems consists of two steps:

  1. Introduce an interface.
  2. Communicate purpose instead of implementation details.

Rule 2: No specific context is needed

Core code doesn’t need a specific environment to run in or have dependencies designed to run in a particular context only.

Core code doesn’t rely on global state, static service locators, command line context, etc.

In summary, core code can be executed in any context without any special setup or external systems that need to be available. Infrastructure code needs external systems, a special setup, or is designed to only run in a specific context.

Connecting the core to external systems and users through infrastructure
Connecting the core to external systems and users through infrastructure

“Is all code in the vendor directory infrastructure code?” In /vendor, we will find some dependencies, like the web framework or the ORM, that usually need external systems like the database or the webserver to be available. So, these dependencies should be considered infrastructure code. However, other dependencies could be considered core code, even though it’s not written for your application specifically.