Rob Cook


Home | Donate

Software architecture: structuring the layers


2021-09-27

A layered architecture helps organise a solution. But if we are to escape the dreaded big ball of mud, we need to introduce some more structure to it. Below are some common structures from software architecture.

Entities

Anything in your domain model layer that has an identity of its own is expressed as an entity. In object oriented systems an entity is represented by a class. Entities are the principle things your application is concerned with. They will typically be persisted to a data store, such as a database, and serialised to some other format for transmission outside the application (think json or xml).

Repositories

A repository is an abstraction over a data store, typically a database. The goal is to limit data access to just one location in the code. The interface for a repository can live in the domain model layer, but the implementation is something that should reside in the infrastructure layer. At its simplest, the repository provides methods to retrieve one or many entities from your domain model, and some way of persisting them back.

The services or handlers in your application layer use the repositories to load entites into memory, so they can perform some business logic.

Factories

Entities can be complex things to construct. When this is the case, it makes sense to delegate this process to a dedicated factory class. Factory interfaces and implementation are defined in the domain model layer.

Services

Services can exist in several layers. Their role depends on the layer they are in

Application layer

A service is modelled as a class. Services can be used to group use cases into coherent groups. For example a document service would expose methods that map to use cases related to document entities. The interface and implementation of the service both live in this layer. They can depend on interfaces from the domain model, such as repositories.

Domain model layer

Services in the domain model arise when a particular behaviour doesn't fit with any of the entities present. Such behaviours can be modelled as services. In this case both the interface and implementation reside in the domain model layer.

Infrastructure layer

Not everything that resides in the infrastructure layer is a repository. Services can also reside here. The interface is in the domain model layer, and only the implementation lives in the infrastructure layer. Services could represent an encapsulation of an external api that the application is a client of.

Command and query handlers

An alternative to using services in the application layer is to model each use case as a command and handler. Each command encapsulates a particular use case request (add user, get document etc.), and there is a handler for each command that executes the logic needed to fulfil the request.

This approach can be taken further by dividing your use cases into commands (write based actions) and queries (read based actions). This allows the handlers to be optimised for either executing logic in the domain model, or simply querying for data. Different repositories could be used for each, or indeed different models.

There's more

This is just a sampling of the most common pieces of architecture that crop up in application development. There are many more out there. The best advice is to read widely to survey the options, then deeply on the ones that you wish to implement.

end