The hardest habit to break when I write about engineering is the pull toward sounding absolute. It's so much easier to write "this is how software should be built" than it is to write "given what I've seen, this is how I'd approach it." The first sentence closes the conversation. The second one leaves room for someone to push back, add context I didn't have, or just disagree — and that's the sentence I actually mean, every time.
It's worth being explicit about what that distinction actually means in practice, because it's easy to read past it. When I write about a topic, I'm describing what I'm doing or what I would do — not trying to move you toward my line of thought. Those are genuinely different goals. One is a report from where I'm standing. The other is an argument built to relocate you to where I'm standing, and that's not what I'm after. If you read something I've written and end up somewhere different from me, having actually thought it through, that's not a miss. That's the only outcome I was ever really hoping for.
If someone asked me how I'd build a Hospital Management System, I could talk for hours about Clean Architecture, DDD, CQRS, event sourcing, microservices, modular monoliths, vertical slices. None of that would be an answer yet. Before I'd commit to any of it, I'd want to know whether this is a rural clinic or a national referral hospital, how many concurrent users it needs to handle, whether it has to work offline, whether it integrates with labs or insurers, what the regulatory and audit requirements are, how often it's expected to change, and who's going to be the one maintaining it after I'm gone. Recommend an architecture before knowing those answers, and what I'm really giving you is an opinion wearing the costume of expertise.
When I write about architecture, security, or engineering practice, I'm not handing anyone a checklist to follow. I'm documenting how I'd approach a specific problem, shaped by the projects I've actually worked on, the incidents that taught me something the hard way, the systems that succeeded, the ones that didn't, and a fair amount of reading and arguing with other engineers along the way. Another experienced engineer looking at the same problem might land somewhere different. That's not a flaw in either of our reasoning — it's what happens when two people bring different constraints and different scars to the same question.
Every choice I make optimizes for something at the expense of something else. A modular monolith trades independent scaling for simplicity and a smaller team's ability to reason about the whole system. Microservices trade that simplicity for independent deployment and organizational autonomy. Neither is better in the abstract — they're answers to different questions, and the same is true of every database, messaging system, authentication approach, and caching strategy I've ever picked. This is basically why I've come to like the discipline behind Architecture Decision Records, the format Michael Nygard proposed back in 2011: not a record of the "right" answer, but of the specific context that made a particular trade-off the right call then — which is also an honest admission that a different context might make a different call the right one now. I've stopped thinking of my job as collecting the right patterns. It's choosing the right trade-off for the specific thing in front of me, and being able to say why.
One thing that's genuinely changed how I think: every legacy system I've ever complained about was, at some point, someone's modern, considered decision — often made by an engineer just as experienced as I am, working with the tools, timelines, and knowledge available at that moment. Given the same constraints, I might have made exactly the same call. That's a humbling thing to sit with, and it's made it a lot harder for me to look at an old system and ask "what were they thinking" without also asking what I don't yet know about the decision I'm currently proud of.
I get some version of this question constantly — should every project use Clean Architecture, should everything be event-driven, should we always reach for CQRS. My answer is almost always "it depends," and I've come to think that's not a dodge. A pattern exists because it solved a real problem for someone, somewhere. That's not the same as it solving my problem, here, now. The engineers I respect most are the ones who can tell me why a pattern exists before they'll tell me whether to use it.
Part of why I resist writing anything as definitive guidance is that the target keeps moving. New vulnerabilities get discovered. Frameworks change. Business requirements shift under a system that was designed around yesterday's assumptions. Something I write with full conviction today might genuinely deserve revision in two years — not because I was wrong when I wrote it, but because the field kept evolving underneath the article the whole time. I'd rather admit that up front than pretend I've written something timeless.
An engineer who's spent years in banking systems is going to value different things than one who's spent years on gaming engines, hospital platforms, or embedded devices — and that's exactly as true of me as it is of anyone else. My opinions are downstream of my experience, not independent of it. That's the whole reason I say "this is how I'd approach it" instead of "this is how everyone should approach it." The first sentence is honest about where the opinion came from. The second one pretends my specific path through this field is somehow universal.
The engineering conversations I've learned the most from almost never ended in everyone agreeing. Someone challenges an assumption I hadn't examined. Someone else brings production experience that reframes the whole question. There's a half-joking version of this idea floating around under the name Cunningham's Law — that the fastest way to get a good answer isn't to ask a clean question, it's to state something slightly wrong and let people who know better correct it. I don't write with that as a strategy, but I recognize the shape of it in how these conversations actually go: what comes out the other side usually isn't a winner — it's a better version of the question we started with. That's what I actually want from anything I write: not agreement, but the kind of pushback that leaves both of us thinking more clearly than we started.
If someone reads something I've written and walks away thinking "I wouldn't have solved it that way, but I understand why you did" — that's the article working exactly as intended. I'm not trying to hand anyone the definitive answer to how software should be built, because I don't think that answer exists in a form portable enough to hand over. What I can share honestly is how I reason through a hard problem, built from what's actually worked for me and what's genuinely failed. When I write about a hospital system, a banking application, or a distributed system's architecture, I'm not setting a standard for the industry to follow. I'm showing my work — and if I learn something next month that changes my mind, that's not a contradiction of what I wrote before. It's just the job continuing to do what it's always done to me: reward curiosity over certainty, every time I've let it.
Experience Is Earned, Not Downloaded
Credentials, tutorials, and AI compress the time it takes to encounter an idea. None of them shorten the years it takes to develop judgment about which ideas actually hold up once reality gets involved.
If All You Care About Is Payday, Stop Pretending You Care About Engineering
A salary rewards your employment. It doesn't validate your judgment. Coasting through the month without questioning anything is a choice you're entitled to make — just don't call it engineering.