There comes a point in the project lifecycle that “it works, ship it” is not a priority anymore, or at least, it shouldn’t be.
I could tell you all about Clean Code and how technical debt slows you down the more you accumulate and that it’s a debt that keeps on charging you interest.
Or I could just tell you to check out Uncle Bob’s books or this one masterclass he gave and that basically resumes most of his books and talks.
Here’s a quote from Uncle Bob:
It is more important for code to be changeable than that it work.
Code that does not work, but that is easy to change, can be made to work with minimum effort.
Code that works but that is hard to change will soon not work and be hard to get working again.
My background is in business and I’m comparing code to the product life cycle.
Be it a “normal” or “digital” product, platform, service, or even a feature: it starts, it grows, it matures and finally, it declines.
The earlier stages
While starting, if you’re smart about it, you know you’re doing something that you will throw away after it’s validated, so working is all that matters.
Then again, it’s still small enough that the few heads that know all of it are actually few, present and know all of it.
But once it starts growing and those few heads aren’t there anymore, when more people have to work on it and it grows in a way that even those who know the most only know it as an overview… then you’re probably already in a growth stage.
In the growth stage, you probably don’t want to use code that “magically” works until you add a comment, then it, someway, somehow, breaks. Probably code made in the late (or earlier?) hours of the day either fuelled by caffeine or alcohol. You get the gist of it, right?
If you started it from zero again, using what you learned from the MVP, or if you managed, somehow, to lift up a fence of “don’t touch” around it. Even in this stage, you still want working code more, but you probably should be a little more aware of other aspects along with “it works”.
The latter stages
Declining stage apart, the maturity stage is where most of us will work with.
When I say “working code isn’t a priority”, I’m not even saying to have good architecture, to have X and Y patterns applied, or to squeeze each drop of performance.
I’m talking about if you can understand and change the code and if someone can just drop there and start coding. And this starts somewhere in the growth phase.
Testing is important, at least for the happy and other main paths, the very least you want is… working code. Not the current code, but all the other code you already have.
Linting and code style is something you should already have set, enforced, and forgotten. But a code can follow all the style guides and have no lining errors and yet be awful to read and understand.
The main problem
We all know that when we write something we go from A to B, to F, then U, Z, and finally C.
Some people say “It works, ship it”, only to come back a few days later and utter those meme phrases like “When I wrote it, only God and I knew it. Now… only God knows.” I like memes, but when you’re always living them… then your life is only a joke.
What I believe in, is that sometimes all you need is to read your code again (even before having someone else read it) and refactor it, while it’s all still fresh to you.
From that mess, you can sometimes make it go A → B → C (and sometimes you can even end up cutting some unnecessary steps), it doesn’t need to be the most perfect piece of code, just to make sense to you and anyone reading it, be it today, next week or latter.
The culprit: YouTube Tutorials
If you’re thinking “But this is basic stuff”, yes it is! But some people see their mess and think “Yes, this is good” and ship it. I blame tutorials for that.
There’s no time and no one would watch people debugging stuff for hours. So, they usually just show you starting at A and “logically” going to B and then as a matter of fact going to C. The better ones do one thing at a time, jumping up and down and adding stuff, with others basically “thinking”: “We will, of course, need all of this” at the start, and then proceeding from top to bottom copying of what’s on their second screen.
The solution: relentless refactoring
My memory for the implementation details of whatever I do is awful, I know that next week the chance of me knowing exactly what’s going on somewhere is basically none, so, I have to read the code.
And if today, I’ll do something that seems clear to me. Then next week when I go over the file again and have to “waste” time studying the code in order to get what’s happening, then, instead of leaving it to the next one to also waste time understanding it, I’ll relentlessly refactor it and comment it in a way the next person will have a better context and written code to be able to work on it.
Conclusion
Zen Buddhism has the concept of “Shoshin” or “Beginner’s mind”. If you approach the code with that, you can, every time make it better.
So, when we are seldom working with starting projects, it might be hard to see where “Shoshin” applies, but when you think of it as for each feature, or even for each time you open a file in the legacy of the project, then the more you feel the need.
Legacy code is a little of a loaded term, people always think of it as something bad, but I worked a lot with legacy projects and it’s easy to see pieces where it was actually cared about and places made with the “it works, ship it” mentality.
Can you guess which ones are better to understand and to work with?
So, what kind of legacy code are you leaving behind?
Cover Photo by Marvin Meyer on Unsplash