I’ve written bad code in the past, and I will guarantee that I will write bad code in the future. It is, unfortunately, inevitable.
The fact that I have written bad code and that I will continue to occasionally produce bad code does not make me a bad developer, nor a bad person. I should feel ashamed when I write bad code, and I should put forth the effort to improve the code when I can.
Why do we write bad code? I believe there are a couple of places that bad code comes from.
We don’t know any better
This category applies to more than just junior developers. Our industry is constantly changing. There are new tools and techniques developed all of the time, and we don’t always know the latest “best practices”.
This category also applies to any new technologies that we use. When we first pick up a new technique, technology or tool, we don’t know the best way to use it, and we will make mistakes.
We need to be diligent to pay attention to the mistakes we make. We need to be open to feedback from others (even though it can be hard to hear). And most importantly, we need to be open to change when we find out that something isn’t working as well as we had hoped.
We are in a time crunch
I hate this excuse, but I will admit that I have used it. I would love to live in a world where we can take the time necessary to do things “the right way”, but we don’t always have that luxury.
The key with this category is that we need to be very careful when we decide to use this as an excuse for bad code. We all know that bad code is going to slow us down in the future, even if it gives us a short productivity boost in the present.
When we make the trade of productivity for quality we need to ensure that we go back and improve the quality when we have a little more time. We will rarely have the time to go back and rewrite an entire application, or even parts of it, but we should be able to slip in refactorings as we are working on code that will incrementally improve the landscape.
As professionals, when we know that there is a portion of the code that is sub-optimal, and there is work to be performed in that area, we need to raise this concern. We need to make the case that we need a little longer to do the work so that we can improve the code.
We are learning about the system/domain
I have seen this class of issue many times. Typically this class of error presents itself as a poorly, or improperly modeled domain. As we are beginning a new project, we often don’t know as much about the domain as would be optimal for modeling it. We do our best to model it as closely to reality as possible, but we almost always learn that we got something wrong, or didn’t write it at the correct level of abstraction.
This is one of the hardest type of bad code to fix since it is often an integral part of the architecture. I believe there are ways to incrementally improve our architecture to better match reality, but we need to do this very carefully.
We are working on a legacy system
The last category that I see happens as we are working on a system that has been around for a little while. The code starts out clean and then a change request is made. We make that little change, and the code still looks good. Then another request and another change, and so on and so forth. After some time, these changes begin to build up, and at some point we end up with a class or a method that is no longer “good code”.
I am as guilty of this as anyone else. I try to keep my eye out for this sort of degradation of the code and will either spend a little extra time on a given task to clean it up, or if there is no “extra time”, I try to keep track of these “code smells” in our issue tracking system.
Some organizations do not like the idea of adding technical debt cards to the issue tracking software. I worked in an organization like this for a while. Rather than writing these cards up in the issue tracker, we created physical cards with code smells on them. When a new card was created, we would review it at our iteration kick-off so everyone was aware of the issue. Then, if we were working in that area on another card, we could grab the technical debt card and try to make that change as well.
I think the most important take away here is that we need to take ownership of the fact that we are going to write bad code sometimes. We need to admit it to ourselves, and realize that this does not make us bad programmers, or bad people. What makes someone a bad programmer is the refusal to improve.