We use Domain Driven Design to try to organise our code into separate related groups which are distinct and uncoupled from the Laravel framework where possible.

We have a Domains namespace in the root of our project under src/Domains which is autoloaded in by composer. This enables us to abstract business logic away from the main application, and should be couples with interfaces that live under src/Infrastructure and the Infrastructure namespace.

Anything to do with the Application or Framework itself should live under the App namespace, as there are ways we can manage multiple apps in one laravel installation. Things such as middleware, policies and models all belong to the app itself as they are tightly bound to the framework. This is a practice commonly knows as clean architecture, where we abstract from the framework as much as possible and where it makes sense.

Soma example domains are:

Fetching data

We use Queries to allow us to easily write unit tests that do not interact with the database, each Query should have a corresponding Interface so that test doubles and mocks can be created. By moving all of the read database logic into Queries it allows us to have a consistent query experience no matter if the integration is coming from web, API or CLI.

Writing data

We use Commands to allow us to easily write unit tests that do not interact with the database, each COmmand should have a corresponding interface so that test doubles and mocks can be created. By moving all of the write database logic into Commands it allows us to have a consistent write experience for the database no matter if the integration is coming from web, API or CLI.

Data Objects

We use DataObjects to pass user land data from controllers to Commands and Queries. This enables us to keep context in each class that data is passed to. A great side effect of this is that we can also ensure better type safety in our code, as each object property will be type hinted.