This will seem like the most obvious tip ever, but I thought I’d get it out there for those that may have forgotten about it in a while. If you’ve ran out of ideas on what to work on your project next (i.e. you have no new features or improvements in mind), try going through your codebase and find the oldest pieces of it. (Side note: Having your codebase be in something like a Git repository that can tell you when each line of code was committed and thus last edited can be amazingly helpful.) Chances are you’ve grown since then. You’re a better developer. You have more tricks up your sleeve. Maybe you know of a new algorithm, a new library, a new, better way to do things. Maybe you’ve read about security risks you weren’t aware of. There’s almost definitely going to be something there that could use some tidying up, some improvement.
Look for redundancies, variables or parameters that seemed helpful at the time, but now seem obviously unneeded. Look for opportunities to refactor, to optimize, to parallelize. Look for possible security risks, replace unsafe procedures and methods with safer ones. Maybe try doing a whole piece of code from scratch.
During one of my interviews, one of the tests I was given was to correct the problems in a piece of code that shuffled a deck of cards. The procedure used to do that was so blatantly unoptimized both as far as space and time goes, that I rushed out of the office to find my examiner and ask if I could just rewrite the whole thing. I was told that I would get “bonus points” for writing my own approach to the problem, but I had to consider that maybe I could not do such drastic changes to the code, and had to just correct the code, without affecting the algorithm itself.
Which brings me to a couple of last notes:
– Old code will probably have both incoming and outgoing dependencies that aren’t immediately obvious. Just because the code compiles after your changes, doesn’t mean that everything works as it should. Maybe other parts of your code depended on how things were done before you rewrote the whole thing. So, the bigger the change you make, the more rigorous the testing needs to be afterwards. Keep that always in mind. A program that compiles right isn’t necessarily one that works right.
– Sometimes it’s better, or even required, that you don’t mess with the code too much. You can try to improve things by making slight changes, fixing bugs and doing small optimizations, but rewriting the whole way it works may end up breaking more things than you’re willing/have the time/have the knowledge to fix. So, even though rewriting the whole thing might seem the obvious first choice, think about whether the space and time improvements are worth the complexity of making sure to test everything afterwards. The more rewriting you do on one part of the codebase, the more rewriting you may end up needing to do in other parts of the program to make it compatible with the new way things are done. And that might lead to an “avalanche effect” of changes needed to be done throughout the codebase, at which point you’ll have already regretted applying your bright idea to that old piece of junk.
– Do not fix things by trying to force the program to compile. I remember that my approach to pointers at some point during my first or second year of University was so naive, that I would be adding “&”s and “*”s to function signatures and callers until it “just worked” or “just compiled” apparently correctly, key word being “apparently”. Understand what the compiler means by that error, and take a long hard look at why that piece of code is failing at compile-time. Compile-time errors are the easiest ones to fix. No stack traces to walk through, no crashes with no meaningful error to help either the user or you, just a simple filename and line indication that tells you that that piece of code logic is faulty. So, break it down, and try to fix it. Maybe the error isn’t even right on that line, maybe you’ve made a mistake some way above and that line is merely the trigger of the compiler error. So, correct your errors with as much care as you would write the code the first time. The last line of the first note still stands, “a program that compiles right isn’t necessarily one that works right.“