While Deptrac is commonly used to enforce horizontal boundaries within PHP projects, it can also help define and maintain vertical boundaries (such as bounded contexts in DDD speak, or quanta) in PHP monoliths.
This capability is especially valuable when implementing the Ports and Adapters architecture, ensuring clear separation of concerns and robust modularity in your PHP applications.
This three-part series will cover:
- Part 1: Setting up a basic Deptrac configuration for a PHP monolith (this post)
- Part 2: Refactoring spaghetti code into bounded contexts using Ports and Adapters
- Part 3: Enforcing architectural boundaries in your CI pipeline
Part 1: A basic deptrac configuration for a PHP monolith
A typical big ball of mud monolith still has some kind of structure, e.g. “packages” which are usually namespaced classes / directories containing similar classes, but referencing classes from other “packages” all over the place.
Let’s assume the following directory structure:
1 | PackageA/ |
And the following files/classes:
src/PackageA/SomeAClass.php
1 |
|
src/Core/Logger.php
1 |
|
src/PackageB/SomeBClass.php
1 |
|
Here’s a simple UML diagram to visualize the dependencies between these classes:
In this example we want to make sure that PackageA
can only access Core
and PackageB
, but not PackageC
. We can use deptrac to enforce this rule.
Enforcing vertical boundaries with deptrac
First, we define the basic structure in deptrac.yaml
:
1 | deptrac: |
So each package becomes a ‘layer’ in deptrac.
This is the key insight: while deptrac is typically used to define horizontal boundaries, we can also use it to define vertical boundaries by treating each package as a layer.
If we run deptrac, we already see two violations:
1 | -------------------------- ------------------------------------------------------------------------------------------------------------------ |
deptrac has detected that PackageA
is depending on PackageB
and Core
, which is currently not allowed, so let’s adapt the config:
1 | deptrac: |
Now, if we run deptrac again, we see that the violations are gone:
1 | -------------------- ----- |
Congratulations, you have successfully set up a basic deptrac configuration to enforce vertical architectural boundaries in your PHP monolith!
Usually, that’s only the first step, since allowing to call all classes in Core
and PackageB
from PackageA
is not a good idea, as it will lead to a lot of dependencies between the packages.
It’s better to define a clear API of what PackageA exposes to the outside world. In Ports & Adapters, this is usually done by defining a ‘driven’ port interface. That’s what we will cover in the next part of this series.
Like what you read?
You can hire me or make a donation via PayPal!