“Let the domain drive” architectural pattern

One of the most helpful concept I learned in my career is the Hexagonal Architecture.
I started using it in green-field projects and I was very happy with it.
After years, I changed my job and went in a so called “agile” company.
Some projects were in a very bad shape… but also new projects had something weird.
And the funny thing was that people working on those new projects were telling me that they were using the Hexagonal Architecture.
WHAT?
They were right: the Hexagonal Architecture was there… but I didn’t recognize it. And the reason was that it didn’t match my style!

Basically, what I found was that:

  1. sometimes the domain objects were not “mentioned” on ports: there were other objects… a kind of anti-corruption-layer (ACL) in between the domain and the ports
  2. the adapters had new objects equal to the domain ones, but not totally… they had some differences here and there… and there were mappers between the domain objects and those duplicate objects
  3. the domain objects were highly protected by “everything”. They were living in a specific module. The adapters were in another module with their objects very similar to the domain ones. If you have to add something to domain objects you were pretty sure you’ll have N other changes to apply (where N is the number of ports in your software)

In the future, I’ll share some techniques we used to refactor those applications.
But in this post, I want to share an improvement to the Hexagonal Architecture that add an additional principle.
I think this architectural pattern is already known by expert OO programmers… probably it is obvious for them, but it has no name, it is not mentioned, and lots of colleagues (even experts not only novice or advanced beginners…) create architectures with the issues mentioned above, so… I decided the name 😀

It’s called “Let the domain drive” architectural pattern.
The added principle is: “if you have to share the state of an object, you strive to share it without polluting your application with duplicated objects”.
Does this mean that your domain objects are in trouble?
No, when you realize that they are in trouble because of “external influences” that could make them “dirty”, you can act duplicating objects… but you have to be sure you need it (YAGNI).

How to handle the known issues mentioned

Now I’ll look at the findings mentioned above and I’ll try to explain how to handle those issues with this architecture.

Issue 1: domain objects not used in ports

This is simple.
It is an error even if you are using the Hexagonal Architecture.
So, please fix this.

It seems someone around the world think that you can have DTOs in the ports.
Just as an example, here you can find an article by Matteo Vaccari on the The Birthday Greetings kata. Do you think it’d be acceptable having the EmployeeRepository returning a List<EmployeeDTO>? Why not the List<Employee>? Employee is the domain object here. Why do you need to use that DTO? Do you have a reason? if the reason starts with “because if in the future…” STOP: YAGNI

Issue 2: adapters with objects very similar to the domain ones

In the “Let the domain drive”, you strive for having only and only the domain objects. Objects that are similar to the domain ones should be used only if you are already sure that the state of your domain objects cannot be “shared” externally.
If YAGNI, you stick with just your domain object.

Issue 3: touching 1 object requires N other objects to change (where N = ports)

In the “Let the domain drive”, you remind yourself being a software engineer.
With this in mind, when you realize that there is a repetitive task/action… a common pattern… something that could become a “liability” in the future, you start applying different techniques to handle automatically those things.

For example:

  • Storing objects automatically using reflection
  • Creating new “objects”/”map”/”things to share with external systems” automatically using reflection or “describing how” in the domain object using syntactic metadata (e.g. Java annotations)
  • Generating code

Everything is allowed if you are not polluting the domain objects with “technical stuff” at the same abstraction level of “domain stuff”.

Just to give you an example found for real (I changed just names). If you have a domain event such as:

public final class ProductPurchasedEvent extends EventObject {
private final Product product;
private final Price price;
[...]

}

and you have to store the event in JSON, you could create new objects ProductPurchasedEventJson, ProductJson, PriceJson and make the mapping manually. This approach is not consistent with Simple Design and by the way it costs a lot in maintenance!
Repeat this approach every time you have this kind of problems and you have just confirmed that you are not a programmer, but a creator of liabilities in your company.
Your company should sue you… just joking (or maybe not).

In the “Let the domain drive” architecture, at the beginning you’ll try to “serialize” the entire object in JSON. Then, if you realize that you can share only parts of the state of your domain object you could add Java annotations to prevent sharing everything or maybe you already have parts of the object that should have been marked as transient

Remember that you are an engineer.
And I am pretty sure you’ll find a solution for your specific case.

What does “Drive” word stands for?

We talked mainly about technical stuff, but “Let the domain drive” architectural pattern is a matter of creating a product with a simple design.
So the real job starts when you have to evolve an object that is in trouble because someone is going to mix data with different meaning in the same place (such as technical data with domain data).

I am going to give you an example. Imagine that you have a domain object representing a product purchase. You mapped automatically that product purchase from a payload of a REST call. Now they need to put a trace id of the HTTP request. If they put that trace id in the payload, your domain object will be in trouble.
So:
you suggest to use a different place to put that trace id, such as (for example) the HTTP header.

This is how you use that “Drive” word.
Your architectural decisions are handled in order to keep the design simple without polluting the application with useless objects and without mixing data.
This is a very simple example, but it is because the entire idea is simple.

What if someone forces you to put that trace id in that payload?

Then, it is time to protect your domain object, but I’d share with the people forcing you that your project will start to cost a little bit more than the solution you suggested. And I’m not joking! It will cost more for sure!

PROS of “Let the domain drive” architectural pattern

  • You’ll have just one object to represent something with just one name (more symmetry and consistent with the 4th element of simple design)
  • You’ll be fast in embrace changes (reduced costs of changes)
  • You’ll understand the code better and faster (clean code)
  • You can apply it even on legacy code, because you have to accept different approaches for each domain object…

CONS of “Let the domain drive” architecture

  • You have to protect your domain objects. If you have junior programmers (or programmers that are not really “clean”), they won’t realize when it is time to break the usage of this style because it is no more suitable
  • Watch for over-engineering. As an example: I have seen people starting with a simple system to store objects automatically on DBs ending with a kind of home made Hibernate or a home made Spring Jdbc. You should remind yourself that the solution should be cost effective
  • You could have different approaches for your objects. Maybe an object can be shared automatically and another one requires a manual mapping. I met people that rather prefer to use the same approach everywhere instead of reducing the duplicated objects.
    If this kind of situations, you’ll have difficulties with this architectural pattern.
  • When a programmer uses this architectural pattern, he’ll have difficulties in going back to the previous approach. His life as a programmer will be ruined 😀

Remember: the aim of this architectural pattern is not to have “a standard way to approach *any* design or every part of your design”, but to stay as much as you can with your domain objects in every part of your application, “disconnecting from them” only when you really need.

Few words on the 4th element of Simple Design

The 4 elements of Simple Design

Suggestions to young men

Few days ago I made an interview.
The interviewer (Tommaso Torti) asked me if I have suggestions to give to young men starting a new career in software development.
Just as a recap, I mentioned:

  • find a company with high skilled software developers
  • changing job frequently: for example every 2 years
  • after few experiences, remain a little bit longer (5 years?) to find how good your design decisions have been in the long term
  • read classics: not only about software design… I mean also The Mythical Man-Month by Fred Brooks, Peopleware by Tom DeMarco, etc…

A missing point

But I forgot to mention one of the most important point.
In my opinion, to become a real expert in Software Development (not only OOP), you have to spend a lot of time on the 4th element of Simple Design: minimal methods, classes and modules (also known as “fewest elements”).

I know it sounds silly: “ehi man, I am already writing the minimal methods, classes and modules!”
Maybe! But, maybe not!
How do I know?
2 reasons:

  1. I have seen code written by lots of people. Expert people. Very often, I could have written the same code with half of the objects/methods/modules maintaining (or even increasing) the readability of the entire code base
  2. I found people able to write the same code I wrote, with a reduced number of objects/methods/etc…

So yes, it is a virtuous “mechanism” that once established creates an “obsessive” research on “how to write less, keeping high readability”.

What happens in reality is that, Object Oriented Programmers are focused mainly on SOLID principles, on the first 3 elements of Simple Design and don’t give any attention to reduce the things they write.
This is the reason I wanted to say few words on the 4th element.

A story

I have a story to share with you.
In my company, we had a coding exercise as an entry test for every applicant: Sales Taxes (you can find my solution at that link).
As an interviewer, I have seen lots of solutions and I can tell you that the majority of applicants created a solution with more than 30 objects. Some of them, reached more than 50 objects. I remember one guy proposing a solution with more than 80 objects.
Few people used 10 objects or less.
I haven’t seen all solutions, so I am talking just about what I have seen.

Another aspect: some developers wrote a solution with lots of objects that could adhere perfectly to SOLID principles and to the first 3 elements of Simple Design. Other developers wrote with fewer elements, but with procedural code.
I can tell you this: I accepted solutions wrote by the latter more often than by the former.
The reason is that, it is very difficult to train yourself on writing less. I think it is almost impossible to train on production software without a mentor helping you, unless you are naturally “obsessed” on this topic.

It is all about “simplicity”

There is another reason I think the 4th element is important.
If you are an object oriented programmer, you are naturally inclined to organize “things” (objects, methods, etc…).
But, as mentioned in The Laws of Simplicity by John Maeda, there are a lot of other ways to create simplicity and the first one is called “REDUCE”.

How to improve

Assuming that you want to train yourself anyway without a mentor, I can share some “exercises” you can do in your daily job or in some pet project you have:

  • try to start with just one module: you can add more modules later. If you really need them (and probably they will be created with a different idea behind them)
  • try not to duplicate your domain objects due to your adapters.
    For example when you have a domain object and then you have another DTO for the REST adapter, one for the persistence, another one to call your supplier, etc…
    If you really need this solution, try to avoid at least a hierarchy of mappers to create those objects from domain ones and vice versa: put factory methods in those objects instead
    Anyway, did you try with just data mappers and Maps? Sometimes, the idea that you need another object lies only in your mind…
    Did you try using reflection with some project convention?
  • try to count the objects (or methods) you are creating for a new feature.
    Put a label near each one: NEEDED, MAYBE, USELESS
    – USELESS: you should delete them immediately
    – MAYBE: “maybe” you can do something to make them USELESS
    – NEEDED: maybe you can think again… once more… are you sure? If you really think they are NEEDED, leave them alone
  • avoid “extract method” to have then just a private method containing one call to a collaborator. It does not increase readability at all! Change the name of your collaborator instead (or of the method name called)
  • pay attention to Parameter Objects. The idea that you need a Parameter Object when you have more than n parameters is the most stupid thing I have ever read (if you think this call discount(Product, Price, MarketStrategy, Report) is less readable than discount(DiscountRequest) you’ll be in trouble reading my blog). Besides, Parameter Objects often hide domain objects in the primitives used (I wrote a story about this: check Once upon a time… in Objectsland).

If you want to share another training exercise, please write a comment below.

I hope you’ll find interesting to spend some time on this aspect of software design.