Whenever you have to deal with a large project, you’ll have to define a set of bounded contexts, each describing a different point of view upon the same concepts.
What is an entity in a context will be a value object in another.
When related to enterprise processes, such contexts will be connected to the organization chart: different users can access to different contexts, often with slightly different capabilities.
Moreover, while you can sell the same domain model to different organizations, you can’t neither predict nor generalize the organizational structure. [2] You can make your software configurable, but whenever the access control rules are complex enough you fall in a customization hell that will erode the return on investment.
As an alternative, we decided to model the typical roles of the customer’s organization, each providing the entry-point to a bounded context.
This was hard to explain to our stakeholders, since for each new customer we get, there are a set of modeling tasks to do. However, as these activities can be easily planned, they managed to value them as a really cool feature: we can customize the applications we sell to fit the corporate structure of the customer!
All applications have users. This is so evident that it’s often forgot.
Each day a user log into our application and access a set of functionalities. He can browse statistical reports and portfolios, he fills profiles of his own customers, he advises them, he plans gifts for them, he sends their orders to financial markets and so on. But he can also access reports about his colleagues, aggregate statistics about their performances. Some time he can send to them alerts. He can even build a report forecasting the enterprise’s revenues for the board of directors.
What he can do depend on the position he plays in the organization. And you know how complex could be an human organization. At first it seem a simple hierarchy, a tree of roles, but soon you learn that assistants must be able to operate for their boss, that private bankers are not born equals and that exceptions exists… just to make you crazy.
If you ever thought to model each kind of user, you know what I mean.
Nevertheless you need to know what each user can do, when and how. Delegating such logic to the infrastructure is just an illusion: you are moving the problem elsewhere (often where it’s harder to solve non-trivial cases).
The solution we found is to model the roles of customer’s organization after the domain contexts.
Each role provides access to a set of repositories, domain services, responsibility and tools just like any real role in any real enterprise. We found that roles follow almost exactly the context boundaries of our best domains, sometimes customized with addictional requirements.
We were not afraid to write specific code for each customer, confident that a satisfied customer would have paid more.
Bounded contexts are among the most undervalued tools in software development. They are useful beyond the niche of domain-driven development.
As you know, when an application grows, its own complexity increases.
Developers try to avoid spaghetti-code, by applying a set of smart design
patterns that should allow for easier evolution.
However, the "overdesign" hell is just around the corner.
What if your software evolves on unexpected axes?
As a simple alternative, you could adopt well-defined and documented boundaries, that describe small contexts: such boundaries should be first class citizens in the ubiquitous language.
Everyone knows that different roles can access to the same things but with
different responsibilities: the IPatient
that a IPlasticSurgeon
operates
have the same InsuranceCode
of the IPatient
treated by the ICardiologist
,
but they are different for everything else.
Splitting the applications into bounded contexts, each linked to a user role,
allow to model a simpler reality. You will have two classes named IPatient
in
different namespaces but each class will be designed according to a specific
point of view, to satisfy a smaller set of requirements.
Roles have proved to be an efficent junction point between the pure domain model (implemented as plain old CLR objects) and the hosting infrastructure.
Logging, persistence, resource allocations, user locking and so on: all passes through the users' roles that act as a natural injector for the infrastructural code.
For example the repositories can bind the user’s access to specified entities, according to the fanciest rules that your customer can imagine, the domain services can be customized to log calls or to cache results and everything you hate will become easy.
You just have to deal with angry stakeholders that will tell you: "but we already did it three months ago!"
[2] In the second chapter of Analysis Pattern, Martin Fowler describe a
set of patterns for accountability management. While such patterns are both
elegant and powerfull we found them affected by a major flaw: they are not
part of the ubiquitous language.
We prefer to learn the language from domain experts instead of teaching them
our own.