RizTech Academy logo
RizTech Academy
Software EngineeringLeadershipAdvice

Thirteen Years of Building Software: The Lessons That Actually Stuck

After 13+ years shipping production software and leading teams, a handful of lessons have earned their keep over and over. These are the ones I'd hand a younger version of myself — and the ones I teach now.

RHRizwanul Haque 4 October 2026 4 min read
Thirteen Years of Building Software: The Lessons That Actually Stuck

I have been building software for more than thirteen years — shipping products, leading teams, and making roughly every mistake available to make. A few lessons have survived all of it. Not trends, not frameworks, but principles that kept being true across languages, companies and decades. These are the ones I would give a younger version of myself, and the ones I now teach.

The database is where correctness lives, not the application

Early on, I "checked if the seat was free, then booked it" in application code, and could not understand why two users occasionally got the same seat. The answer is that between the check and the book, another request slips in. Application-level checks are a race; the window is small, but at scale small windows open constantly.

The fix is not more careful application code. It is pushing the guarantee down to the database, where it can be enforced atomically:

UNIQUE (show_id, seat_id)   -- on the bookings table

Now a second attempt to claim a taken seat does not get past a careful if — it violates a constraint and the database rejects it, for every code path, forever, even under true concurrency. The lesson generalises: for anything that must be true, ask the layer that can actually guarantee it. Hope is not a concurrency strategy.

Simple is the hard skill

The most expensive code I have ever met was clever. It was admired when it was written and cursed for years afterwards, because every change meant first decoding the cleverness, then praying.

It took me a long time to understand that writing code so plain it looks obvious is far harder — and far more valuable — than writing code that looks smart. Obvious code is read correctly on the first pass. It is changed without fear. It onboards new people in hours instead of weeks. When I review code now, "could this be simpler?" is the question I ask most, and "wow, clever" is usually a warning, not a compliment.

Name things for the person who reads them next

That person is frequently you, six months from now, with no memory of what you were thinking. A good name is the cheapest documentation there is and the only kind that cannot drift out of date, because it sits on the thing it describes.

availableSeats tells the reader everything without them opening the function. calc2 tells them nothing and forces them in. Multiply that across a codebase and naming stops being cosmetic — it becomes the difference between a system people can reason about and one they are afraid of.

Make it work, then make it fast — and usually stop

A great deal of effort is spent optimising things that were never slow, often at the cost of clarity. The honest sequence is: make it correct, make it clear, and only then — if a real measurement says so — make it fast.

Most performance problems are not exotic. They are a loop inside a loop over data that grew, or a query run once per row instead of once. You find those by measuring, not guessing, and you fix them by addressing the actual cause rather than adding capacity to paper over it. Throwing hardware at a bad query is the expensive habit; fixing the query is usually free. Cost discipline is an engineering skill, not an afterthought.

Tests are what let you change things without fear

I used to think tests were for catching bugs. They do, but that undersells them. Their real value shows up a year later, when the system has to change and you are no longer sure what might break. A good test suite turns "I'm scared to touch this" into "let me change it and see what goes red." That confidence is the thing that keeps a codebase alive instead of ossifying into something nobody dares edit.

So I test the behaviour that matters, especially the edges — the empty list, the duplicate, the concurrent request — because those are exactly the cases that fail quietly in production at the worst possible moment.

The person who can read code can fix anything

I have written about this separately, but it belongs on any honest list. On a real job you read far more code than you write — other people's, your own from long ago, systems with no one left to ask. The engineers I trust most are not the fastest typists. They are the ones who can walk into unfamiliar code, trace one thread through it, and understand it well enough to change it safely. That skill scales to problems no individual could have written alone.

Mentoring made me better, not slower

For a long time I treated helping others as time taken away from my own work. I had it backwards. Explaining something forces you to understand it properly — the vague bits you had been getting away with suddenly have to be made precise. Nearly everything I understand deeply, I understand because I had to explain it to someone. That realisation is a large part of why I now spend my time teaching, and why RizTech Academy exists at all.

Why I'm writing this down

None of these lessons are complicated. That is the point — the things that actually matter in this craft tend to be simple to state and hard to live by consistently. Thirteen years did not teach me more syntax; it taught me judgment about which problems are worth solving, when simple beats clever, where correctness has to be guaranteed, and how to leave work the next person can build on.

That judgment is what I try to pass on in every course and every mentoring session. If you take one thing from this: stop trying to look clever, and start trying to be clear. The rest tends to follow.

Frequently asked questions

What separates a senior engineer from a junior one?+

Not how much syntax they know. It's judgment — knowing which problems are worth solving, when simple beats clever, where correctness must be guaranteed rather than hoped for, and how to leave code the next person can understand. Seniority is mostly good decisions made consistently under real constraints.

Is writing clever code a good thing?+

Rarely. Clever code is expensive to read, risky to change, and usually exists to impress rather than to serve. The hard skill is writing code so clear it looks obvious. Obvious code is the real achievement; most cleverness is a cost the whole team pays later.

How important is testing in real-world software?+

Essential, but not for the reason people say. Tests are less about catching today's bug and more about letting you change the system a year from now without fear. A codebase you can change confidently is worth far more than one that happened to be correct on the day it shipped.

RH

Written by Rizwanul Haque

Software engineer with 13+ years in the industry, and the founder of RizTech Academy — a free tech-education initiative offering in-depth courses and mentorship, open to everyone.

Want to learn this properly?

The free courses take you from the basics to real, working software — no sign-up, no fees.