Bounded Context Patterns

After a decade of coding, I tend to believe that being able to discover and implement correctly bounded context is one of the main values I can bring to a company in my daily job. As a consultant I have the chance to do it in different gigs since a few years now, and I start to see repetitive patterns in the way companies are structured. I usually use a strategic Domain Driven Design (DDD) approach to understand and classify this structure, resulting in some domains, subdomains and bounded contexts. 
Because of this repetition, I think bounded contexts can be classified in patterns, and that these patterns can help to know the importance of the bounded context and how to build it in the most efficient way for the business. 
 
I believe these patterns can also be seen with a hexagonal approach. Indeed, like in the hexagonal architecture, we have core stuff and surrounding stuff with adapters and/or anti-corruption layer. It’s the same principle, just at a different scale. 

Here is a list of the most recurring patterns I have discovered over time. 

The Data loader Context 

It is quite common for a business to be dependent on data from an external source. This is when we require to fetch data from somewhere else, usually at a recurring period.
When I identify this pattern, I try to isolate this behavior in a context, ideally one project per data source. All these projects are Data Loaders for our domain. These contexts are often quite technical and requires a strategy to handle the external (and usually unreliable) data source. 

This image has an empty alt attribute; its file name is image-4.png

The Referential Context  

This a very tricky and still very common one. It is the famous “Tools” or “Common” you’ll find in any solution, but at a different scale. It’s usually a referential of something, that you need to share with the rest of the company, or even with other companies. You know that you should avoid it, but still you really need the whole business to share this single source of truth.
Of course, you want to isolate this behavior in a single context, and then you should not consider it as a “safe” context, because it will have many dependencies. If possible, make this context independent of its consumers, at least the dependencies will go only in one direction.
It’s a very challenging context, because of the dependencies. You need to talk a lot, with lots of team. They are also usually technical, because to make them more Domain Driven you’ll need to know why your data are used. And this is not often compatible with the will of staying independent of the consumers.


The Anti Corruption Context 

Because external data fetching is common, we need to convert them from something not trusted to something validated for our business. It is well known in the DDD community and usually implemented through what is called an Anti Corruption Layer
But I believe that it often makes sense to actually consider this layer as a context by itself, because the logic behind data conversion of an external source can be pretty complicated. Even if the business will tell you that “this is just a JSON you know”… 
This context is at the border between the external/technical world and the internal/domain world. It maps the technical validated data from the Data Loader to something usable by the domain. It is an adapter in the hexagonal architecture metaphor. 

The Reporting Context 

Here comes another almost unavoidable one: the reporting context. It “just” reports data from the core domain and we should not have a high level of domain complexity for that…But still, in my experience they are important because they are used to drive the company and some critical business decisions might depend on it.
And they can also be complex because it is not uncommon to handle automatic integration of this report with external tools, or different access type to the data depending on the user role. 
As explained by Scott Wlaschin in Domain Modeling Made Functional, this is where you’ll put the OLAP responsibility of your system. Whereas the business core is more like an OLTP system. It explains for me why you want to isolate both behaviors.
It is a port to the external world in the hexagonal architecture metaphor. 
 

The Business Core Context 

And finally, the holy grail, the one you look for because it creates value for your business, the key technical asset for your company: the business core context. 
All the projects I have worked with have a business core context. The thing is that most of the time, we put too much things inside (like the data loading or the anti-corruption or the reporting…)  
This is usually done for the sake of Don’t Repeat Yourself (DRY): we have the JSON from this external source, why should we transform it before use it?  This is the usual doom of DRY leading to technical issue leaking into your business, and that’s why you want to avoid it. 
This context should be the more Domain Driven of your whole solution, meaning for example that you want to avoid primitive types, dependencies to external stuff, or not handled exceptions. You shouldn’t do technical validation either, because other contexts can take care of that for you.
In the hexagonal metaphor, it is of course the core domain layer of the architecture. 

Map with core, generic and support contexts

In the DDD community, based on the already mythic blue book by Eric Evans, we usually classify contexts in three categories: core, support or generic. Of course, these categories will depend on your domain, but I think we can most of the time map them with the patterns define above. 
For instance, The Data Loader and the Reporting context can be generic contexts, but again beware of the hiding complexity in it (a third part tool might do the job, at least to start).
The Anti Corruption contexts are usually in the support category (useful but not a competitive advantage, still cannot be done by a third part tool, because it depends on your core domain).
The Referential Context might be core or support.
The Business Core Context is obviously in the core category. 

What next ?

Here are the main patterns that make sense for me so far. This is non exhaustive, for example another pattern I omit is the User Interface (UI) context. Because in which context your UI belongs to isn’t an easy topic in DDD, and one answer to this complex question can be a dedicated context to handle it. But I still don’t really know if it is a useful or a harmful pattern… I tend to prefer context like reporting with a clear business responsibility and usually many UIs.

Anyway, what about your experience? Maybe you have identified some patterns that are missing here? Maybe you know about some blog post or books exploring this part of strategic DDD patterns?
I’ll be glad if you accept to share it with me, and maybe we could build together a more exhaustive (and hopefully useful) list of bounded context patterns? 
 
 

 

Event Storming and Event Modeling from the trenches

In 2014 I had the chance to join a workshop on Event Storming by Alberto Brandolini at BuildStuff. After that I started to practice it intensively at work and was quickly convinced that it was a very interesting asset to do my job. Indeed, as a consultant I meet many teams, and need to understand in a few hours as much context as possible. It is surprising how, with the right tool, you can even learn things about the job that business experts themselves were missing because they lack time to think about it. 
In 2019, I added another string to my bow thanks to a workshop on Event Modeling by Adam Dymitruk and Greg Young in Lyon. As already explained, it covers some lacking for me in the Event Storming approach, and thus I find it to be a very complementary method to Event Storming. The synergy of both tools can be huge.
I would like to share with you how they help me to improve my craft, plus give you some tricks from the trenches. 

Event Storming from the trenches 

A quick lesson I learned from early Event Storming is that all Event Storming are different, and this is great. Of course, they are different in terms of content, but what I mean is that they can also be really different in form. Because they will always adapt to your context!
For instance, it is sometimes enough to put only the events (no commands, aggregates or even contexts), because it will trigger the necessary discussion, and you won’t need to go further.   

An important point is to agree before the Event Storming on why you are doing it. You want to cover a new feature? You want to explain the business to someone else? You want to clarify a point with your team? Depending on the end goal, the form should be adapted to suit your needs. 

By experience, the law of two feet works very well for an Event Storming workshop. You don’t want people to be disengaged, and you don’t need to have all the team all the time. Some might take a break while others are digging a specific point, and this is great. Collective intelligence at work! 

In terms of timing, I believe that half a day is basically the most that you can do if people are really invested. It can be exhausting to carry such a workshop for too long. Keep an eye on how people feel and don’t hesitate to call for a break if you feel like the mob need it. 
 
Something I rarely see when people talk about the Event Storming session they performed is drawing a link between events and commands between contexts, when an event in a context triggers a command in another one. It gives you an instant view of Bounded Contexts relationship, hence some hints to know if your contexts are well defined. 

Finally, after many attempts, I must say that for me, Event Storming is a killer tool to have a big picture view of a situation. I’ve seen it a bit less valuable when I needed to dig in the implementation on a specific part (in the solution space if you prefer). This is where Event Modeling came to the rescue! 

Event Modeling from the trenches 

One of the main feedback I had from my many Event Storming workshops is that losing the temporal link between the events was a shame, because it has a great value to describe business workflow. For me this is one of the main benefits of Event Modeling. 
It makes it very good to explore concrete implementation, to represent business workflow and to link it with the UI.  
 
And like Event Storming, it gives a very good domain view, especially when combine with Event Sourcing and CQRS. It is powerful to describe the solution workflow, as you imagine and then implement it. 
With time, as the model evolve and grows in maturity, it’s something really valuable to support technical and/or business discussion. 
As Adam would say, this is sort of a blueprint of the system that a business or a technical profile can understand easily. 

I find useful to take screenshots of such models to add into User Story as documentation, or even in Pull Request in order to describe which part of the system we updated (showing a picture before the Pull Request and after the Pull Request for instance).  

Another trick to reach an interesting model is to describe each workflow separately, even if we feel that some of them will be handled by the same piece of code. Then when all scenarios are well described as a unit, you can try to merge them into a single one that could theoretically handle all of them. But even there it’s interesting to keep a trace of all the single scenario that leads you to this design. 

Hope it helps! 

I hope these few tricks will help you to perform better Event Storming and Modeling sessions. I could add that whatever the workshop you do, capturing the end result in a Miro board (or equivalent tool) is usually a good idea for asynchronous communication and future evolution of the model.
But if you should keep only one thing from this article, it would be don’t worry too much about the form, keep whatever works well as an event driven description for your team, and don’t mind how you call it.  
 
Because domain events are the powerful idea here, Event Storming or Modeling are “just” a way to exploit it 🙂 

 

When business does indeed sucks

In a recent article I explained why I think we should all be Domain Driven.
I get some interesting feedbacks on the “business sucks” syndrome.

Indeed in this previous article my point was to make technical teams aware of the necessity for business to change in order to constantly fit its market as much as possible. But sometimes business does indeed suck.
Let’s take a few examples I’ve met in 10 years as a software developer.

The never-ending prototype

One of the most common business error I’ve met is the fast hacked prototype that goes into production, and then evolve in a maintenance nightmare because you know… It works, why should we rewrite it?
To be fair, this is one of the hardest things to do when you start a new business. The first step is to look for a market fit. This can take years, and you must be very fast to test your hypotheses. You are sending many prototypes in production, and most of them will only live for a few months. At this step this is perfectly fine.
Of course the problem arises when, finally, you find your market fit. The growth is here, more and more customers are using the prototype. This is when courageous entrepreneurs should throw all the technical stuff, and write it from scratch with more money and knowledge. More money because growth means that we can get money, more knowledge because many technical limitation from the prototype will be clear, and a more robust product can be built from this knowledge. As Francesco Cesarini would say: “A programmer will fully understand a problem only when he fixed it at least once”.
What happens instead is that the money is used to growth even faster, the prototype has to scale even if it’s not done for it, and the technical team has to deal with many domain and technical problems that should have been avoided.
Here starts the famous “we don’t have time for tests, we have to deliver”.

Head in the sand policy

This error concerns mainly big corporation. But I’m sure you already were as surprise as me to see how fast politic can become important even in small companies.
The company is big enough to have a few layers of management and different services. Because the top managements want to keep control of the company, he’s requesting the famous KPIs. Each service has different KPI, and quickly enough, most employees understand that they can earn more money by targeting the KPIs than by trying to achieve the best possible product for their customers.
Worse, KPIs might be highly destructive when the KPI from a service leads to more burden for another service.
For example, if one of the KPI for the support team is to take as many call as possible, they will quickly classify lots of tickets as critical bugs to be managed by the technical team. Just because it’s faster than trying to understand what happens to the user.
As a result the technical team might have a more work and the global delivering flow of the company will be slower.
Each service prefer to keep their head in the sand rather than trying to collaborate with other ones.

Enterprise Standards

Another widely spread error is the standardisation spree. Usually in the name of costs hunting (even if it’s more about power and control, because in the end it often cost more than local auto organization), the company imposes some methods, tools and/or architectures, without knowing if it makes sense for a given context.
For instance a policy will enforce all the teams to work with SCRUM. Or they will impose a common integration platform for the whole company.
It often happens when management confuses practices (SCRUM, Unit tests, continuous integration…) with principles (being more agile, code quality, fast feedback…).
Many consultants actually increase this confusion and deliver what they (think to) know instead of what the company need in its context.

So should we be domain driven when they suck?

I think my point in the original article is still valid. In the end the problems I described here is just that sometimes, the business itself is not Domain Driven. In the sense that they are looking for immediate profit or power and control instead of caring about the domain.
Thus we should all be Domain Driven, especially the business part of the company. And writing it like that is a bit depressing, but yeah, quite often the business part of the company does not really care about the domain itself.
In this case, we should help them to be more Domain Driven, or just leave them and go work in more healthy environment 😊

 

Dry should not be technical

Do you know the “I talk about it so often that I believe I already wrote a blog post about it” effect? It happens when you talk about something so often that you are sure to have a blog post somewhere to explain it more deeply 😉
It happens to me recently about DRY (Don’t Repeat Yourself). In a twitter conversation where I once more had to explain why DRY should not be technical. I’ve looked for my blog post about it. Just to find that it doesn’t exist yet… Thus, here it is.

DRY ?

According to Wikipedia, DRY is a principle of software development aimed at reducing repetition of software patterns, replacing it with abstractions or using data normalization to avoid redundancy.
One of the main arguments for avoiding redundancy is to improve software maintenance. It seems great right? If you have to modify the code in two places instead of one when you want to change a behavior, you increase the risk of error.

Coupling ?

According to Wikipedia, coupling is a measure of how closely connected two routines or modules are.
Low coupling is often a sign of a well-structured computer system and a good design, and when combined with high cohesion, supports the general goals of high readability and maintainability.

The main issue with DRY when apply dumbly is that it increases coupling (which is a code bad smell). Because, sharing the same code between two things create a coupling between them. Too many developers consider that two identic lines of code in the system must be merged and shared into one, because we want to be DRY.
The key to have a smart refactoring in order to be DRY is to care about cohesion.

Cohesion ?

According to Wikipedia, cohesion refers to the degree to which the elements inside a module belong together. In one sense, it is a measure of the strength of relationship between the methods and data of a class and some unifying purpose or concept served by that class. In another sense, it is a measure of the strength of relationship between the class’s methods and data themselves.

If we share code between two modules with low cohesion, the result is a dramatic decrease in maintainability. We take the risk to break the second module, each time we want to change something in this shared code for the first module.

DRY Should not be technical

An easy way to avoid this pitfall is to consider the business concept of what you want to share.
If the business concept is the same for the two modules, you can share it with less risks, because it should evolve for the same reason in the two places.
If it’s just a technical concept, sharing it may be dangerous, because both modules will probably need different updates depending on their use cases.

Of course it happens because, no matter if you know/want it, you’re Domain Driven. It means that your module will evolve because of business requirements. Low cohesion means the two modules have different business purposes, then will evolve very differently. And we don’t want to share something between two things that evolve very differently.

Let me recap

  • To be efficient, DRY must be combined with high cohesion (and few people remember that)
  • An easy way to detect cohesion is to care about the business goal of each module

I do believe it’s one of the first good practice easy to apply that can radically change your code maintainability day after day.

 

We’re all Domain Driven

Believe it nor not, one of the main reasons why software exists is to help companies to make money. These companies earn money because they have a business. Usually they sell something to customers, in order to solve a problem for them.

A software developer that doesn’t care about the business is missing an important point. It creates a mismatch between the business and the software. This mismatch makes the system harder to maintain, because even if we don’t want it, we’re all domain driven.

The burden to maintain this system lies on the IT team. In other words, denying the domain aspects of the software is a way to shoot yourself in the foot.

How to recognize this mismatch

When this mismatch happens, there are many patterns that emerge.

One of them is the “business sucks” syndrome. You can recognize it when the IT team is always complaining with arguments like “they don’t know what they want!”, or “they always change their mind”, and even “they sell something that doesn’t exist!”.

Of course they sell something that doesn’t exist, otherwise how would you know what to build?
Of course they change their mind, because they are constantly testing and adapting to customers.
Of course they don’t know what they want, precisely because it doesn’t exist yet, and it’s not trivial to know what’s possible to do with software.

Let me raise a warning though, selling something that doesn’t exist is totally legitimate from a business perspective. But stressing someone else because a business man took unrealistic commitment with a customer is not.

It’s the business job to sell stuff that doesn’t exist, and then to handle customers expectations until it’s delivered. It shows why it’s a team work. Without the production team, the business man has only dreams to sell. Without a business man, a production team has no one to sell the product. The sweet spot is to sell something that doesn’t exist, but that can be done quickly. In other words, something that “almost exist”.

How to handle this mismatch

The solution is to let the business drive your software. To let your domain drive your design. Good news, there is a bunch of literature about Domain Driven Design!

It can be resumed by: organize your code, then your teams, then your company around the business, and you will improve software maintainability and customer satisfaction.

It seems trivial, but it isn’t. Trying to know at every line of code which business purpose it serves is hard. Trying to know at every meeting which business purpose it serves is hard. Trying to know if the company has a structure that serves the business is hard.

It’s even harder because as the business evolve, the whole structure (company, teams, software) should evolve as well.

To be fair it’s so hard that I don’t think any company can achieve it. But trying to constantly improve following the principles of Domain Driven Design is good enough to be far better than the average.

 

How do you teach DDD?

The more I work using Domain Driven Design in my daily job, the more I face how hard it is to teach. What’s the matter here? Why is DDD so often misunderstood? Of course, we can just consider that it’s a complex thing, hence requiring lots of knowledge and practices to be mastered. But let’s be more constructive and try to find the root problem in the domain of DDD teaching.

Like always, we need to agree on the terms we’ll use through this post.

Reminder: DDD

DDD is about tackling the complexity of the domain in the heart of software. It means that, in an ideal world, your software must be as complex as the problem it’s solving. Plus, the problem you solve must be the most valuable possible thing for your company. DDD provides patterns to address these points (spoiler alert: it’s not an easy task). Implementing DDD is all about analyzing dependencies.

Reminder: Tactical patterns

Tactical patterns are the most concrete parts for us developers because it’s about code! It’s a set of technical tools to concretely apply a DDD approach where it matters the most. These patterns evolve quickly, at the same speed as good practices. A well-known example is the repository pattern. Tactical patterns help to know how to build each part of a business.

 

Reminder: Strategic patterns

Strategic patterns are more abstract. They allow to categorize the domain (the business) into subdomains, in order to know how to build context of applications around it. Each context has a specific common business language (the ubiquitous language) and use precise way to communicate. Does a context impose things to another context? Do they share a kernel? How do they communicate? All of this can be captured using strategic patterns. They help to know what the different parts of the business are, and how they interact.

The DDD usual problems

Since I start studying DDD in 2012, I meet two recurrent problems.
The first is that newcomers (including me) do not know where to start. They can feel DDD is huge, but the reference books are intimidating. The community of smart peoples using words you never heard before seems nice, but you feel so stupid around them that it’s hard to stay.
The second one is that most people (yep, was me again) will not grab the duality of strategic versus tactical patterns at first glance. Worse, they may stay focus on the tactical patterns because they seem more concrete. We already know some of them, like factories or layered architecture. The consequence could be that we overlook the strategic patterns.

Root cause analysis

Following the principles of good design, how can we improve DDD so that these mistakes are harder to make for newcomers? Let’s use my (almost) secret silver bullet for that.
In my domain of DDD teaching, I believe there are two sub domains: one is about tactics, the other is about strategies.
An efficient implementation for teaching DDD would map one bounded context for strategic patterns, and one context to for tactical patterns. We have several clues to justify this implementation.
First clue: different languages. The two contexts have specific ubiquitous language.
Second clue: different life cycle. Tactical patterns evolve quickly. Most of the patterns from the blue book can be replaced by more recent patterns like CQRS/ES or hexagonal architecture. Strategic patterns are much more durable.
Third clue: the level of abstraction is not the same in both contexts.
Last clue: the strategic context is much more important. It’s my core domain, the core values I want to share when teaching DDD. There is a clear dependence between my contexts. Tactical patterns are important but will bring much less value if I teach them alone.
I now have a part of the answer about why DDD is hard to teach: it mixes two very different contexts. Both are useful, one is more central than the other, but also more abstract, hence harder to understand.

Solution attempt

Eric was really ambitious in his attempt to improve the industry, providing both strategic and tactical views. I think the trending and the emergence of major DDD conferences across the world are proofs that he succeeds. I also understand his willing to provide something that is not only abstract, to avoid the architect ivory tower syndrome.
Still, strategic and tactical patterns are really different beasts. These two faces of DDD make it harder to understand.
How can we manage this complexity? It depends on the context (did you see that coming?). But in the domain of teaching DDD for newcomers, I would accentuate on strategic patterns, mainly bounded context, because this is the pattern that can lead to all other patterns. Then I would explain that all the industry standards good practices (continuous integration, segregation of responsibility and so on…) are mandatory to implement the core domain, and that DDD also includes them under the name tactical patterns.
Trying to go the other way around (teaching the tactical part as introduction to DDD) increases the risk of missing the core concepts.

As always, it’s not a recipe, but it may be a way to facilitate the understanding of DDD.

 

It’s all about fast feedback

I’m a big fan of James Coplien.
I appreciate his controversial point of view about Unit Testing, even if I don’t agree with him. Recently he tweeted about this article explaining why integration tests are much better than unit tests.
Let’s explore it together.

Unit test problem

You write code and then run the unit tests, only to have them fail. Upon closer inspection, you realize that you added a collaborator to the production code but forgot to configure a mock object for it in the unit tests.”

In other words he points out that after a refactoring, some tests will fail despite there is no behaviour modification.
But it really depends on how you write your unit tests. When practicing TDD, I’m testing a logical behaviour. Several classes can emerge, I don’t necessarily have one test class for one production class. And when coupled with DDD practices, I can write unit tests without mocking anything, because I test business logic. Also when I strive for applying SRP, I have a few functions per interfaces, meaning one test won’t fail just because I change some interfaces in another place.
That being said, I agree that some refactoring might change some contracts, which requires to change both the production and the test code. My point is: if it is complicated, it is not because of the unit tests.

System tests solution

“While I was enslaved by unit tests, I couldn’t help but notice that the system tests treated me with more respect. They didn’t care about implementation details. As behavior remained intact. they didn’t complain.”
(System tests for the author are almost end to end and include database)

Again, I agree, if it’s a technical refactoring, the tests that use only production code without mocking may be less brittle.
But I also notice that, when a system test goes red after an actual regression, it takes me a while to find out what the actual problem is. Also, when I had some bugs in production, it is harder to reproduce it in my system tests. It encourages me to fix the code without changing the system tests.
And finally, when there is a business change, it hurts much more to change my system tests. I need a few hours just to write the test managing the new behaviour. I have to initialize half of the application just to check 2 lines of code.

 

Pyramid tests is a myth!

“If you’re like me, you were trained to believe in and embrace the testing pyramid.”…”But my experience revealed a different picture altogether. I found that not only were unit tests extremely brittle due to their coupling to volatile implementation details, but they also formed the wider base of the regression pyramid. In other words, they were a pain to maintain, and developers were encouraged to write as many of them as possible.”

I definitely disagree.
I was not trained to believe in the testing pyramid. I was trained to believe in the “get your shit done, faster please”. And using this approach I believed, like the author and many other developers, that system tests have a better ROI.

It’s all about Fast Feedback

So I tried, and it doesn’t work for me because of long feedback (more than a few minutes).
Feedback time is everything when you run your tests hundreds of times per day, on your local machine. And running your tests hundreds of times per day is really important to practice TDD.
Running the tests has to be easy and fast, or it becomes a pain. And when it’s painful, we loose discipline. We start checking Twitter while the tests are running, and that’s the start of the end of our productivity.


Contextual testing

Maybe there are contexts where systems tests have a better ROI than unit tests. But in my context of backend complex application, with lots of business requirements changing every day, it is not the case.
And I’m not speaking theoretically here. I was involved in 6 projects since I started my career. One has no tests at all, two used inverse pyramid, and three used the classic Mike Kohn Pyramid.
No need to talk about the failure of the project without tests.
The two who used the inverse pyramid have commons characteristics: it was really painful to maintain after a few months, and we need one or two developers almost full-time to keep the system tests working. Not mentioning the time we loose to run the tests before pushing our code, meaning that we often pushed without testing and break the build.

The projects I enjoyed the most as a developer, and my customer as well I believe, was when we have a solid unit testing strategy following the classical Mike Kohn Pyramid. We were able to run thousands of unit tests in a few seconds, and keep a few integration tests running only on the server.

To get results in the long run, don’t give up unit tests, at least if you are working in the same context than me.

 

The coding Iceberg

Recently, I read a few posts about AIs, including Uncle Bob’s post, in response to Grady Booch (about this tweet).
I think the fact tha
t some people believe AIs might replace developers leads to interesting questions about what is programming?

What is programming?

As Bob recalls us, Alan Turing defined programming as a sequence of simple statements of the following form:

Given that the sstem is in state s1,
When event E occurs,
Then set the system to state s2 and invoke behavior B

We express some needs in terms of state transition to be executed by a machine, in other words we build state machines in order to satisfy precise specifications.
This explanation makes it crystal clear that the complexity increases with the number of states in the system.

The perception

Lots of people consider coding as a translation in a given language. You can translate a text from French to English, so you should be able to translate specifications from human readable to computer understandable.
Of course, it is only the emerged part. The translation from human readable to machine understandable code is already automatic, it’s called the compilation.

Developers must be Domain Driven

Under water, developers must express business needs in an unambiguous way, which is the hard part. Coding would be a translation only if the requirements were already a precise state machine, ie a suite of exhaustive Given/When/Then.

As the specifications are never precise enough, we developers must complete them. We have to challenge existing specifications with our understanding of computer, and we have to fill the missing parts with our understanding of the domain.
Thus, considering developers as simple translator who do not need to understand what they are writing about is a sure recipe for failure.

The future

Believing that coders can be replaced by AIs is believing that coders do not need to understand what they are writing about.

AIs might help developers to do a better job though, if they are designed to optimize automatic part like compilation.

 

The over-engineering theory

I never was comfortable with the idea of “complex domain”.

“Use DDD only in complex domain” is a mantra used by DDD experts to avoid the Silver Bullet Syndrom. It is really convenient to avoid uncomfortable discussion.
 

Why do I mind?

We’d like to know what is a complex domain to know when to use DDD.

From a strategic perspective, I already argued that we could always use it. The remaining question is: when should I use DDD from a tactical perspective? When should I implement hexagonal architecture, CQRS/ES and other fancy stuff like that?

Not in a CRUD software?

Whatever the implementation we choose, software is a business abstraction. When we choose a CRUD implementation, we bet the future software will have few features. We bet we won’t need many abstractions.  The cognitive load due to the domain will stay low, implying we can mix business logic with technical terms, without building unmanageable software.

In my experience, lots of applications begun as simple CRUD, but they quickly evolved in something more complex and useful for the business. Unfortunately we keep coding them as simple CRUD, which results in a massive mess. Certainly not in purpose, adding just a bit of complexity day after day makes it hard to grab the whole complexity of the solution. We are the boiling frog.

The over-engineering theory

The challenge is to find at which point our simple CRUD application becomes a more complex line of business application.

My theory is that we consider patterns from tactical DDD over-engineering all the time. Because we are unable to feel the complexity of the software we are building day after day. Worse, we think that the knowledge we accumulate about this complexity makes us valuable as the dungeon master. We are deeply biased to sense our own work.

But what happens when we go working on another project? The will to rewrite the full software from scratch. Push the frog in hot water, and she won’t stay for long.

 

Looking for the inflection point

We’d like to find when it becomes interesting to implement tactical DDD patterns, despite the cost it has.

A part of the solution may be to check how long a new comer needs to be productive. When it is too long, there is room for improvement, and tactical patterns can help to decrease the code complexity.
Another solution may be to ask for a few audits by different DDD experts, but it could be more expensive.
A simpler solution may be to assume that the software will become more complex. It implies we should look at which tactical pattern can fit our needs, day after day.

Remember there is a world of practices in tactical DDD patterns. Using all of them all the time is not desirable. Picking the good one at the good time is the actual difficulty.

When should I use tactical DDD patterns?

I do not have a definitive answer for that, just an empirical observation: I’ve seen countless software implemented in a CRUD way that would be greatly improved by a DDD tactical approach. I’ve seen no software implemented with a tactical DDD approach that would be greatly improved by a CRUD implementation.

Just saying.

 

“If you think good design is expensive, you should look at the cost of bad design.” -Dr. Ralf Speth, CEO Jaguar 

 

 

 

It is not your domain

From a technical perspective, I would argue that a DDD project is nothing but a clear and protected domain.
Working on lots of legacy code though, I observe common mistakes to identify what is inside the domain, and what is outside.

 

Your data model is not your domain model

It is a really common mistake to use a data model as a domain model. I think ORM and CRUD have their part of responsibility in this misconception. A data model is a representation of the model optimized for data storage.

Building object in code from this model using ORM doesn’t make it a domain model. It is still a data model, it is still optimized for data storage. It is no longer sql tables, nothing more.

The data model has the responsibility to store data, whereas the domain model has the responsibility to handle business logic. An application can be considered CRUD only if there is no business logic around the data model. Even in this (rare) case, your data model is not your domain model. It just means that, as no business logics is involved, we don’t need any abstraction to manage it, and thus we have no domain model.

 

Your view model is not your domain model

Another common mistake is to add just one layer between the data model and the view. This layer has different name (Presenter, Controller, ViewModel…Whatever) in different patterns and languages, but the idea is the same: abstracting the view using code.

The mistake is when we believe this is the place to add business logic. This layer has already the responsibility to abstract the view, we don’t want to add any other responsibility.

 

Your data model should not notify your view

I go crazy when I find a model object with the responsibility to notify the view when some data changed (often using databinding). It literally means that this data or domain object, has also the responsibility to manage the way data are displayed.

As usual, it is all about separation of concern.

Your domain model should depend of (almost) nothing

The domain model is a set of classes or functions, group in a domain layer, containing all the business logic. This layer is absolutely free from the infrastructure. It should be a pure abstraction of the business.

A domain model is still valid if we change the way we render the software. A domain model is still valid if we change the data storage. A domain model is still valid if we decide to stop using our favourite Framework.

A domain model depends of one thing and one thing only: the business.