Over the last year, I've ended up on four projects that were started prior to my arrival. This isn't uncommon; more often than not throughout any career in development, you'll find that you're spending a lot of time trying to understand someone else's code. It may have been written a few days ago, and it may have been written years ago. The original author may still be on-hand to talk you through it, or they may have moved on. But regardless of the circumstances, you will often find yourself spending time figuring out what a codebase you're looking at is doing, and why.
In a more extreme case recently, I found myself working on a project that had been worked on up until then by two developers, both of whom had been let go (because of budget constraints, not because of the quality of their work, I hasten to add). They had done a great deal of work, but each of them had only worked on one side of the application (one on the front end, one on the back). Regardless of the calibre of these developers, this is a situation that few people would be excited to find themselves in; there were no readme files, no test suites, no code reviews had been carried out at any time, and there was no handover of the project.
After a good few weeks, the project was looking a lot better. Thanks to the archaeology carried out by myself and the fantastic team that I was fortunate enough to be part of, it was documented, there were automated tests, and we had resolved a number of issues that had slipped through the cracks as a result of code reviews not being carried out. But we still shouldn't have been in this position in the first place - and our organisation shouldn't have lost months of (cumulative) development time to this.
And this whole experience made me think a lot more seriously about the code that I write too. And it made me acutely aware of how much we, as developers, end up having to think like a compiler.
Now, that's fine in general - when we're developing new functionality, our brains need to be bent out of shape to consider how the code we're writing will be interpreted - that's part of the job. But when you're looking at a module for the first time, should you have to go through that to understand what that module is doing?
Consider this function (written in Haskell, but the language here isn't what's important), which takes a message and returns a response:
responseFor :: String -> String responseFor message | length (dropWhileEnd isSpace message) == 0 = "Fine. Be that way!" | not (null (filter isAlpha message)) && all isUpper (filter isAlpha message) = "Whoa, chill out!" | isSuffixOf "?" (dropWhileEnd isSpace message) = "Sure." | otherwise = "Whatever."
If you're not familiar with Haskell, you probably just skipped straight over all that, right? I don't blame you; what a mess!
But in my experience of picking up other people's code, it feels that a lot of people end up delivering code like this; people will get their code working, and then move on to the next problem. And that's understandable of course. We've all got deadlines, and project managers, and product owners, and stakeholders. We can't make everything absolutely perfect all of the time. But consider how little time it takes to break out the logic of your functions and make them more readable. Literally a couple of extra minutes of your time could save hours of other people's time when they look at your code next - in most cases the time will be saved immediately when your work goes through a code review.
Consider this very quick revision to the above code snippet:
responseFor :: String -> String responseFor message | isEmpty message = "Fine. Be that way!" | isShouting message = "Whoa, chill out!" | isQuestion message = "Sure." | otherwise = "Whatever."
Obviously I've omitted the actual logic here - although it is basically the same as in the first example - but by replacing it with useful function names, you don't need to see it any more. If you wanted to know what the
responseFor function was doing, you'd be able to tell nice and quickly, unlike in the first example I gave you. You don't have to know that the
isShouting function checks to make sure that there are letters in the message, and then checks to see if they're all uppercase, because you're not a compiler. You just need to know that if the message passed in is shouting, the response will be "Whoa, chill out!".