Quality software should contain no redundancies—it should not repeat itself. Quality software should contain no redundancies—it should not repeat itself.
You see, redundancy in learning can be good. We learn by repetition. But redundancy in software always costs more to maintain and is therefore a burden.
I have to be careful here. I was teaching a software design class several years ago outside Dallas/Fort Worth, and I didn’t know it but I had two senior NASA developers in the room. I said, “Redundancy is always bad.” One of them stood up and said, “Wait a minute, redundancy saves lives!”
He was right but he was talking about a particular kind of redundancy—intentional redundancy. If you’ve ever worked on mission-critical applications, you know what I’m talking about.
I define a mission-critical application as one where if a bug gets into production someone could likely die. Under those circumstances you think about the software you build differently than if you were writing a social media app—at least if you have a conscience and you want to sleep at night. Development becomes about reliability at all costs. These two developers from NASA build mission-critical applications.
For example, there were five computers on the space shuttle, and for mission-critical computations they each did the computation separately and then voted on their answer. If they concurred, there was a high likelihood the computation was correct, but if there were discrepancies they may have needed to recompute.
Those NASA developers are right—having intentional redundancy for mission-critical applications can save lives. But what I’m talking about here is unintentional redundancy—and that’s always a maintenance issue.
People use the acronym DRY (Don’t Repeat Yourself) or phrases like “Once and only once,” but finding redundancy isn’t always so easy.
Most redundancy is obvious and easy to see in code. However, redundancy can also take subtle forms that make it not so easy to spot, which is why I prefer the term redundancy instead of the term used in Extreme Programming: duplication.
I may recognize that I’m introducing redundancy when I inherit from the clipboard—if I copy something to the clipboard, before I paste it, I could ask myself if I really need it in both places or if I could put it in its own place and call it from both places. If I want to call something in more than one place, I can surely name it so I can wrap it in a method and call it.
I would say that 95% of all redundancy is easy to recognize in code and once seen it is easy to get rid of. It’s that last 5% that can be hard to find, but often it can be worth the extra effort. I’ll hunt for it if I have the time because redundancy in code can hide the true nature of a problem, and without understanding a problem, it’s difficult to find a concise solution that solves it. If I can rid my code of every bit of redundancy, I often discover patterns in the problem that I didn’t see before. This can collapse complex code into a much simpler solution.
There are many forms of redundancy. I’m not just referring to redundant state or redundant behavior; many other things can be redundant—redundant relationships, redundant tests, redundant concepts, redundant construction, redundant processes where most of the steps are identical but some of the steps are different so you create two algorithms that must be maintained forevermore. There are patterns that can help with these issues.
For me, redundancy in code is trying to do the same thing in multiple places regardless of the way you do it. Nonidentical code can be redundant and identical code can be nonredundant. Redundancy is not necessarily a repetition of form. Redundancy is a repetition of intent.