What does bad code look like? Well, code that does not do what it should is probably bad by default. Not much else to say about this one.
Beyond that, it is probably easier to think of bad code in terms of what it feels like. Most of the bad code I’ve seen tends to fall into one of three categories.
Easy to understand, difficult to change
Working with this kind of code initially feels pleasant, but could quickly devolve into a terrifying and never-ending game of Jenga. Code like this is common among new programmers and could actually be useful in some contexts. In search of growth and perfection, too many software engineers eventually lose their tactical ability to write this kind of “bad” code.
Difficult to understand, but easy to change once you get around to understanding it
Working with this kind of code feels like a constantly swirling mix of confusion, surprise, and sudden enlightenment. This kind of code is common among experienced software engineers who have their heads full of useful principles, design patterns, and other “best practices”. I’ve had to fight my way out of writing this kind of code more times than I can count.
Difficult to understand, difficult to change
This is just the worst! Avoid like the plague.
This kind of code feels like a terrifying nightmare that continues when you wake up and when you go back to sleep. I’m not sure how one ends up here, but this is certainly not what you want your code to feel like for anyone who touches it.
You’ll probably end up with this kind of code when you apply design patterns, design principles, programming paradigms, and/or complex architectures without understanding why these things exist and when to use them.
One of the most elusive aspects of your job as a software engineer is to figure out how to produce code that is both easy to change and easy to understand. Producing such code is not easy, but it is typically the best way to build software that retains its value over time.