That Code’s Not Dead — It Went To a Farm Upstate… And You’re Paying For It
Editorial Note: I originally wrote this post for the NDepend blog. Head over there and check out the original, if you’re so inclined. I encourage you to go give the NDepend blog a read, in general.
When it comes to pets, there’s a heartbreaking lie that parents often tell little children when they believe that those children are not yet ready to wrap their heads around the concept of death. “Rex went to a nice farm in the countryside where he can run and play with all of the other animals all day!” In this fantasy, Rex the dog isn’t dead — he lives on in perpetuity.
Memoirs of a Dead Method
In the source code of an application, you can witness a similar lie, but in the other direction. Code lives on indefinitely, actively participating in the fate of an application, and yet we call it “dead.” I know this because I’ve lived it. Let me explain.
You see, I’m a method in a codebase — probably one that would be familiar to you. My name is GetCustomerById(int id) and I hail from a class called CustomerDaoMySqlImpl that implements the interface ICustomerDao.
I was born into this world during a time of both promise and tumult — a time when the application architects were not sure whether the application would be using SQL Server or MySQL. To hedge their bets, they mandated data access interfaces and had developers do a bit of prototyping with both tools. And so I came into this world, my destiny taking a single integer and using MySQL to turn that integer into a customer.
I was well suited to this task. My code was small, focused, and compact, and I performed ably even to the point of gracefully handling exceptions in the unlikely even that such would occur. In the early days life was good. I fetched customers on development machines from unit tests and from application code, and I starred for a time on the staging server.
But then my life was cut tragically short — I was ‘killed.’ The application architects proclaimed that, from this day forward, SQL Server was the database of choice for the team. Of course, neither my parent class nor any of the methods in it were actually removed from the codebase. We were left hanging around, “just in case,” but still, we were dead. CustomerDaoMySqlImpl was instantiated only in the unit test suite and never in the application source code. We would never shine in staging again, let alone production. My days of gamely turning integers into customers with the help of a MySQL driver were over.
But I learned that ‘dead’ was not as bad as it sounded. People talk about “dead code” as if nobody would ever look at me or bother with me again, but I would come to learn that being dead wasn’t half bad, and it certainly didn’t mean oblivion.
At first, nothing much happened, but after a while, I started popping up occasionally in developers’ IDEs. They’d do a text search for “GetCustomer*” and then click on me in the results. Of course, I wasn’t what they were looking for because no one was using MySQL, but, hey, it was nice to get a little attention in spite of being dead.
Then, something exciting happened! One day a developer navigated to me by mistake, but didn’t like something about my implementation. So he actually spent the time and energy to do a well-executed refactoring, making sure that all automated tests continued to pass. I was dead, but someone was doing actual maintenance on me.
It turned out this was actually pretty common. There was the big refactoring where the Customer ID field was changed from an integer to a long, and then another one later where it became a GUID. My interface changed, and so, of course, did I. But that wasn’t the only action I saw. There was The Great Logger Implementation of ’12, an exciting period when developers dutifully cracked open literally every method in the data access assembly and manually added logging calls. That was followed by The Great AOP Refactoring of ’13, when the logging code was removed from me for a much cleaner choice.
Of course, those were just some major events I can think of. I can’t tell you how many little things there were. It was exciting to be part of the code coverage analysis, the average method size report, and all sorts of other static analysis concerns. In fact, there was a time I got tweaked a bit to eliminate a StyleCop warning. But even when that wasn’t happening, it was just gratifying to be commented, documented, reviewed, and peered at by new people on-boarding. I didn’t even feel offended when people would say things like, “I thought we weren’t using MySQL” or “why are we even looking at this when it’s obviously dead code?”
It would have been hard to be too offended, after all. Think of what people say about methods that aren’t dead. They grow and rot sometimes, and people are afraid to touch them. And, worst of all, they create production defects. Developers literally curse their names. Nobody ever curses my name.
At times, I think it’s amazing that I’ve slipped under the radar for so long. After all, there are dead code detectors out there. But then I remember that this application uses and IoC container configured by XML and that I actually am used, technically, in a few unit tests. And I’m thankful.
It’s sad when a pet dies and a parent tells a child that the pet will be living on a nice farm upstate. But it’s awesome when a piece of code dies, because it actually does get to live on a nice farm upstate, so to speak. The life of dead code is pretty sweet.
The Real Cost of Dead Code
I think I did a decent job anthropomorphizing a method. If you were code, being dead code would be a pretty sweet deal. But if you’re part of a software development group, dead code is actually a terrible deal.
We have a tendency to equate dead code with clutter stuffed into a closet. It’s not ideal, but whatever — it’s out of the way and not hurting anything. But in looking at things this way, we miss the countless small costs incurred by carrying around that dead code.
Every line of code in the codebase is a liability. Every line of code can come up during a search, presenting a red herring to a developer. Every line of code can get swept into some cross cutting initiative or to some generalized cleanup. Every line of code counts when you’re running analysis on a codebase. Dead code sits there, doing nothing for you, and throwing off your results. It wastes everyone’s time over and over and over again. It’s not harmless — it’s dragging you down.
Do yourself a favor. Spend some time doing a deep analysis of your code base, looking for dead code. And don’t let it sit there, leaching your team’s productivity. Don’t keep paying for its stay at a luxury farm upstate. Just get rid of it.