“Your code is your understanding of the problem made manifest.”
Looking back at some of the code I’ve written in the few years on my experience, I often find one of the below things : either it still works untouched and has since become a critical part of the solution or it’s become a fragile mess no one dares refactor. Sometimes it works just right and doesnot need any change although at times it’s an old relic that defines the old ways and assumptions I had. Each single piece of code has a history and it’s own life of how it evolved and mutated through it’s history of existence.
But, what separates the best from the rest often lies in the engineering practices that shaped the code - not the language, not the framework, not even the domain but the desgin thinking behind it. This post is me trying to collect those ideas and practices so that I can come back to them when I need to center myself.
Albert Einstein defined five ascending levels of cognitive prowess: Smart, Intelligent, Brilliant, Genius and Simple. “Good code is simple code” – Code Complete, Steve McConnell.
Every capable developer can come up with a complex solution to an easy problem. Any good or smart developer can come up with complex solution to a complex problem. But it takes an especially brilliant mind to come with a simple solution to a complex problem. Always, strive for simplicity be it in system design, writting your code or documenting the same. Code that’s too clever for it’s own good is fragile by default. It’s hard to test, harder to extend and easy to break. Maybe it looks good on a resume or helps you put those leetcode hours to good use. But will come back to haunt you when you have to debug the deadlock condition between the two channels in the thread and will lead you to rethink the meaning of your life. Choose clarity over optimization it may look you are in late 60s while the world have moved over but such code will let you sleep better and won’t be the cause of High BP for you or your boss.
“Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.” - The Pragmatic Programmer.
I find this is often the least used or understood principal if any. For a long time I used to think less lines of code means less things to maintain and is hence good. After bashing my head on lambdas, nested and convoluted map reduces and filter I have learned my lesson. It’s not about lines of code but the information that it carries. If I find there’s two sections which duplicate the knowledge that’s the liability. This can be anything including Infrastructure as code, documentation, configs etc .. Be succint, make sure there’s no duplication but also be verbose enough to not kill the message.
“Things that are orthoginal are independent of or no-overlapping.”
The Pragmatic Programmer book teaches this lesson pretty well with the example of the Helicoper Controls. The more different modules depend on each other the more likely one change causes a domino effect of breaking the entire code. This has more often than not left me thinking about life and what I have been doing debugging the code at the middle of the night. Always, Always make sure to have minimal dependencies, separate concerns between the different modules.
This one has the highest chances of going wrong when you are starting a project and need to iterate quickly. Unless you have worked through a few of such projects that quickly gets moved to production from the POC phase, it’s hard to see when such depdencies creep in. You become overwhlemed when your side-project which you started as a hobby and creative outlet suddenly grabs the attention of higherups and now have to be shipped to be used by actual clients and make money.
There’s hardly anytime to fix it forget about rewriting, you’d written it for just yourself but now there’s less than a week to ship it for atleast a few thousands. This is where you’d remember if I had just written it in a way things are orthogonal, I could refactor this modules one by one overtime and make the project into a relible and functioning system that it is now destined to be.
“Tracer bullets let you home in on your target by trying and seeing how close you get.”
It’s immpracticle to think you’d get everything right the first time. Thus, rather than building the whole system perfectly the first time, build thin slices end-to-end. This helps you think if the architecture or your framework would hold good for the problem you have. Not every new shiny architecture suits everything. Monolith still works in places where coupling is needed and often suits to halt the entire system, you’d never be able to get a microservices architecture work in such a highly coupled system even though it may seem to work.
Trying and iterating over ideas help you think and see the issues which paper and pen wouldn’t accomplish. But, that’s only true when you are okay with building quickly and throwing away things that donot work ruthlessly rather than sticking to it just because you wrote it.
“Don’t live with Broken Windows.” – The Pragmatic Programmer.
Tiny design issues, tests left incomplete compund into bigger ones. That messy interface you meant to clean up ? It becomes the pattern everyone copies. Small, frequent refactoring keeps your codebase in a shape where change is easy and not painful. Think about this as your monthly trip to Barber, you need that trim to keep up appereacnces look sharp and presentable so does your code. After all your is a reflection of you.
“Write it down or lose it forever.”
In my part of the world, there’s a joke that keeps on circulating every few years. It goes like this : A year ago I wrote that code, then it was only me and the god who knew how it worked or why, now it’s just the god who do. Capturing not just the what but the whys helps a long way when you have to explain the system to a new joiner who would tilt his/her head when you go through a not so obvious part of the system. Every such decision every such detour has a story to tell and this story is worth documenting not just for the new joiner but the future you.
Formally it’s the spirit behind the ADRs (Architectural Decision Records), although these need not be formal but a casual reminder of the battle which was once waged between the multiple choices and constraints the team faced and what was done to solve the problem. It serves as the history lesson on what was done, why it was done and maybe help you Identify what could be done better the next time you are in same situation.
“It’s easy to get caught up in the hype - harder to maintain the mess it can create.” “Don’t be a slave to tools” – The Pragmatic Programmer.
There’s always a hot new framework, database, technology or language taht promises better performance or developer experience. But mature engineering isn’t about chasing trends that look good on your resume - it’s about making deliberate, sustainable decisions. Every new tool adds surface area for bugs, onboarding, maintenance and integration complexities. It may not be bad but it should have a clear reasoning and justified benefit that overwhelms the issues that it could bring. Don’t ever give in just because my competition is doing it I should too. Always ask yourself :
“Premature scaling is teh root of all architecture regret.”
It’s tempting to mimic the systems of Big Tech companies especially when you often cram the system designs and case studies for such while you are preparing for interviews. You are expected to know every bit of jargon and architecure decisions to take when there’s a millions of concurrent users hitting your application like a crazy hornet. How to achieve the 9, 9s of the availibity and build for high performance even when Internet goes down.
But here’s the reality : You are not operating at that scale. Not yet.
Overengineering is one of the fastest ways to make your codebase brittle and your team frustrated. Simpler systems are easier to reason about, easier to change and much faster to build. Always :
Robust, long-lived and extensible code doesn’t come from buzzwords or frameworks. It comes from thoughful engineering.