When integrating systems it is very easy to fall into HashMap temptation. “Just put some details in a Map and pass it to the service layer and it gives back what you need”. Maybe,… but there are risks.
I consider passing Maps around to services an anti-pattern because interfaces become less intentful and creates coupling between layers.
Let’s consider a hypothetical example of a farm system. Every morning old McDonald wants to name roll call all animals to ensure they are safe and sound. Farmer McDonald knows he has animals in the pond and on the pasture.
On the first pass we create a service receiving a context Map, keyed by environment type and containing animals’ names. The service returns a List with farm Animal instances.
Old McDonald knows the animals’ names, where they live and expects them to say: “present”, in their own dialect, obviously. One client program could look like the one bellow:
With this implementation it’s impossible to have a pond roll call only. But that’s not the worst thing, knowing that the service needs to be aware of different environments and keep track of them is the creepiest part. One solution is to make the service layer more intentful and have old McDonald say explicitly the animals of which environment he is roll calling:
Now instead of a Map it’s a List that gets passed around, the service interface expresses *exactly* what’s to be done and code can be re-used. The downside is that an extra call needs to be made from the client. In this particular example it’s not a major hassle because it requires no extra information about the livestock:
Bottom line: avoid passing Maps around and put more effort into defining highly intentful interfaces. As a rule of thumb service layers are dumb, hence they don’t have to decide which method/logic is to be invoked based on states/keys of other objects. Service layers should only know about domain objects and which methods to invoke. Utilising HashMaps in similar ways to this example violates the Tell, Don’t Ask principle. This design forces service layers to understand what’s inside of Maps to decide which method to invoke and the client layer in its turn, must create Maps with all things the service needs in order to process the call, which smells like coupling.