Bounded Context #4: Bonuses
One day, the sales desk managers asked us to automate a simple yet tedious procedure they had been doing manually: calculate the commissions for the sales agents.
Again, it started out simple: once a month, just calculate a percentage of each agent’s sales and send the report to the managers. As before, we contemplated whether this was a core subdomain. The answer was no. We weren’t inventing anything new, weren’t making money out of this process, and if it was possible to buy an existing implementation, we definitely would. Not core, not generic, but another supporting subdomain.
We designed the solution accordingly: active record objects, orchestrated by a “smart” service layer, as shown in Figure A-5.
![]() |
Figure A-5. The bonuses bounded context implemented using the active record and lay‐ ered architecture patterns
Once the process became automated, boy, did everyone in the company become crea‐ tive about it. Our analysts wanted to optimize the heck out of this process. They wanted to try out different percentages, tie percentages to sales amounts and prices, unlock additional commissions for achieving different goals, and on and on. Guess when the initial design broke down?
Again, the codebase started turning into an unmanageable ball of mud. Adding new features became more and more expensive, bugs started to appear—and when you’re dealing with money, even the smallest bug can have BIG consequences.
Design: Take two
As with the event crunchers project, at some point we couldn’t bear it anymore. We had to throw away the old code and rewrite the solution from the ground up, this time as an event-sourced domain model.
And just as in the event crunchers project, the business domain was initially catego‐ rized as a supporting one. As the system evolved, it gradually mutated into a core subdomain: we found ways to make money out of these processes. However, there is a striking difference between these two bounded contexts.
Ubiquitous language
For the bonuses project, we had a ubiquitous language. Even though the initial imple‐ mentation was based on active records, we could still have a ubiquitous language.
As the domain’s complexity grew, the language used by the domain experts got more and more complicated as well. At some point, it could no longer be modeled using active records! This realization allowed us to notice the need for a change in the design much earlier than we did in the event crunchers project. We saved a lot of time and effort by not trying to fit a square peg into a round hole, thanks to the ubiquitous language.
A classic understanding of domain-driven design
At this point, our understanding of domain-driven design had finally evolved into a classic one: ubiquitous language, bounded contexts, and different types of subdo‐ mains, each designed according to its needs, as shown in Figure A-6.
![]() |
Figure A-6. A classic model of domain-driven design
However, things took quite an unexpected turn for our next project.