Domain Driven Design and package organization

I am lucky enough to be working in a team that values DDD. In my time in sky I have worked in at least one big long-lived application (8+ years) and a couple of greenfield applications. The long-lived one was fairly well structured around it’s domain. Even though the domain was big and complex, it was usually reasonably easy to navigate the code and change as long as you knew enough about the Ubiquitous Language and the business.

For the greenfield apps, we wanted to apply our interpretation of DDD from scratch. One of the challenges we found in doing so was to find the right package structure to organize our source code. In this post I will explain the evolution of this structure.

Long-lived application

The previous long-lived application had a package structure like following one:

src/main/java
├── CommonClass.java
├── aDomain
│   ├── aDomainValueType.java
│   ├── aDomainEntity.java
│   ├── aDomainUseCase.java
│   ├── aDomainServlet
│   └── aDomainDatabaseAdapter.java
├── anotherDomain
│   ├── anotherDomainAudit.java
│   ├── anotherDomainValueType.java
│   ├── anotherDomainEntity.java
│   ├── anotherDomainConfiguration.java
│   ├── anotherDomainTemplate.vm
│   ├── anotherDomainRequestUnmarshaller.java
│   ├── anotherDomainResponseMarshaller.java
│   └── anotherDomainResponseTemplate.vm
└── CommonException.java

We really liked the clarity of having all the classes and files related to one domain under the same folder. That way, when you are on a domain or subdomain you can always find all the classes at hand. It also helps to understand the domain if you can easily see a list of all the classes involved. However, there was a downside. Since the infrastructure classes were in the same package and the core domain ones, it was hard to make sure that the dependencies pointed in the right direction.  We were trying to implement something like clean architecture or hexagonal architecture. We wanted to make sure that the pure domain logic had no dependency at all on infrastructure classes. We found that to do that we needed to segregate make the domain/infrastructure segregation at the package level.

Our DDD package structure (1)

In the canonical DDD book Eric Evans mentions 4 layers in applications: User Interface, Application, Domain and Infrastructure. One of my colleagues wrote a post about how to decide where to place a class. We decided that Infrastructure was a crosscutting concern that should serve the other three parts of the system. We decided to implement the dependency structure shown in “First DDD aproach”.

VP112i8m44NtSufSe3TmKI48FO076DAf3gP9c4nm8TwzebPIYDt-UGyUqsT5qJ9x06NrP4uiMOsrrc2IYEuA00dT3Izapfba24eoeIFpUBOFGvW4iqfnMkID_JWRP-HGcvzbHpccvDcXSjnurToGjw67ReptqErMmZTjPLjTKBUiuDyGW9x2-Fhi0W00.png

The package structure was something like this:

src/main/java
├── UserInterface
│   └── ... (java files)
├── Application
│   ├── OneUseCase.java
│   ├── AnotherUseCase.java
│   └── YetAnotherUseCase.java
├── Domain
│   ├── SubDomain1
│   │   └── ... (java files)
│   ├── SubDomain2
│   │   └── ... (java files)
│   ├── SubDomain3
│   │   └── ... (java files)
│   └── SubDomain3
│       └── ... (java files)
└── Infrastructure
    ├── domain
    │   └── SubDomain1
    ├── application
    │   └── SubDomain2
    └── userinterface
        └── SubDomain3
  • Disadvantage: Verbose, deeply nested and non-intuitive infrastructure packaging.
  • Advantage: Static analysis makes it easy to enforce expected dependencies.
  • Advantage: Application layer as an entry point to functionality.

The nesting here started being considerable. We haven’t shown the java files for the infrastructure but they would be in the next nesting level. Every domain, application and user interface package was mirrored inside infrastructure, and sometimes it was a little bit of an overload.

This mirroring of packages was also sometimes counter intuitive. For example, all the database adapters were in a “events” sub package inside infrastructure, just because the domain layer stored domain events in a package with name. Nevertheless, when we were looking for database adapters inside the infrastructure package our expectation was usually to look for something called “database”.

It was also hard to place crosscutting concerns inside the infrastructure. For example, where to place the “logging” package if both the domain and the application layers need to log things? Under “infrastructure/domain/logging” or “infrastructure/application/logging”? It would seem much more natural to put all the logging infrastructure classes under “infrastructure/logging”.

One of my fellow colleagues wrote an utility for enforcing dependencies between packages. A test written with this tool looks as follows:

private static final String DOMAIN = "domain";
private static final String WEB = "web";
private static final String USE_CASES = "usecases";

@Test
public void webInterfaceShouldDependOnItselfAndApplicationAndDomainOnly() 
                                  throws Exception {
 List<String> violations = 
               domainEnforcer.checkThatPackageOnlyTalksToItself(WEB)
               .apartFrom(USE_CASES, DOMAIN, FINDBUGS, VISIBLE_FOR_TESTING);

 assertThat(violations)
               .describedAs("The web interface should only depend on itself and the application and the domain")
               .isEmpty();
}

These little test cases helped us gaining confidence on keeping certain dependencies between the packages.

One of the nicest things of this package structure and naming convention is that now it is very easy to find an entry point to any functionality. You just have to search on your IDE “*UseCase” and select the one related with the functionality you are going to work with.  Then you only have to start digging in the code to find whatever you want to.

Our DDD package structure (2)

We decided to evolve our infrastructure package to make it simpler and more intuitive. To do that we conceptually unified the infrastructure under one cross-functional unit supporting all the other layers.

TOz12W8n34NtEKKkC3TmCK8tinOF4DAC5ZjfILDSY7TNH6H6TFl-vp_-s9pC-v81F7aMF0WNZHX2GAfMYCy0K8alT18yDh59NMmc5hpTFq4e2oLTatsjEJ5vAXiywMpKt3fxjzS4R4TtGonN7RwBy3RyZc5j-rE1KJG-Zpu0.png

This translated into a flattened directories structure:

src/main/java
├── UserInterface
│   └── ... (java files)
├── Application
│   ├── OneUseCase.java
│   ├── AnotherUseCase.java
│   └── YetAnotherUseCase.java
├── Domain
│   ├── SubDomain1
│   │   └── ... (java files)
│   ├── SubDomain2
│   │   └── ... (java files)
│   ├── SubDomain3
│   │   └── ... (java files)
│   └── SubDomain3
│       └── ... (java files)
└── Infrastructure
    ├── database
    │   └── ... (java files)
    ├── logging
    │   └── ... (java files)
    └── httpclient
        └── ... (java files)

We retained the advantages of the previous directories structure while solving the infrastructure problem.

Header image source: https://pixabay.com/en/module-share-items-organization-68955/
Header image license: https://pixabay.com/en/service/terms/#usage

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s