When writing code, we try to implement a model of a certain real life domain. In a basic OO approach, we let nouns from this problem domain give name to our classes, while verbs give names to the classes’ methods. Our code is the solution domain.
In addition to the problem domain and the solution domain I like to think that we actually have a third one, let me call it the solution meta domain. This is the domain that describes the software development process we use, with it’s own specific words and phrases, like “use case”, “feature”, “story”, “bug”, “release version”, depending on what process we use.
Should it perhaps make sense to let parts of that solution domain also be explicitly represented in the code?
To benefit from this idea I think we should use the meta solution domain as something that could be queried to get hold of parts of the solution domain. For example:
Service myService = metaSolutionDomain.getServiceFor(UserStory.TRANSFER_MONEY);
The returned Service myService being a fine tuned service containing no less and no more than the exact API needed to carry out the Transfer Money user story.
We could take it one step further and pass a version number, or a release number:
Service myService = metaSolutionDomain.getServiceFor(UserStory.TRANSFER_MONEY, Release.4_3_0);
Thus actually making it possible to support many versions of the same functionality if that is needed (See for example at the end of Gojko Adzic’s Potentially shippable is no longer good enough).
Taking it even one step further, we’ll end up in something that resembles some of the ideas presented by James O. Coplien and Trygve Reenskaug as the DCI (Data, Context and Interaction) architecture paradigm. In DCI, the Context is the place where we’ll not only find the Service class from above (or rather the UseCase in DCI), but also the roles that will participate.
A very lightway approach to this would give us something like:
Context myContext = metaSolutionDomain.getContextFor(UserStory.TRANSFER_MONEY, Release.4_3_0); SourceAccount sa = myContext.getSourceAccount(someAccount.getAccountNo()); TargetAccount ta = myContext.getTargetAccount(anotherAccount.getAccountNo()); Receipt receipt = myContext.transferMoney(sa, ta);
Very well, but what’s the gain? Asking for, and then using these small services, perhaps only containing a single method, seems to me a very appealing way to focus the code. Only the stuff that is needed is there, making the code hard to misuse, and easier to test. And depending how far we go, we’ll start touching the DCI paradigm, in itself a very interesting idea!