A letter to every new software engineer about the things nobody told me in my first decade. Not generic advice — specific habits that compound, with receipts from the 15 years of shipping that preceded the writing. If I could go back and hand this to my 22-year-old self starting at the HAKEEM National EHR project in Amman, I would.
One: read the code before you write it
The single highest-leverage habit in your first decade is reading code you didn’t write, in a production codebase, with intent. Not skimming. Actually reading — file by file, function by function, asking “why is this here?” at every branch.
Every senior engineer I respect has a version of this habit. It sounds obvious. It’s the first thing juniors skip, because reading feels less productive than writing. It isn’t. Writing without having read will make you reinvent functions that already exist in the codebase, invent abstractions that conflict with established ones, and propose designs that violate constraints the original authors encoded in the code’s shape.
Budget a full week, in your first month at any new codebase, for doing nothing but reading. Your manager will think you’re not producing. Three months later, your output will be dramatically better than peers who skipped this. Compound interest.
Two: write down what you learn
Every codebase has invariants that aren’t documented. Every team has conventions that live in three people’s heads. Every production system has weird edges that were learned the hard way during incidents.
Write them down as you find them. Not in a private file — in the shared knowledge store (the repo’s docs, the team wiki, the README of the specific module). The writing forces you to articulate what you learned, which surfaces things you didn’t actually understand. It also means the next person can skip the week you just spent.
I’ll say the vain part: you build a reputation as a helpful engineer faster by documenting than by shipping. Ship AND document and you’re building a career. Ship without documenting and you’re just producing tickets.
Three: the one-hour rule for asking
If you’re stuck for an hour, ask. Not three hours. One.
Every senior engineer has been there: you stared at a screen for half a day, made no progress, and then someone spent 30 seconds answering your question. That half-day was wasted. You learned nothing that a pointed question wouldn’t have taught you. You also didn’t produce anything during that half-day, which means the team paid for your silence.
The counter-argument is “I want to try harder first.” That instinct is right, but the calibration is usually wrong. One hour. Then ask. If you’re embarrassed to ask, ask anyway. The embarrassment is a reputation tax that’s vastly smaller than the tax of a junior engineer who disappears for half a day at a time.
Four: when you debug, narrate
When you’re debugging something gnarly, say out loud (or in a terminal scratch file, or in a Slack scratch channel) what you’re thinking. “I think X is happening because of Y. If that’s true, then Z should be observable. Let me check Z. Huh, Z is not observable. So X is not because of Y. What else could cause X?”
This is not for show. It’s how you avoid running in circles. The narrated version of debugging surfaces assumptions you’d otherwise make silently. It also has the side effect of turning your debugging into a post-incident story you can tell other people, which is enormously valuable to the team.
Five: a test is cheaper than the bug it would catch
Every junior engineer I’ve mentored has had the same first-year temptation: skip the test “because I’m sure this works.” The honest truth: you’re never sure. Nobody is. The test is the evidence that it works. Without the test, “it works” is a vibe, and vibes don’t survive the next engineer editing that function.
Write the test. Especially for the edge cases. Especially for the boring happy-path cases that “obviously work.” The tests you skip are the tests that catch the bugs you ship.
Six: do the unglamorous work on purpose
Every team has work that nobody wants: upgrading a flaky test, documenting a confusing module, rewriting a brittle script, owning the on-call handoff template. Volunteer for it.
Three reasons:
- You learn the system in a way feature work doesn’t teach you.
- You build the specific senior-engineer reputation of being someone who reduces entropy. That’s worth more than any single feature.
- Senior engineers are scarce. Every team needs them. Building visible evidence that you are one is the fastest path to being treated like one.
Seven: your first manager is a data point, not a calibration
If your first manager is great, treasure them — and recognise they’re an outlier. If your first manager is bad, it’s not a calibration on managers in general. Most senior engineers I know have had the full spread.
The practical consequence: don’t make long-term career decisions based on your first manager’s opinion of you. That opinion is one person’s view, and that person probably hasn’t been trained as a manager either.
Also: when your first manager gives you advice that sounds wrong, ask “wrong how?” rather than dismissing it or accepting it. Most first-manager advice is a garbled version of something genuinely useful. Unpack it with them. They’ll often learn something from the unpacking too.
Eight: the open-source portfolio is the career cheat code
Every engineer I know who ended up in a role they loved had a visible body of work. Not necessarily a popular project — visible. A handful of OSS contributions, a small tool they wrote and documented, a series of blog posts, a conference talk. Something that, when a hiring manager Googled them, returned a coherent picture of “this is the shape of this engineer’s thinking.”
You can be an excellent engineer with none of that. You will get fewer opportunities. It is, at every stage, cheaper to have a portfolio than not to. Start one. It doesn’t have to be a big deal. Ship a small tool. Write three posts. Contribute to something you use.
Current me shipping this site you’re reading is, in part, a re-commitment to that exact advice. I got lazy about it for a few years. I’m fixing that.
Nine: the compounding skill is clarity
Not cleverness. Not velocity. Not depth. Clarity.
The ability to explain a decision in one sentence. The ability to write a commit message that describes the why. The ability to leave a codebase where the next engineer knows what’s going on. The ability to tell a PM that the feature will take three weeks rather than six, and show them exactly why.
Everything else you’ll learn along the way. Clarity compounds, and the engineers who build it early have a compounding advantage over the ones who don’t.
Ten (the quiet one): be suspicious of your own excitement
The most expensive mistakes I’ve watched — and made — come from being excited about a solution before the problem was properly understood. “Let’s rewrite this.” “Let’s use this new framework.” “Let’s break it into services.” Excitement is a signal, but it’s not a decision function. When you notice excitement about a technical choice, wait a week. Write the plan down. Sleep on it. Ask someone who’s less excited than you to poke holes.
If the excitement survives the week, it was real.
If it doesn’t, you saved yourself months.
That’s it. That’s the letter. It’s not complete, but it’s honest, and it’s the thing I wish someone had handed me at 22. If you’re starting your first job and someone points you at this, I’m glad, and I hope some of it saves you time.