Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
- Martin Golding
Here are 6 coding practices that I've adopted in the past 10 years to ensure that my future self has fewer sins to forgive.
1. Standardize code formatting
Any codebase is read a lot more than it is written. Code with consistent formatting is easily readable and comprehensible for everyone in the team. Standard formatting ensures that your eye, and your subconscious, can look for variables, braces, functions, etc seamlessly. Golang does a great job by providing the gofmt command in the standard library. This ended all formatting discussions that come up so often in code reviews in the Golang community.
2. Don't follow the DRY principle blindly
DRY (Don't Repeat Yourself) is almost a mantra for developers. But if applied indiscriminately, it leads to abstract code that’s hard to read & understand. It also stops different parts of the code to evolve to their full potential. Do not follow the DRY principle blindly.
It is a good idea to copy-paste the same function a minimum two times in the codebase. Only when you see the same requirement a third time, should you refactor the code and apply DRY. Doing this ensures that you are not prematurely assuming that two problems that looked the same initially, are still going to remain the same after a period of time. When you come across a similar requirement a third time, you have some data on what parts of the code are common. You also have three instances of repeated code to create a good abstraction.
3. Debug code via logs
Practice debugging code on your local machine via logs instead of a debugger. Debugging on your local machine ensures that logs are added at the right place. This, in turn, makes sure that you can debug production issues quickly because you would have gone through this cycle on your local machine before. Remember to not get too excited and add unnecessary logs everywhere. It will clutter your log file in production.
Too much logging == no logging.
4. Beware of premature optimizations
A primary goal of code optimisation is to improve performance. More often than not, performance issues are not where you think they are. Always benchmark your code before starting to optimize for performance. Without benchmarking, how will you ever know whether the code changes you make have any real impact on efficiency or not? Premature optimization, especially micro-optimization, is not a good idea because you don’t know whether you are working on removing a performance bottle-neck or not.
As a corollary, this doesn't give you the license to code like the wild west. Don't get the computer to do work that it doesn’t need to do just because you got lazy and didn't think of the most efficient way of solving a problem.
5. Don't complicate your codebase with unnecessary features
Don’t complicate the codebase with features that no user has asked for. This is a problem you need to avoid in early product lifecycles. Startup teams tend to assume that building more features will help them find product-market fit faster. This is an anti-pattern. Adding unnecessary features makes the code harder to read & debug. When new developers come on board, they will find it difficult to differentiate important code paths from the ones that were added on a whim. Eventually this technical debt slows the entire team down.
6. Setup a CI/CD pipeline early in the development lifecycle
Even if it’s a one-wo/man show, a CI/CD pipeline reduces the overhead of remembering (& doing) the build & deployment of a particular codebase. The common assumption is that CI/CD pipelines are important only in teams that are pushing a lot of code into production every day. In my experience, CI/CD pipelines are even more important for codebases that are rarely touched because you won’t remember how & where the code was deployed. This is especially true if you are updating the code only once a year. Plus, having a CI/CD pipeline ensures that you have a version-controlled script telling you exactly what you were thinking X months ago.
What other practices have you followed to prevent your future self from hanging themselves? 😜
I share TL;DR versions of articles on software engineering that I read every weekday through my newsletter - in.snippets(). Sign up here if you want to learn something relevant every day.
Oldest comments (78)
Nice post - definitely agree.
You mention
gofmtfor go (which is great); and for JS I'd recommendprettier: github.com/prettier/prettier , especially on teams. It allows the automatic code formatter to be the "bad guy", instead of having to talk about style during code reviews :)Also definitely agree with number 4 - premature optimizations can kill code quality years later. It's always a terrible feeling when you get into an old codebase and realize that it's 4 levels of abstraction deep and you can't figure out what anything is doing :)
Rustfmtfor rust.We use
prettiervery heavily in our team and that has definitely reduced the number of bike-shedding arguments internally. I think more and more languages are realizing the importance of this and baking it into the standard library instead of an external library.Love the quote you started with! Personally, I have this as a mantra:
When you write code, think about the poor bastard that's going to have to maintain it six months from now. It most likely be you.
Also, A solid set of rules.
I think that's a more accurate mantra. Be kind to your future self :)
Another one here that had to laugh out when reading the quote. I forwarded it to my group of fellow-programmers. Oh and btw, love the set of practices
Don't write stupid comments on code, but write comments.
I should add "do not write in comment what you could have write in code".
That include the name of function/variables, the types (if it's a typed language that is), the exception that can occur, any optional result, constant arguments.. etc...
Couldn't agree more. Comments should describe the "Why" and not the "How". The "How" is already present in code.
Couldn't agree more. Was guilty of this before. Now I just duplicate first, often times more than three occurences and before refactoring and making them DRY.
You should go WET (write everything twice) first.
As always, do not follow that one blindly too.
I'm more biased towards MOIST these days. Walking that thin line between DRY & WET 😜
MOIST? Please enlighten me :p
Not too DRY, not too WET; just moist :)
My Own Interpretation of Some Things 😉
"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
Wiser words have never been spoken. But your write-up comes pretty close.
Thanks 🙌
Thank you so much. Glad you found it useful.
I'm guilty of the 4. Especially combined with 2. And 5.
Optimizing and trying to get 4 or 5 things done in a "clever" function has been the bane of me.
Then I had to scrap it as the client didn't ask for that (even if I thought we would like it and it would be nice).
But I'm learning... I hope.
WET: Write Everything Twice! 😜
These days, I follow MOIST. Not too DRY, not too WET. :)
Finally, five pieces of advice I can actually agree with.
💯
Thank you! Btw, which one didn't you agree with? 😜
Great post!
Thank you. Glad you found it useful!
I love that quote and frequently use it with my juniors. :)
Internally I like to add that, that sociopath is me, because that’s how I feel when I look at my old code...
Haha ... each time I look at my old code, I think "I don't think I'd be good friends with my past self. That guy was an idiot." :D
Some comments may only be visible to logged-in visitors. Sign in to view all comments.