← Journal
· 7 min

What AI Coding Agents Still Get Wrong About Distributed Systems

Agents write correct-looking code very fast. The failures I keep seeing are not syntax or API misuse — they are assumptions about time, ordering and retries.

AIDistributed SystemsEngineering practice

I use coding agents daily and they have changed how much of a day goes into typing. What has not changed is where the bugs live. The failures I keep catching in review cluster in a few places, and they are all the same kind of mistake: local reasoning applied to a system that is not local.

1. Check-then-act, everywhere

Asked to prevent duplicates, the near-universal answer is a read followed by a write:

if (!repo.existsByReference(ref)) {
    repo.save(payment);          // two callers both get here
}

It is correct single-threaded and it reads as obviously right. The version that holds is a unique constraint, with the violation treated as the duplicate signal rather than as an error to log. Agents produce this correctly when asked directly and rarely produce it unprompted.

2. Retries without idempotency

Retry logic arrives readily — usually with sensible backoff. What arrives much less often is any statement about whether the operation being retried is safe to repeat. For a payment, that difference is the whole problem.

3. Time as if it were a clock

Instant.now() compared across services, timeouts assumed to be honoured, ordering inferred from timestamps. Distributed timing is the area where generated code is most confidently wrong, because the wrong version looks completely ordinary.

4. Optimising the wrong axis

Ask for a faster batch and you tend to get concurrency: threads, parallel streams, async. Often the real win is removing round-trips — batching the access, grouping related work — which is a smaller total workload rather than an overlapped one. Agents reach for the second reflexively and the first only when told.

5. Cache invalidation as a footnote

Caches come back well-formed on the read path and thin on the write path. Multi-instance eviction, ordering between two rapid updates, what happens to an instance that was down during the publish — those need to be asked for.

How I actually work with them

None of this is an argument against agents. It is an argument about where to spend attention.

  • Specify the invariant, not the feature. “Two concurrent callers must not both create a payment for this reference” produces the unique constraint. “Prevent duplicates” produces the race.
  • Ask for the failure mode. “What happens if this runs twice, out of order, or half-completes?” is the single highest-yield prompt I have.
  • Review concurrency and I/O boundaries by hand. Everything else I read quickly. Those two I read properly.
  • Make it write the adversarial test. Agents are good at generating the concurrent test that fails; they just do not volunteer it.

The leverage is real and it is large. It sits in implementation speed, not in judgment about correctness under concurrency — and that gap is currently the most valuable thing an experienced engineer brings to the pairing.