The Don't Repeat Yourself principle is important. But it's not the only important principle or consideration for software design. Like all good things it should be used with caution and afterthought.
Two things happened today that reminded me about a blog post I’ve been meaning to write for ages. First I had been talking about meta programming in Ruby with my Rails-developing colleague Johannes. On the topic of meta programming sometimes being overused he said “DRY isn’t everything”. Then later during the day, another colleague of mine, Mikael wrote this on Twitter: “Changing a model based on inheritance to composition. Damn, I wish I knew what I do now 2 years ago.”.
When I first started programming I built web sites using PHP and classic ASP. I often copied and pasted code all over the place creating quite a mess. But at least the sites worked pretty well. Later I studied programming in school, both at the high school level and at the university.
There I learnt about object oriented languages and basic patterns and practices. I especially remember being thought two things: that it’s important to comment your code and that it’s important to keep the code DRY. That is; to follow the Do not Repeat Yourself principle. I also remember being taught that a good way to ensure DRYness was to use inheritance. By grouping common methods into base classes sub classes can share common functionality.
Now, after having worked professionally with software development I’ve slowly come to realize that the focus on not repeating code during my education, and being taught that inheritance can be used for code reuse, is an experience that I’ve shared with many others. I’ve also come to realize that it’s a fallacy.
While DRY is an important principle it’s only just that. A principle. But by focusing so much on it in textbooks and lectures the education system made many of us believe it was the key to being good programmers. The key to being nice to the one maintaining the code once we we’re no longer there. The key to being professional.
Since the years of my education I’ve seen plenty of examples where a developer, often myself, has gone overboard with it. Making the code super dry, or making excuses when it isn’t. Often this level of DRY has been achieved by creating elaborate inheritance hierarchies or by having tons of static utility methods.
But DRY isn’t about ensuring that our applications doesn’t have two lines of code that look the same. It’s one of many guiding principles for writing code that is easy to change. Just like any other principle it has to be applied with the context taken into consideration. Two lines of code might do the exact same thing at a specific point in time. But that doesn’t mean that they are conceptually the same. And in order to effectively apply DRY we also have to know about other principles for writing software that is easy to change into account. Ranging from basic, but not easy, things such as thinking about how expressive our code is to principles such as the Open/Closed Principle and the Liskov Substitution Principle. To name a few. And when we do so we often come to realize that inheritance is often a lousy way to reuse code. Or that reusing code isn’t the key to delivering value.
I wish I had been taught more about the importance of variable and method naming in school. About writing code that speaks to the reader. Code that is clear and concise. Code that solves the problem in an efficient way but also communicates what it does and why from the perspective of the user.
I wish I had been taught more about how to write components that could be changed without actually changing that specific code at all. I wish I had been taught more about polymorphism and composition. About how to structure applications not with a focus on reuse but on change. About why abstractions matter. I’ve written and seen code that is super DRY but that doesn’t contain a single abstraction and that group things in huge inheritance hierarchies. Code that is about as flexible and reusable as a sunken ship.
Blindly applying DRY can quickly do more harm than good. And teaching us that applying DRY is the key to being professional is, well, unprofessional.
- A simple example of the Open/Closed Principle
- The Open/Closed Principle – A real world example
- Inversion of Control – It’s broader than just injecting components
- Inversion of Control – An Introduction with Examples in .NET
- Learning Scala part five - Methods
- Øredev impressions and insights
- Learning Scala
- Learning Scala part seven - Traits