Maintaining bad code is in a lot of ways harder than creating good code. Or at least, a person good at one of those things might not be good at the other.
I have a related theory that software development as a profession is starting to increasingly resemble being an air-traffic controller; as the actual programming parts get easier (languages, tools, and libraries get better, awful code-bases notwithstanding), the non-programming tasks tend to take up more and more time. So, you end up spending a lot more time talking to people and figuring out what to build.
When we go into the world of unsolved problems that someone solved and we have to maintain them, and we can't understand them immediately, we call them bad. It's my gut reaction almost every time I'm confronted with something that doesn't immediately enlighten me, even thought I know it's the wrong reaction.
We are always comparing everything to the simplest and most solved problems that were easy for us to understand. When it isn't so easy we call them "bad".
That happens in code all the time. People do things in ways that are prone to problems because either they don't have the experience to know better, or they didn't take the time to think about the domain. I would call that "bad code", no matter how pretty it looks or understandable it is.
Part of the problem is that "good" and "bad" are far too vague, so everyone will bring their own meaning. You might see people using "bad" to mean unclear, but I would count that as a sign of progress. A imagine a "bad" mechanical in this day and age engineer is someone that does stuff that costs more money, either now or later when it breaks early, but still produces mostly safe constructs because that portion of the job is highly constrained, and when they fail there, they often aren't just "bad", but may be criminally negligent if they failed to adhere to both the law and industry best practices.
If were getting to the stage that "bad" programmers are just ones that write unclear code, that's a huge step up. Unfortunately, I don't think we are there.
I don't believe in this world of unsolved problems. Most codebases reinvent the wheel like they've never seen one. Most "problems" are just a problem of picking one from known solutions and gluing it all together. People don't always pick the right solution, or they start gluing at the wrong place and won't stop once they realize it, so the end result is a mess. And then you can ask, why did they do it like this? This is not good!
If you're a programmer, you've hopefully tried to rewrite some bit of code of yours a few times until you've arrived at something that eliminates redundant logic, is more readable and less buggy than the previous versions.. don't tell me they're all just equally bad?
I have written all sorts of implementations for things that I'm positive there's a library or existing example out there that is just plain better and more thorough.
The problem is, I don't know what it is. I don't know where it is. And finding it will take time, take effort to evaluate the non-good implementations, and take effort to integrate with other systems.
Whereas I can write code now which is "good enough" (or worse, just not good at all but exists and does something right now) and then move on and hope I'll find the "better" I'm looking for later.
Experience teaches you how to adjust for the right spot on the spectrum between "build for business value" and "build for maintainability."
Isn't that funny. Get the inexperienced folk to churn out features so the experienced folk can enjoy the nightmare of perpetually repairing the monster.
But oh man, when you actually do write that one function that does the cool thing in a neat way and fits into the other crap you're wading around in without breaking anything in a way that makes intuitive sense... man, does that feel nice.
And sometimes when it comes to this I feel bad and somewhat guilty. But I can't restructure the whole trash pile and orders and budget constraints and all that, so it just has to keep growing and we shore it up where we can until it starts collapsing around the base and then maybe we can admit it was a trash pile all along and try to do better next time.
Great comment. This also happens as someone moves up in responsibility.
Also of note, I think good code is like a good plan. It's great, until it gets punched in the face. The reality is that most code is written to address constantly changing requirements with a slew of unknown unknowns. And while there certainly is a range from bad to good, what most people say is good will eventually give way to reality of constant change. The best we can do is maintain some semblance of good in this reality. I'm reminded of this excerpt from Musashi:
“What a fool I’ve been,” he exclaimed aloud. “I tried to make the water flow where I thought it should and force the dirt to stay where I thought it ought to be. But it didn’t work. How could it? Water’s water, dirt’s dirt. I can’t change their nature. What I’ve got to do is learn to be a servant to the water and a protector of the land.”
My Dad used to be an ATC and he always told me that he actually has fun doing it and loves his job. When I was little I was unable to comprehend how one can enjoy being in such a pressure situation. But now as I am older it makes more sense, as now whenever we are near a major release the pressure is still pretty high but I enjoy writing code and deliverying features too. Even if the code base is really annoying and the architecture of the platform makes me pull my hair out. It still is super satisfying to successfully do a release or when you fix that pesky bug. :)
Oh man, this really resonates with me. So much of my work time is spent manipulating the yak stack it's crazy. The feeling when you can just crank out some code with no external speedbumps is magical though.
I didn't expect someone to read that as a historical detail as opposed to a point about the type of mental context switching high school students do.
I'm not that far out of my mental prime, I'm just far enough that I'm noticing it.
But that's beside the point, this isn't a contest for who is older, I'm trying to point out that the work adults do is often less friendly to multitasking, and getting older doesn't help.
I‘ve started using a copy-paste history tool, and pretty sure it reduced stress and memory pressure considerably. I can just go back after half an hour and see the code snippets I might else have had to remember.
Creating calendar events with notifications - same thing. I just don’t have to remember most events because the phone will nag me about them, but paradoxically I now remember them easier.
Also, perhaps your sleep is not restorative since your kid was born? On the one hand, as a parent you get a little alert kit installed by nature, perhaps leading to lighter sleep. On the other hand, low oxygen in the sleeping room can be a thing, with multiple people sleeping there - I have way more dream call since opening the window just a little bit (just rotating the handle without actually opening).
So, you got plenty done.
As you say, "It's complicated in a way that teenage me never really had to deal with". And that's really the nub of it. Not all complexity is reducible. But many of us can't escape the notion (perhaps an evolutionary drive?) that "there's gotta be a simpler way". To your example, if you hadn't unwound those hidden dependencies, perhaps you would have experienced more severe consequences at the wrong end of the process. So well done you for clearing your path.
I see this kind of distraction as introducing complication. When I was in high school about all I could do was listen to the radio on my boom box and even that was using too distracting.
Maybe another way to say it is that in high school math problems fit into a small enough chunk of memory that you could store it to disk and load it back into working memory in a few minutes.
On the other hand, I literally can't fit my current work project into working memory. It's just too big. I have to page it to stored notes. At the end of the day, I write to myself where I need to pick up the next day, and then the next day I spend 20 minutes following my notes to load that context back into working memory.
I don't think I'm bad at this stuff either, because my solo side projects don't have this problem. I can pick those up for an hour at a time and it's fine. But my work projects...
I suppose that’s because I insist on understanding more of the tech stack for my personal projects than I do for my work projects.
But the second is that everything is more complicated. In high school, you could just sit down and crank out some homework while watching Youtube videos and chatting with friends. And you would just sit down and crank out some homework.
Yesterday, I got into work thinking I was going to write some code, and... oh wait, this depends on chasing down an issue in code owned by someone else, and I need to get answers to some questions about how this other component works that I depend on, and this other piece of code I need to modify doesn't actually work the way I thought it did. Even within the same task, I'm constantly context switching between mental modeling, communicating with other people, and code reading/writing. Also, I'm reconciling all of this against a multi-stage rollout plan where different people will see different behaviors. It's complicated in a way that teenage me never really had to deal with.
It's no wonder I've spent several days feeling like I got nothing done. I did a lot of unwinding hidden dependencies, but very little of it was actually writing code. Most of my time was spent figuring out what questions were the right ones to ask in order to get the answers I needed, which might not end up being what I thought I needed.
Teenage me never had to deal with that kind of complexity.