In SoftwareMill we practise something that we call a “reading club”. It takes various forms. Usually we go through a book, chapter by chapter. This usually takes several weeks to accomplish. Other times, this is a kind of a discussion panel where a group of people share their experience or opinion on a given subject. The last panel we had was titled “Quo vadis, Akka?” where we talked about the current state of the Akka ecosystem. However, there is yet another form of the reading club we really like. A free talk about some article or a blog post. It does not have to be a long one.
The wrong abstraction
A couple of weeks ago we read The Wrong Abstraction post by Sandi Metz. Let me share here some thoughts that popped up during our conversation.
The main idea of the post is to take a deeper look at the abstractions in our code to see if they are still useful. And if not, to consider inlining the piece of code in question, even if that means reintroducing duplication. The outcome of this should be a simpler abstraction with less parameters used and cleaner code in overall. Moreover, such over-parameterized abstraction becomes a code that is difficult to change and not so easy to understand. Therefore it can slow us down.
While all of this sounds quite simple and, after reading this, looks obvious, this is a really interesting reading. Let me explain why.
Less places with bugs
Having an abstraction that removes duplications in our code is cool, right? Less code to maintain means less places where a bug can be hidden and so forth. Also when business logic changes, it has to be applied in one place only. We all know this. We were taught that duplication in code is evil and we should avoid it. We are so familiar with this that very often all duplications are removed because there should be none of them.
Duplications as improvements
Yet, as you can read in the post, striving to achieve this state is correct only to some extent. When a given abstraction gets (or already is) complicated, we should consider taking a step, or even two, back. This means restoring duplications in code to have an abstraction that is simpler and not overloaded with additional parameters.
You have to admit the idea sounds strange at first. How can introducing more duplications into the code improve its quality? It can guide us to new possibilities, where we can find a different abstraction, more appropriate in the given place. Keep in mind that Sandi does not encourage preventing abstractions. The DRY (Don’t Repeat Yourself) principle is still valid and an important one. You should always look for duplications in your code and remove them where applicable.
What can be extremely helpful when reintroducing duplication is good test coverage for a given part of code. Of course the ideal situation would be having a high coverage (something close to 80-90%), but that is quite rare. Or - if you are unlucky enough - there are no tests at all. In such case, writing tests looks like a good starting point. Only then would I go on with the duplication in the code. After all, without tests, how will you know whether the code is not broken at the end?
The last takeaway? We, software engineers, have to always remember that the output of our work should be as good as possible. Whether we will achieve this by stepping back (by inlining duplications) or moving forward (by extending an already existing abstraction or creating a new one) is not as important as doing such things thoughtfully, with a clear view on the benefits and costs of the decision made.
And this is why I really encourage you to read Sandi’s post. It nicely shows that sometimes taking steps that seem counterintuitive might have a beneficial effect on your code.