If you’re the type of developer that studies and does their best to apply best practice, you’ve probably read or heard at some point that you should separate policy from mechanism. You might not have heard it stated that exact way, but I’m sure you’ve probably heard it at some point in your career.
Maybe you were told you should separate the what from the how. Perhaps you were told to separate the algorithm from the implementation. Or, it might have been that high-level policy should not depend on low-level detail – they should both depend on shared abstractions.
All of these are ways of saying the same thing, and there’s a principle that represents them: the Dependency Inversion Principle.
You might wonder why, if I’m so sure you’ve heard about this bit of historical wisdom, I’m talking about it today. Well the truth is that, while I am sure you’ve been exposed to the idea, the code I see people writing fails to comply.
The only reasonable conclusion is that people either don’t understand how to comply or choose not to. Since we’re talking about people focused on best practice, I prefer to think it’s the former rather than the latter.
What Does It Mean to Separate Policy From Mechanism?
I still can’t tell you whether it was a lack of understanding about policy, mechanism, or the scope to be considered that caused my personal confusion. In the end, it doesn’t matter.
In the end, I think it’s best to explain everything. After all, the thing that I missed might not be the thing you or someone else has missed.
To help make it more concrete, we’ll use the example of saving a new entity in the context of a web application.
What’s In a Policy?
Policy is, simply stated, a business rule. You could call it business logic, if you wish. Just make sure you include every bit of it from input, to processing, to output.
Exception flows are included. Transaction demarcation (start, commit, rollback) is included. Spanning multiple persistence operations is included – if that’s part of the business rule.
If we consider our example, the policy would be receiving the input (the task or fields that will be used to create the task), the creation of the task (if it wasn’t received directly as input), the validation of the task, and the persistence of the task.
Since we’re including exception flows, we have to also include the case where validation or persistence fails. And, since we are followers of best practice, validation and persistence are represented by interfaces.
If we have to create the task, that too has some abstraction at play. Maybe it’s a Factory Method. Maybe it’s a Builder.
Everything that remains after the details are factored out is the policy.
What’s In a Mechanism?
The mechanism is all the code you factored out. All the implementation details.
The mechanism is the builder implementation, the validator (custom, JSR-373, whatever), the Hibernate DAO. All of which implement some interface.
The thing that called the policy – a controller for some framework – is mechanism too.
What Are the Shared Abstractions?
The interfaces are the shared abstractions, and they belong more strongly to the policy than the mechanism. In fact, it’s these shared abstractions that make it possible for the policy to stand alone. Without them, there is no way for the policy to use the mechanism without becoming dependent upon it.
The Holy Grail: Environment-Agnostic Applications That Run On Any Platform
For as long as I can remember, our goal has been to create applications that can be moved from one environment to another without alteration. Unfortunately, we have failed.
The sad part is that, while it’s very possible to pull this off, we haven’t – but we believe that we have.
What We’re Doing Right
Nowadays, most folks are writing to an interface. We create interfaces for our services, validators, and persistence. As mentioned earlier, these interfaces – shared abstractions – are a critical part of achieving the separation of policy and mechanism.
What We’re Doing Wrong
I know! The last thing you probably need is yet someone else to tell you what you’re doing wrong. Still, the first step in changing anything is admitting that a problem exists. So, please read what follows in that spirit.
Unfortunately, there’s a bit to say.
Controllers Belong to the Mechanism and Should Delegate to Policy Instead of Containing It
One of our greatest departures from the separation of policy and mechanism is the fact that we tend to write our policy as controllers. No matter which platform we are building for, the controller represents a low-level detail that is not part of our business logic.
Stop and think about it for a moment. If the controllers are where policy lives, how can you possibly implement your application in another environment on another platform unchanged?
You can’t.
Well, not without writing controllers for the new platform to house the policy. The goal is to avoid having to recreate the policy at all.
All the controller should do is accept input and delegate to our policy.
Entities are Policy – Not Mechanism
Whether you call them entities, domain objects, business objects, or something else, these objects belong to policy and should not contain anything that enlists them in the service of the mechanism.
Those annotations you love to use to configure persistence? Mechanism! By putting them on your entities, you are breaking policy/mechanism separation.
Gateway and DAO Interfaces Should Live With Policy Not the Implementation
Separating policy from mechanism requires shared abstractions to connect them. However, those shared abstractions – Gateway or DAO interfaces qualify – must be housed with the policy and not the mechanism.
They are bound more tightly to the policy than the mechanism. In fact, you could consider the Abstract Server pattern as an example of how the policy (client) and shared abstractions relate to the mechanism (server).
So, How Do We Fix Things?
Fortunately, coming into full compliance with the separation of policy and mechanism is pretty simple.
Create an Object for Policy That’s Independent of the Controller
If you’re following Clean Architecture, the boundary accomplishes this. In fact, you could think of it as a story controller. Clean Architecture calls it a boundary to avoid confusion, but that’s really all it is.
If you’re not following Clean Architecture, you could create a new class that belongs to the business logic that contains the entire policy. Of course, to do that, you need some way to communicate results back to the UI, so you need to factor in the Presenter concept somehow.
In other words, if you’re not following Clean Architecture, you might as well start. It’s got all you need.
Use XML Configuration Instead of Annotations
I know!
I know!
Someone told you that it was better to place those annotations on your entities rather than using XML configuration because it places the configuration closer to the thing being configured.
The root problem here is that entities are policy and those annotations are mechanism. It’s okay for mechanism to know about policy (via shared abstractions that are created to serve the purpose of the policy), but policy should never know about mechanism.
Policy/mechanism separation is a stronger rule than placing configuration next to what is configured, so the annotations lose.
Sorry!
So go back to XML configuration. It’s really not that bad, and you’ll gain a lot of flexibility from it.
Move DAO Interfaces Into the Policy Project
Yes, it’s a simple fix. You have to lose the annotations on your entities first – that’s the hard part.
Once you’ve done this, you’re positioned to change from one set of DAO implementations to another with no further pain.
The Preservation of Business Value
The business value in our applications is represented by the policy. Policy may change over time, and new policies may be introduced, but – if separation of policy and mechanism is followed faithfully – its value can be longer lasting than any user interface or persistence mechanism ever thought about.
Some policies may change. New policies may come along. However, there are going to be some policies that continue to exist – for very long periods of time – without change. Maybe more than you think.
Don’t Ignore Simple Applications
There’s always a temptation to avoid doing simple or small applications properly. People like to argue that – because they are simple – it’s overkill to apply any formality to them.
That’s simply untrue.
Simple applications are the first place you should begin practicing the separation of policy and mechanism because they’re simple. Once they have that formality applied, they can be great testbeds for new UI and persistence frameworks.
Because of the separation, the work to test these new things out will be super-focused. You’ll truly be able to focus on one thing.
No More Rewrites!
Let’s be honest with each other. The day is going to come that, no matter how much you love it, you’re going to want to change your UI framework or your persistence framework.
Maybe you make a big jump by going from a traditional web application approach to a hybrid HTML + REST approach. Maybe it’s something simpler.
You’ll never need to do a rewrite though!
Think about it. Your existing application follows Clean Architecture so you don’t have to go figure out what the business rules are. You just have create new implementations of those shared abstractions for the new mechanism.
Want to add some new business rules at the same time? Go ahead. The pre-existing ones will still be just as sound as they ever were. Just plug-in the new mechanism(s) and go!
Always Be Competitive When Acquiring New Talent
Let’s face it, developers want to work on contemporary technologies. If you’re not separating policy and mechanism, it’s inevitable that you will find yourself in a less favorable position when it comes to recruiting top talent.
Why?
When policy and mechanism are mixed (web framework + business logic, business logic + persistence, or – worst case – web framework + business logic + persistence), policy becomes hidden. Just the idea of trying to change your web framework or persistence framework might strike terror in the hearts of the bean counters.
How could you ever begin to estimate that work?
When policy and mechanism are separated, each thing can be estimated and developed independently. So, you could, for example, make a true business argument for changing from one web framework to another or one persistence mechanism to another.
You could easily quantify it.
First, create an estimate for creating the new UI. Then, all you have to do is show the cost of being unable to hire better talent – or turnover – or whatever your resourcing problem is that being more agile would solve.
Never Get Stuck On Obsolete Technology
If you skipped the “Always Be Competitive When Acquiring New Talent” section above, go read it. Same argument applies.
Although, there’s another point to make here: you don’t want to find yourself in a position where security updates are difficult or impossible to make. Or, perhaps in a position of running on decommissioned libraries or frameworks.
Closing Thoughts
It amazes me, when I stop and think about it now, that I did not realize earlier I was writing code which violated the separation of policy and mechanism. I’ve always considered myself a person who is good at seeing things like that.
I hope writing this down helps to open your eyes too, if they haven’t been opened already.
If you found this article helpful, please remember to show your thanks by leaving a comment, liking, sharing, or tweeting the article to your network. Thanks in advance to those who do.
That’s all for this week. Until next time, this is Eddie Bush for Craftsmanship Counts reminding you to keep your tests passing and your code clean!
This is very helpful.
Thanks! 🙂
Glad you found it useful!