maestros

I used to be DRY, now I am WET

24 January, 2022 • 4 min read

During my early days as a software engineer, I was told by one of my senior colleagues, that if some code snippet had to be duplicated then it should be abstracted somewhere and reuse it from there.

And for many years I kept that advice as a rule of thumb. Whenever I spotted an opportunity for abstraction I would proceed without second thoughts, as long as I would avoid copy-pasting existing code.

To my understanding, being a DRY (Don't Repeat Yourself) engineer was the right approach.

But guess what, retrospectively speaking, I couldn't be more wrong.

The Wrong Abstraction

At some point in my career, I realized that there were not a few times that a premature optimization led me to a wrong abstraction down the line.

And that's when things used to get interesting. In fact, not that interesting as it may sound, because let's agree on this, wrong abstractions prevent a codebase from being able to scale or even adapt to refactors.

Trust me, I can tell for sure that there is no such thing as introducing a bullet proof abstract code that will be written once and solve both my current and future problems.

To my surprise, and although it hurts me, I can't predict the future after all.

Long story short, trying to be DRY can usually have unwanted side-effects, such as wrong abstractions.

The Premature Optimization

Okay, this is why I refrained from being DRY. Now we will examine the root cause behind my tendency to abstract things in the first place.

I think it is fair to say that as a software engineer I like optimizations. But are optimizations always a good thing ?

To speak for myself, it has been a while now that I've came up to the conclusion, that prematurely optimizing things is a bad habit. Let me elaborate on this...

Spending time trying to optimize performance or make code more efficient, isn't always the best use of our time.

Especially when we are building a product from scratch, we might want to release an alpha version of it, to validate first its value to our users. Then, after we have collected some valuable information, we may apply any optimizations needed.

On the other hand, imagine working on a feature for a long time, ensuring it will be a state of the art code before it is delivered, to only realize that no one is using this feature after all... Wouldn't that be both waste of time and demotivating ?

If not DRY, then what ?

In case you haven't heard of WET before, it stands for Write Everything Twice, and it is somewhat the opposite of the DRY mentality.

This is me now, and to be honest things are going so far, so good.

To give you some further context, a year ago I joined an early stage startup, and all we had was the idea, since we built the product from the ground up.

The fact that I used to write everything twice, or even thrice at times, allowed me to quickly deliver product iterations and validate whether we were heading towards the right direction.

To accomplish that, I had to break old habits and stop feeling guilty for copy-pasting a functional code snippet from one to another file.

I would go back to rethink my implementation and apply needed refactors and optimizations only after we had enough knowledge about a feature and the value we were providing to our users.

The Downside of WET

I would be a liar if I told you that writing everything twice has no drawbacks at all.

If this approach is abused, you can easily end up with a great amount of technical debt.

I could use one my favorite analogies here when it comes to software engineering. Our job is more like gardening rather than building a house. There are no irreversible actions and most of them are meant to be reevaluated at some point. So, introducing some technical debt is not the end of the world.

It is our responsibility though as software engineers and maintainers to find the right balance between quickly delivering a feature and ensuring that good foundations are laid in the product's codebase at the same time.

Finale

Based on my experience until now, being DRY was never about code itself. It's about being consistent in terms of building domain knowledge.

Having said that, if two or more parts of the codebase refer to the same knowledge, it is certain that they will always have to change in parallel during a product's lifetime. In this case, de-duplicating them would be a good choice.

On the contrary, two similar parts of code which are irrelevant to each other, they will change separately. Introducing an abstraction for them implies the risk of applying a change that would accidentally affect the other part as well. And that's another way to end up with technical debt.

So remember, our life as engineers would be simpler if we keep in mind to avoid premature optimizations, and write everything twice before we rush into making our code more efficient.


Thanks for reading!