I have heard it said that "insanity is a perfectly normal response to an insane environment." Over the course of my career, I have learned some really bad development habits as a form of self-defense against bad management habits. For example, when you combine a lack of good source control systems with project management that keeps asking you to remove and put back a piece of functionality multiple times throughout a project, you tend to develop a habit of never actually deleting code, just removing the access points in the user interface. After all, without good source control, you can't easily get it back, and with indecisive management, it is likely that you will need to get it back.
I know that I am not alone in this behavior. I can't tell you how much code I have seen where there are huge blocks that are totally unreachable, pages of commented out work, conditions set to "if true == true" so they didn't have to get rid of the work in the "else" portion, and so on. It is obvious to me that there are a lot of developers who are afraid to ever hit the delete button with a large piece of code selected.
Unfortunately, while this bad habit may have saved me a lot of time, it has some very serious side effects. Here's a list of the issues that I have come across:
- Code changes gets ugly because you are trying to keep orphaned code in-line with the rest of the system, but there is often no real regression testing or anything else.
- Maintaining code after a long period away from it (or by someone else) is very difficult, because no one really knows why a piece of code is there, they just know that it is there.
- The code is no longer a faithful representation of the business logic, because it contains logic that the specifications and business logic are not aware of.
- It presents potential security risks, as unmaintained code can sometimes be reached (especially in Web applications, where tweaking parameters may trigger the code).
I'm thinking about and addressing this subject because, for the first time in a long time, a "dead feature" that I left in place caused a bug. It was a silly thing: At one point I had both "Is Approved" and "Is Active" for an invoice system, where "Is Approved" was for a manager to sign off on an invoice, and "Is Active" to act as a soft delete, and in one particular piece of code, it was checking "Is Approved" but not "Is Active." The problem was, the "Is Approved" system had been removed entirely from the UI, but I left the code in place because "we might need it again." It would have taken me less than 15 minutes to put "Is Approved" back in, linked to the UI, and re-tested, but because I never removed it from the system, I missed that one section where it was still being checked and "Is Active" was not. The end result was that in a very rare scenario, an invoice would be floating around, totally invisible to the user, but ready to get billed to the customer. And that is exactly how we discovered the bug, when a nightly billing report showed an end customer getting billed. Luckily for us, this was a rare bug, and it only affected two invoices, which were easily rectified, and the bug was fixed straightaway.
All the same, as a developer who tries to be open minded about constant improvement, it made the point all too clearly: I am no longer in an insane environment, and I no longer need to do insane things as a coping mechanism to defend myself. We had a card in Trello to remove some other unwanted code, and I had backlogged it because "I didn't have time." After this incident, I immediately took ownership of that card and resolved it. It took me 10 minutes, and I feel a lot better knowing that this other unwanted code is gone and not going to cause me any embarrassment in the future.
Justin James is the Lead Architect for Conigent.