← All posts

Ten working principles for engineers, and how each one fails

Ten principles that make an engineer good to work with, each grounded in a real situation, plus the failure mode each one produces when overdone.

Every principle is dose-dependent

Every behaviour that makes someone good to work with has a dose at which it turns harmful. Ownership becomes hoarding; high standards become a PR that never merges. Engineers who are hard to work with rarely lack principles — they run a good one at ten times the dose. Ten I use, each with the situation it applies to and how it goes wrong.

Build from what your users need, not from a rival’s changelog

In planning, someone puts a competitor’s release notes on screen and we start generating tickets from them. That’s not requirements gathering — it’s outsourcing your roadmap to a company whose constraints you can’t see.

The best change we made to our diagnostics tooling came from watching a field technician correlate timestamps across two exported logs by hand in a spreadsheet. Nobody had filed it; he’d stopped expecting it to be fixed.

Failure mode: feature-chasing. You ship parity with someone else’s list, nothing your own users asked for, and the copies land worse because you took the surface without the reasoning under it.

Process, metrics and status reports are proxies for reality

Every dashboard is a lossy compression of a system — fine, until you manage the compression instead of the system.

The clearest version I’ve seen: every health check green, customer unable to complete a request. The check hit a /health endpoint that returned 200 while the process was alive. It measured “the JVM has not crashed”; we read it as “the service works.”

Keep first-hand contact: read the log, not the summary of the log; run the failing test yourself before theorising; call the person who filed the ticket. Five minutes there beats an hour of guessing what they meant.

Failure mode: deciding all process is theatre. The engineer who keeps everything in their head, writes no runbook and skips design reviews hasn’t resisted the proxy — they have become one.

A standard is an explicit, checkable bar

“High quality” is not a standard. “No new public function merges without a test that fails if you delete the body” is one, because two people can look at a diff and agree on whether it’s met.

Standards are team-specific and learnable. A new joiner doesn’t know you require a rollback plan in the PR description, or that a TODO without a ticket number gets rejected. They aren’t lowering the bar; they can’t see it. Write it down and taste becomes teachable. Raising the bar is a separate, deliberate move: one new non-negotiable per quarter.

Failure mode: perfectionism that never ships. A three-week naming argument in a service with two users costs exactly what you didn’t build instead.

Learning has to be deliberate, or it’s a hobby

Passive learning is reading whatever the feed serves. Deliberate learning is studying what actually cost you time. I lost two days to a CAN bus arbitration issue because I’d never properly read that part of the spec. Reading it took ninety minutes — a better return than any course I took that year.

Failure mode: learning as procrastination. Starting a third framework tutorial is a socially acceptable way to avoid the migration you don’t want to begin. If you can’t name the decision the learning improves, you’re hiding.

Sort decisions by how expensive they are to undo

Most decisions are reversible and get treated as if they weren’t. A few are irreversible and get treated as if they were. The second error is much more expensive.

A decision arrives Cheap to undo next month? yes no Decide now, note a date to revisit Write the options down, get a reader
One test, two speeds: reversibility decides how much ceremony a decision earns.

Reversible: log format, directory layout, anything behind a feature flag. Decide in the meeting. One-way: a public API other teams build against, a storage format already written to a million rows, firmware flashed to vehicles in the field.

Failure mode: saying “we can change it later” about a one-way door. You can — where “later” means a migration, a deprecation window and a year of supporting both.

Disagree properly, then commit fully

Arguing well has a shape: your position, the cost you expect, the evidence, and what would change your mind. Say it once, in writing, where the decision gets made — then ask for it to be made.

If it goes against you, you build the other thing — genuinely. Not “I told you so” in the retro, not a design that quietly leaves room for your version.

Failure mode: silent non-compliance. Nodding in the meeting and slow-walking the work is worse than the original disagreement, because it teaches everyone that agreement in a room means nothing.

Ownership is about the result, not your ticket

Your ticket is done. The feature still doesn’t work, because the upstream service returns null in a field you assumed was populated. Ownership is the gap between “not my component” and either fixing it, filing it with a reproduction, or walking to the team that owns it.

Failure mode: hero culture. Someone who owns everything, answers every page and never writes the runbook is a single point of failure with a pulse. Ownership that doesn’t end in documentation and a second capable person is hoarding.

Invention is the fun half; simplification is the valuable one

Anyone can add. Deleting the config layer nobody set, collapsing a 400-line state machine into a lookup table, removing the abstraction with one implementation — that’s harder, because it needs understanding the whole thing first.

Failure mode: rewriting things that work. A boring service with no open bugs isn’t a refactoring opportunity, it’s an asset. Simplify what you’re already forced to touch.

Prefer the cheap experiment — where it’s genuinely cheap

Two candidate model architectures, and a week of arguing about which generalises better. Both fit on the GPU box overnight. Run them.

That only holds where the experiment is cheap and reversible: “let’s just try it” applies to a branch, not to a production schema migration. And a failed experiment is data only if you wrote down what you expected first — otherwise you’ll rationalise the result and learn nothing.

Set the target past the constraint, then work backwards

“Make the build 10% faster” gets you a cache. “Make the build 4 minutes instead of 40” makes you ask why the whole thing rebuilds when one file changed. Same engineers, same week, different question. Then work backwards to a first concrete step this sprint — a big goal with no Monday task is a slogan.

PrincipleIn practiceOverdone
Serve the userWatch someone use it before writing ticketsParity with a rival nobody here uses
Resist proxiesRead the log, not the summary of itNo runbooks; doesn’t scale past you
High standardsA bar two people can check on a diffNaming debates outlive the feature
Deliberate learningStudy what cost you two daysA tutorial instead of the migration
Reversible callsDecide now, note a revisit dateSpeed applied to a one-way door
Disagree and commitObjection in writing once, then build itNodding, then doing it your way
OwnershipChase the result across team linesHero on every page, bus factor of one
Invent and simplifyDelete the layer with one callerRewriting a service with no bugs
Bias for actionRun both models overnight, don’t argue”Just trying it” on the prod database
Think bigTarget 10x, then find this sprint’s stepA goal with no first step

On Monday

  • Label your team’s oldest open decision reversible or one-way. If it’s reversible, close it today.
  • Turn one review comment you make repeatedly into a written, checkable rule in the repo. That converts your taste into the team’s standard.
  • Verify by hand that one health check you trust would actually go red if the thing it watches broke.
  • Put your next design-review disagreement in one written paragraph with the cost you expect. Then let it be decided, and drop it.
  • Spend ninety minutes on the primary source — spec, RFC, datasheet — for the last thing that cost you more than a day.
  • Delete something: an unused flag, a dead branch, an abstraction with one caller.