Communication IS Engineering. Stop Calling It a Soft Skill.

TL;DR: Communication isn’t a soft skill bolted onto engineering. It IS engineering. The same rigor you bring to system design applies to how you convey ideas. I learned this across three languages, one failed technology adoption, and too many lost demos. The receiver determines the encoding, not the sender.
I once spent forty-five minutes explaining why a particular build system would eliminate an entire class of deployment failures. I had diagrams. Benchmarks. A live demo that worked flawlessly, which, if you’ve ever given a live demo, you know is basically a miracle.
The engineering lead across the table nodded politely, said “interesting,” and went with the other option. The worse option. The one that would, six months later, cause exactly the outage I’d warned about.
Better technology. Airtight argument. Still losing.
I blamed politics. I blamed the other team’s influence. I blamed the culture. Took me an embarrassingly long time to realize the problem was me.
Not my technical analysis, that was solid. The problem was that I was transmitting on a frequency nobody in that room was tuned to. I was encoding my argument in the language of systems (determinism, reproducibility, hermetic builds) and expecting people who think in terms of risk, timelines, and team capacity to just… decode it themselves.
They didn’t. Why would they?
Most engineers have one encoding, technical, and they blast it at everyone. I did this for years myself. For years. Across jobs, countries, languages. I could explain something in three human languages and still only speak one: engineer.
What I’ve come to believe, and what this post is about: communication isn’t a soft skill bolted onto engineering. It IS engineering. The same rigor you bring to system design (understanding constraints, choosing the right abstraction, optimizing for your target environment) applies directly to how you convey ideas.
Maybe you think communication is important for engineering, not engineering itself. That it’s a complement, not a component. I think by the end of this, you’ll disagree.
Why Is Every Line of Code a Message?
Nobody tells you in school: you’re already communicating all day. Every line of code is a message to someone. You just don’t think about it that way, so you’re doing it badly.
A variable named tmp2. You move on. Somebody six months
from now, maybe you, stares at that name in a stack trace
at 2am and has no idea what it holds, why it exists, or
whether it matters. That’s not just a bad name. It’s a
message to the future that says “figure it out yourself.”
Naming isn’t a style preference. It’s telling the next
reader what this thing IS and why it’s here.
A commit message that says “fix stuff.” Three weeks later someone bisects a regression and lands on your commit. They need to know what changed and WHY. “Fix stuff” tells them nothing. Actively wastes their time. Every commit message is a letter to a future debugger, and yours said “lol good luck.”
An exception with the message “invalid input.” The person on the other end can’t see your code. Can’t read your mind. They don’t know which input, what made it invalid, or what to do instead. One chance to help them and you punted.
A pull request with a blank description. Congratulations, you just shifted your work onto the reviewer. Now they have to reverse-engineer your intent from the diff. They’ll either spend twice as long reviewing or, more likely, skim it and approve. Neither outcome is good. A blank PR description isn’t laziness, it’s telling your teammate their time matters less than yours.
A code review comment: “this is wrong.” No explanation. That reads like a verdict, not a review. A review is a conversation. “This is wrong” without “here’s why, and here’s what I’d try instead” is just a slap. Nobody learns from that. They just resent you a little more.
All of these are communication. Naming, commits, error messages, PR descriptions, review comments. Done daily, reflexively, without thinking about the human on the receiving end. You’re already communicating all day. Just doing it unconsciously. Badly.
Three Languages, One Encoding
I grew up switching between three languages. Bosnian at home with family. Slovenian at school, in the street, at the store. English on the internet, in music, eventually at work. Every conversation required translation, and not just swapping words. Entire operating systems. The humor, the warmth, the weight of things.
In Bosnian, there’s a way of being direct that carries affection. You call someone out, tease them, and it’s love. It lands warm. Take that same directness into Slovenian and it’s just rude. Into English and people think you’re angry. The words aren’t the message. The encoding is.
I remember a meeting early in my career, first international team, mostly native English speakers. I was explaining why a proposed architecture wouldn’t scale. I knew I was right. I’d run the numbers. But I made my case the way I would’ve at home: blunt, impatient, no softening. “This will break. Here is why. We should not do it.” Factually correct. Socially catastrophic.
The room went quiet. Not the productive quiet where people are thinking. The other kind. Where people decide you’re difficult. I watched it happen in real time and couldn’t stop it. My face got hot. I spent the rest of that meeting saying nothing, replaying every sentence, wondering which word was the wrong one. Was it “should not”? My tone? That I didn’t smile enough? I didn’t know. I just knew I’d transmitted something I hadn’t intended.
That’s the non-native speaker tax. You’re always performing. Running two processes at once: what you want to say and how it’ll land in this language, in this culture, with these people. Think in one language, speak in another. Rehearse sentences before saying them. Watch faces for micro-reactions to figure out whether your encoding is working. Every conversation costs more CPU than it should.
For years I resented it. The extra effort. The constant self-monitoring. A joke that would kill in Bosnian just dies in English because the rhythm is off, or the punchline depends on a word with no translation, and once you have to explain a joke it’s dead.
Then, slowly, I realized something. The tax was training.
Monolingual people encode automatically. Never have to think about it because their default encoding matches their audience. Which means they never develop the muscle of deliberately choosing an encoding. One channel. Works at home, so they figure it works everywhere.
I had three channels from birth, and none of them were the default anywhere. So I was forced, constantly, painfully, to think about the receiver. Who is this person? What’s their context? What encoding will land? Not “what do I want to say” but “what will they actually hear?”
Took me embarrassingly long to figure out that’s the whole game.
Engineers encode for different audiences constantly. Other engineers. Product managers. Customers. Executives. Each is a different language with different idioms, different things that matter, different ways “blunt” and “warm” and “clear” get decoded. Most engineers don’t notice. One encoding, technical, blasted at everyone. Then frustration when the PM “doesn’t get it” or the executive “doesn’t care about quality.”
The receiver determines the encoding. Not the sender. You don’t get to pick how your message lands. You only control how you send it, and adjust until it lands the way you intended. This isn’t people-pleasing. Not “dumbing things down.” Same thing as choosing the right data format for your target system. You wouldn’t send protobuf to a service that expects JSON and then blame the service.
I learned this in kitchens and schoolyards before I learned it in meeting rooms. Same skill, though.
What Happens When Great Technology Can’t Explain Itself?
Nix is a tool that lets you describe your entire system configuration in code and reproduce it exactly, anywhere. Think of it as infrastructure that’s deterministic by default: same inputs, same outputs, every time.
The technical arguments for Nix are overwhelming. Builds that actually reproduce. Rollbacks that work because every system state is immutable and addressable. Dev environments that don’t rot, don’t depend on whatever someone installed on their laptop six months ago. Dependency hell? Solved. “Works on my machine”? Gone. The engineering underneath is genuinely brilliant, a rethinking of how software should be built and deployed from first principles.
And for years, almost nobody used it.
Not because the technology was bad. It was ahead of everything else by a decade. People didn’t adopt Nix because the Nix community encoded for themselves.
I watched it from the inside. Documentation assumed you already understood functional programming, store paths, derivations, and a custom language with no formal spec. You couldn’t just start. You had to earn the right to start by absorbing concepts the docs never bothered to introduce. Error messages read like compiler internals, because they were. When you hit a wall, community discussions were technically brilliant and completely impenetrable. Mailing list threads that solved real problems in ways only the thirty people who already understood the system could follow.
Perfect encoding for receivers who were already Nix experts. For everyone else? Noise.
The cost wasn’t abstract. It was concrete. Enormous.
For every engineer who pushed through the documentation
cliff and became a Nix convert, fifty tried it for a
weekend, couldn’t get a basic dev environment working,
and went back to Docker. Not because Docker was better.
Because Docker told them what to do in language they
understood. FROM ubuntu:22.04 is a worse abstraction
than a Nix derivation, but it’s a sentence you can read
on day one. Companies built entire deployment platforms
on Ansible and Terraform, tools that solve a fraction of
what Nix solves, less reliably, because those tools met
people where they were. Nix demanded people come to it.
I felt this tension both ways. As someone who understood Nix deeply, I was frustrated that people couldn’t see what I saw. But having spent my whole life switching encodings, I also knew exactly why they couldn’t. The community was making the same mistake I’d made in that meeting room years before: transmitting correct information on a frequency the audience wasn’t tuned to, then blaming the audience for not receiving it.
The waste was staggering. Years of slower adoption. Engineers using worse tools because the better tool couldn’t explain itself. Entire categories of infrastructure pain that didn’t need to exist, persisting because the solution was locked behind a communication wall. A good product many people use beats an excellent product few people use. Nix was excellent. And for too long, barely anyone used it.
That’s what radicalized me about communication. Not some management book. Not a workshop on “soft skills.” It was watching technology I loved, technology that genuinely solved hard problems, fail to reach the people who needed it. For reasons that had nothing to do with the tech itself. The gap between what Nix could do and who it could reach was a communication gap. Pure and simple.
And it made me ask a question I couldn’t shake: what if the community can’t communicate its tools? What if communication itself is the job? What if instead of building more technology and hoping people decode it, you stand in that gap between builders and audience and make the translation your entire purpose? That question pulled me out of pure infrastructure work and toward something I hadn’t expected: customer-facing engineering, where the job IS the encoding.
What Changes When Communication IS Your Deliverable?
Until that point, communication was something that happened between engineering sessions. Build something, then explain it. Code first, talk second. The talking felt like overhead, necessary, sometimes painful, but not the work itself.
Then I moved into customer-facing engineering, and that hierarchy collapsed overnight. Communication wasn’t between the sessions. It WAS the session. What I shipped wasn’t code. It was understanding. If the customer didn’t walk away knowing what the product could do for them and why it mattered, I hadn’t delivered anything. A flawless demo nobody followed was worse than a broken demo that actually taught them something.
I learned this the expensive way. And I keep learning it, because I still get it wrong.
My pattern: I prepare a demo obsessively. Know the product inside out. Every edge case, every technical advantage, every architectural decision that makes this thing better than the alternative. Then I walk into the room and assume too much. I figure they see the value because I see the value. That they can connect the dots because the dots are obvious to me. And I forget to answer the only question that actually matters to them: what’s in it for me?
It’s a balance I haven’t found yet. You don’t want to bore people by explaining things they already know. But you can’t skip the bridge between “this is what it does” and “this is why you should care.” Not everybody connects those on their own. Some people need you to say it out loud. And when you don’t, when you get so deep into the how that you forget the why, you lose them. Not because they’re not smart enough. Because you didn’t do your job.
Worst part is the silence after. A confused customer doesn’t say “I don’t understand.” They say “we’ll get back to you.” And they don’t. They go quiet. Pick the worse tool that explained itself better. Make the same decision that engineering lead made in my first story, not because they’re wrong, but because the person with the better answer forgot to make it land.
I still catch myself doing this. Mid-demo, I’ll see someone’s eyes glaze over and realize I’ve been talking about implementation for five minutes without once saying what problem it solves for them. The difference now is I notice. I course-correct. Stop and ask “does this make sense for your situation?” instead of powering through another slide. That’s not mastery. Just the non-native speaker tax kicking in again, watching faces, recalibrating the encoding in real time.
Being right isn’t enough. Being understood is the job.
This should make every engineer pay attention: the market figured this out before we did. There’s a job title (Solutions Engineer, Sales Engineer, Developer Advocate, whatever your company calls it) that exists specifically because translation between engineering and business is hard enough to warrant a dedicated role. Companies pay real money, senior-engineer money, for people who can stand between what a product does and what a customer needs to hear. That role doesn’t exist because communication is “soft.” It exists because communication is so hard, so valuable, that it became its own engineering discipline.
Markets don’t create job titles for nice-to-haves. They create them for bottlenecks.
What Patterns Make Engineering Communication Work?
After enough failures, patterns started to emerge. Not frameworks. I don’t trust frameworks for this. Just patterns. Things I kept getting wrong until I didn’t.
First one took the longest to accept: the receiver
determines the encoding, not the sender. You don’t get
credit for being clear. You get credit for being
understood. I used to walk out of meetings convinced I’d
nailed it, precise, thorough, technically airtight. Then
nothing would change. The proposal would die. Decision
goes the other direction. And every time, I’d think: they
didn’t listen. Took years before I internalized that
“they didn’t listen” isn’t a diagnosis. It’s a confession.
If they didn’t get it, I encoded wrong. Not them. Me. I
think about this now every time I write a PR description.
Don’t ask “is this accurate?” Ask “will the reviewer
understand what changed and why without reading the diff
first?” The difference between tmp2 and
retry_count_before_fallback isn’t about style guides.
It’s whether you encoded for yourself or for the person
reading your code at 2am during an incident.
That shift, from “did I say it right” to “did they receive it right,” changes everything downstream. But it only covers what happens when you’re actually talking. The more expensive failure? When you’re not talking at all.
Silence is the most expensive communication failure there is. Not sharing your work early enough kills impact.
Engineers have this instinct to wait. Wait until it’s finished, polished, presentable. Wait until you can show the whole thing with confidence. I’ve done this more times than I can count, heads down for weeks, solving a real problem, making progress, telling nobody. Not secrecy. Just some misplaced idea that the work should speak for itself when it’s ready.
It never does. By the time you surface, context has shifted. Priorities moved. Someone started solving the same problem differently. Or, and this one really stings, people simply forgot the problem existed because nobody kept it visible. Your work didn’t fail because it was bad. It failed because you were the only one who knew about it.
If nobody knows your work exists, it doesn’t exist. That blank PR description? Small version of this same disease. You did the work but didn’t tell anyone what it was or why it mattered. Code doesn’t speak for itself. It just sits there. You have to speak for it. Early. Often. Even when it’s unfinished and ugly. Share the rough version. Share the direction before you have the solution. Let people poke holes while there’s still time to adjust. The discomfort of showing unfinished work is nothing compared to the waste of finishing something nobody needed anymore.
There’s a direct line from “I’ll share it when it’s ready” to “why doesn’t anyone appreciate what I do.” That line runs through silence.
When you do finally speak up, present the work, there’s an order that matters. Start concrete, then move to abstract. Never the reverse.
You’ve sat in that chair. Everyone has. Conference talk, or a meeting someone invited you to, or a call with a vague title on your calendar. You sit down. Speaker starts. Five minutes in, you still don’t know why you’re there. Not even sure what problem is being discussed. They’re deep into architecture, into layers, into “let me walk you through the approach.” You’re checking your phone under the table. Scanning the room to see if anyone looks as lost as you feel. It just drags on and on, and the whole time you’re thinking: why should I care?
That’s what happens when someone starts abstract and builds toward concrete. Feels rigorous to the speaker. Thorough. And it’s torture for the audience, because you haven’t earned their attention yet. Haven’t told them why any of this matters to them.
Now flip it. Someone walks up, shows you a result. “This is what it does. This is what changes for you.” Two sentences and you’re leaning in. Now you WANT the architecture. Now you’re asking questions yourself: how does it work, what are the tradeoffs, what’s underneath. Technical depth follows naturally because you gave them a reason to care first.
Story should start almost backwards. Lead with the payoff. Show what changed. Then peel back the layers for people who want to go deeper, and they will, because they have context now. They’ll follow you into the architecture willingly once they know why it matters.
“Fix stuff” as a commit message is the same mistake. Abstract where it should be concrete. “Fix race condition in session cleanup during logout” starts with the thing. Reader can decide if they need the theory.
These three patterns are really one principle. They all point at the same mistake I kept making: treating communication as self-expression instead of engineering. Encoding for the sender instead of the receiver. Staying silent instead of shipping signal. Starting with the abstraction instead of the artifact.
Next time you open a PR, leave a review comment, or present your work to anyone who isn’t you, ask which direction you’re encoding in. The answer determines whether your work lands or disappears. Only person who gets to decide is the one on the other end.
Why Does This Matter More Now Than Ever?
Now the punchline. Engineers today spend more time describing intent than writing code. You talk to copilots, agents, LLMs. Describe the problem, the constraints, the edge cases, what “done” looks like, and something else writes the solution. Job’s shifting from “write the answer” to “describe the question clearly enough that something else writes it for you.” That’s not a future prediction. That’s Tuesday.
If you’ve been paying attention, you already see it: that’s not new. It’s the communication skill engineers always needed, just made explicit and unavoidable. Vague prompt gets vague code, same way a vague requirements doc gets a vague product. The encoding problem doesn’t go away when your audience is a machine. It becomes the WHOLE problem. Every prompt is an encoding. Every response is a decode. The gap between what you meant and what you got is the same gap it always was, between intent and your ability to transmit it. Prompt engineering is just communication engineering with a different receiver. Same skill.
I spent twenty years thinking communication was the thing I did around engineering. Turns out it was engineering all along. And it’s about to be the only part that matters.