9 min read

The Senior Engineer's AI Workflow, End to End

Twenty posts of AI-assisted engineering, synthesised: the three questions that decide whether to reach for a model, where it belongs across a real working day, what it never touches, and the honest multiplier once you separate mechanical work from judgement.

AIWorkflowEngineering CultureAndroidProductivity
HR

Hessam Rastegari

AI Native Engineer · 12 years shipping Android

TL;DR — Three questions gate every use: is verification cheap, do I know what correct looks like, and will I own this code. Across a day it earns its place in seven spots — understanding unfamiliar code, enumerating design options, implementing in categories, self-review before push (the highest-value placement), debugging, trace analysis, and migrations. It touches none of: deciding what to build, judging a design against constraints only you hold, the organisational conversation, or domain semantics. Honest multiplier: 3–5× mechanical, 1× judgement, 0× organisational — which for senior work is a smaller number than the demos imply, and still worth it. The one real risk is letting it erode the skills you need to check it.

The three questions

Everything in this series reduces to these, asked before reaching for a model.

1. Is verification cheap?

This is the whole game. A model that produces an answer in five seconds which takes you forty minutes to verify has made your day worse, not better.

Cheap verification looks like: a test that goes green, a compiler error that disappears, a query result on screen, a table you can read. Expensive verification looks like: prose about your business logic, an architectural recommendation, a "this should work" refactor of code you don't know.

Tasks aren't fixed in this respect — you can often restructure them. "Explain how the sync layer works" is expensive to verify; "write a test demonstrating what the sync layer does when the network drops mid-write" is cheap. Same question, one of them checks itself.

2. Do I know what correct looks like?

If you can't recognise a wrong answer, you're not reviewing — you're agreeing. And agreeing with a fluent, confident answer feels exactly like understanding.

This is the reason "use AI to learn a new area" is more dangerous than it sounds. It's genuinely good for orientation and genuinely bad as your only source, because the failure mode is a confident wrong model of a domain you can't yet audit.

3. Will I own this code?

Decide the trust level up front:

  • Disposable — a script, a one-off migration, an internal tool. Skim for anything destructive; ship it.
  • Owned — production code someone maintains. Read every line as if a new colleague wrote it.
  • Critical — payments, auth, data migration, security boundaries. Read twice, write the tests yourself, have a second human look.

Choosing afterwards means choosing while invested in 300 working lines, and you will choose wrong.

Where it sits in a real day

Understanding unfamiliar code

The best available use, and the one I'd keep if I could only keep one. A module you've never opened, explained in two minutes instead of an hour.

The verification move that makes it safe: write a test that encodes the explanation. If the test passes, the explanation was true; if it fails, you learned something more valuable than the explanation. Either way you now have a test the module didn't have.

Design: options, not recommendations

Three ways to do this. For each: how it works, and
what it's WORSE at than the other two.
Then pick one and say why.

The worse at clause is what separates the answers. The trade-off list is routinely more useful than the recommendation, because you're the one who knows which downside you can absorb.

The decision stays yours. It has to — it depends on the deadline, the team's skills, and the migration half-finished in another repo, none of which are in the prompt.

Implementation

Plan in five bullets first. Rejecting a wrong plan costs ten seconds; rejecting a wrong 400-line diff costs twenty minutes and leaves you attached to salvaging it.

Then: one category per commit, three worked examples instead of adjectives, and an explicit "if it doesn't fit the pattern, list it and skip — don't improvise". That last clause converts the awkward 5% from hidden improvisation into a short list of things needing a human.

Self-review, before push

The highest value-per-risk placement in the whole workflow, and the one most teams skip in favour of a PR bot.

No social cost, no shared attention budget, no morale risk, and the person verifying the output is the person who wrote the code and knows which suggestions are nonsense. Noise costs you thirty seconds instead of costing your team a channel they'll mute.

Debugging

A rubber duck that reads code. Paste the actual stack trace, the actual failing assertion, the actual interface — never your summary, because whatever you paraphrase you've already decided is irrelevant, and that's the decision you're least qualified to make while debugging.

Performance

Never paste a trace. Paste query results. Perfetto's trace processor speaks SQL; the model writes the query, you run it, you paste back twenty rows. It never sees the trace, so it can't hallucinate about it — it can only be wrong about what to ask next, which costs eight seconds.

And it proposes the next query, never the conclusion.

Migrations and upgrades

The pattern that generalises: let a deterministic tool produce the task list. The compiler, for a KMP migration. The official behaviour-changes page, for a targetSdk bump. Then the model categorises, you decide policy per category, and it applies volume one commit at a time.

Never let it both find the work and do the work. That's where the errors compound invisibly.

What it doesn't touch

Deciding what to build. It can build the flaky-test leaderboard. It cannot notice that your team's real problem is that nobody trusts the test suite.

Judging a design against constraints only you hold. The deadline, the team's appetite, the thing that was tried in 2024 and abandoned for reasons nobody wrote down.

The organisational half. The deprecation that needs five teams to move, the KMP adoption the iOS team wasn't consulted on, the vendor whose SDK blocks your upgrade. These are most of what makes senior work hard and they compress by exactly zero.

Domain semantics. Whether "a day" means a calendar day or a business day in your billing rules. It will pick something plausible and never mention that it chose.

The honest arithmetic

Kind of work Multiplier
Mechanical, high-volume, cheap to verify 3–5×
Judgement — design, trade-offs, what's worth doing ~1×
Organisational — alignment, vendors, other teams 0×

Across a real senior week, the mechanical share is smaller than a demo suggests. A targetSdk upgrade whose audit collapsed from three weeks to two days still took the same two weeks of testing and the same three weeks waiting on a vendor.

That's not a disappointing result. It's a clarifying one: it tells you exactly which half of your job to point this at, and it explains why the "10× engineer" claims never survive contact with a real backlog.

The risk worth naming

Don't let it erode the skills you need to verify it.

If you never read a Perfetto trace yourself, you can't tell when it's wrong about one. If you never work through a concurrency bug unaided, you lose the instinct that says that explanation is too neat. The verification skill and the doing skill are the same skill, and only one of them is being exercised.

So do some things the slow way on purpose. Read the trace before you query it. Write the tricky function first, then ask for a critique. It costs an hour a week and it's the difference between using the tool and depending on it.

The rule

Use it hardest where verification is cheapest, keep the judgement, and keep the skills that let you judge. The bottleneck moved from typing to deciding what's worth typing — which was always the senior skill. It's just become the whole job.

Keep reading