The Joy of Removing Code

There's a story about James Joyce's infamously gargantuan book, Ulysses. It is probably considered the pinnacle of his stream-of-consciousness style where language is obscured and plot is meandering to achieve the affect of reading through someone's daydream. It's akin to the way impressionist painters use the medium of brush strokes to add a layer of sensation to the subject of their art. The length of the book compounded with this elevated style makes it incredibly foreboding even for academics.

Virginia Woolf, no stranger to this style herself, had harsh criticisms of Ulysses saying, "Never did a book so bore me." Yet the story goes that Joyce's original manuscript was ten times longer than the final book and contained apparently thousands of errors. No matter the arguable position Ulysses might hold in the literary canon, it's at least a testament to the power of editing.

With programming, the skill of editing is really just as important as writing actual code. That means you sometimes even have to remove code which can be counterintuitive. This post enumerates some of those things you might want to remove from your code and why you'd want to even do that.

Isolate Non-Project Code

There isn't an experienced programmer who doesn't already appreciate the use of modules for encapsulating and isolating logic. It is a very important skill to know where and how to split your code into modules.

For me, one of the greatest things you can do, when possible, is create modules that have absolutely nothing to do with your project. You're still going to pull in these modules and use them, but they are so far removed from how your project works that you could maybe even give them their own repository or open their source as a public project.

Reduce complexity in your code

This gives you a very nice way to isolate the complexity of your project drastically reducing the overall scope of what your actual program needs to do on its own. For example, date and time functionality hardly ever comes out of the standard library box ready to go with everything you need. Maybe you have to handle obscure date formats or maybe you just need simple shortcuts to complex functions. It would be unfortunate to litter this handling throughout your project. Less worse, but still not any more useful, would be to just handle all of this in some globally available functions. At that point, just move it into a module. Or even better, take it out of your project completely and put it into it's own package.

Lock out third-party libraries

It's also a nice way to handle dependencies. Each third-party library you lean on comes with the risk that someday it won't update the right way or some change may get introduced that breaks your code. By isolating the ways third-party code impacts your own code, you can much more easily handle this risk and will possibly have reduced the overall surface area of that risk. I will even go so far as to even make sure my primary project code no longer even directly uses those third-party dependencies. The penalty here is that you may need to introduce new abstractions and, yes, more code than the original implementation to really put a buffer between your project and the dependency. The benefit, however, is that you know that there isn't code in there that isn't 100% relevant to your project.

Focus on the non-project code

This code you are taking out of your project is messy. That's why you don't want it showing up in the nooks and crannies of your business logic. The benefit of isolating it into its own module is that it forces you to really consider the right level of access into this module, exposing only the key parts of what it does. It also gives you the chance to test it on its own terms. So what was a generalized weakness in your code could eventually become a solid entity that you no longer need to think about.

Make your code about the business logic and only the business logic

Project-specific code is the primary reason you are programming something in the first place. If your client could just use out-of-the-box software, they would have done it already. It's your client's special needs that are driving your code and we all know that clients needs change rapidly and frequently. You may never get rid of the business logic in your program, but you're going to want to keep it is as small and clear as possible. That starts with isolating everything unrelated to that business logic away from it.

Your Code is Not Set in Stone

When you work hard on something, it can be particularly difficult to see that work thrown in the garbage. There are many reasons we may need to change the code: new requirements come in, performance is not good enough, dependency evolution, etc. It's going to happen. Just accept it and move on. Even with careful planning and discussion, there is sometimes the inevitable chance that the code you built is not the right implementation anymore. Or in early projects, you may only get a clearer picture of what the architecture of your program needs to be after having built half of it already.

Getting past this emotional barrier of being tied to the code you write is difficult, but it's also freeing. It can be very confining to step around the main problem, your code, in order to finish out the project. If it was someone else's code, would you treat it differently? If someone else was stepping around your code, how would you feel if they ripped out your implementation? It's really just not a fun game to be playing wearing your heart on your code like that all the time. The endgame is really to find the right solution for the problem and to be objective about the code.

A lot of beginner coders feel like they've earned a badge after tackling a tough problem and they did. Fair enough. But they don't lose that badge when someone finds a better way to solve that problem. Especially if that person is them.

Working Code Only

In those slow evolving projects where requirements come trickling in like water down a stalactite, partial implementations seem to linger throughout the codebase. The "what ifs" and "we might" functions that are ready to go "just in case" start piling up because half-formed thoughts were uttered in meetings with clients. Clearly, there are a lot of issues with how this process isn't functioning great, but strictly looking at the code and what we can do about it there, you're going to thank yourself down the road if you just leave these half-baked ideas in the documentation and not in your code.

Reading code is a very important skill to have and nothing really loses your trust in some codebase more than tracing through function calls only to find out that none of it actually ever gets called. If you don't want to read code like that, you shouldn't write code like that. Documentation and project tracking tools are where all of those what-ifs belong.

It Becomes a Habit

As you get into the groove of writing lean code with small single-purpose modules, you'll get comfortable with throwing out the stuff you don't need. It also changes the way you write that code in the first place. It's no longer a scratch pad for jotting down ideas or tinkering around until things fall into place. Your effort becomes much more deliberate and intentional. You start to feel an extra weight on your shoulders to have superfluous code lying around. It bugs you. So you delete it. And that brings you joy.