Stop me if you know this one. You find a library/framework that does something useful to you. You start using it and then realise it doesn’t work the way you want it in certain scenario or has a missing feature.
What do you do then?
- Abandon the library and look for alternative that is more “feature rich”?
- Ask the author to support your scenario/submit a pull request with the feature?
Those two, from my experience, are by far the most common approaches people take when faced with this situation.
There is another way
Surprisingly not many people take the third, most beneficial way, that is swapping part of the library for custom one, that is tailored for your needs.
Now, to be honest this has a prerequisite, that is, the library you’re using must be designed in a modular fashion, so that there are swappable parts. Most popular open source libraries however do a fairly good job at this. What this allows you to do, is to make specific assumptions and optimisations for your specific needs, ones that author of a generic library can never make, therefore having much more robust and targeted solution for your problems. Also being able to simply extend and/or swap parts of the library/framework means you don’t have to wait for a new version or waste time looking for and learning a different one only to discover at some later point that it also doesn’t support some scenario you’ve got.
I did just that today with RavenDB (or more specifically Json.NET library it uses internally). The application I’m working on needs to store object graphs from a third party vendor. Objects that weren’t designed with NoSQL storage in mind (or any storage in mind) and this was causing Json.NET some troubles. Not to bore you with the details, I was able to resolve the problem by swapping
DefaultContractResolver with my own implementation that catered for quirks of the model we’re using, and in less than 20 lines of code I achieved something remarkable – I was able to store in RavenDB, with no issues, objects that were never meant to be stored in such a way. And all of that without authors of RavenDB or Json.NET having to do anything.
Consider the alternatives
This brings us to the main point of this post – modularity is a feature. It is one of the most important features of any reusable piece of code. Consider the alternatives. If you don’t allow for swapping parts of your code from generic one-size-fits-most solution to scenario specific variants you’re painting yourself into a corner, in one of two ways.
You are writing a very rigid piece of software, that unless used exactly in the way you anticipated, will be unfit for the task.
Alternatively as you discover new scenarios you can try to stretch your default implementation to support them all, adding more and more configuration flags to the API. In the end you will find that for every new scenario you add support for, two new get reported that you don’t support, all while metrics of your code complexity go through the roof and maintainability plummets.
So be smart. Whether you’re creating a library or using one, remember about modularity.