
Diffusion models made image generation possible. Midjourney made it feel addictive. The difference wasn’t just the model — it was the product loop: fast iteration, visible search, and UI as a steering system for probability.
Axel Domingues
In November, I wrote about DALL·E as the proof that text can steer image distributions.
In December, I want to talk about the part most engineers underestimate:
Why Midjourney feels magical.
Not “because the model is better.”
Because the product loop is better.
Midjourney is a masterclass in shipping a probabilistic generator as a steerable system:
If you’re building any generative feature (text, images, audio, code), this is the lesson:
Capability is a model problem.
Reliability and delight are product loop problems.
The core idea
Midjourney is interactive search over a probability distribution — wrapped in a loop that feels like creation.
The engineering takeaway
When you ship generators, you’re really shipping a steering interface + job system + evaluation loop.
The product superpower
Users don’t need perfect outputs. They need fast iteration and good control handles.
The hidden constraint
The loop only works if latency, cost, and queueing are designed — not “left to infra”.
A lot of teams ship generative features like this:
That’s a single-shot API mental model.
Midjourney’s mental model is closer to:
That’s not “one inference.”
That’s a loop — and loops create compounding improvements:

Ask: “how do we make iteration cheaper and more guided?”
One of Midjourney’s simplest choices is also one of its most powerful:
return a grid.
A grid does three important things:
A single image looks like “the answer.”
A grid looks like:
“Here are four plausible samples from this intent.”
That psychologically reframes the system:
Many users can’t describe what they want precisely.
But almost everyone can do:
Selection is a low-friction way to provide signal without writing a better prompt.
Even if none of the four images is perfect, the user usually sees something that’s promising.
That keeps them in the loop.
If your product returns four outputs and one is close, the user feels in control.
When engineers say “add controls,” they often mean:
Midjourney’s controls are more subtle:
These are not UI features.
They are steering primitives.
Think of them as the image equivalent of:
Steering primitives
Good generative products don’t expose the model.
They expose operations over the output space: explore, refine, constrain, commit.
Under the hood, a well-designed generator has two different loops:
Exploration loop
Fast, cheap, low-risk.
Generate candidates, learn direction, stay playful.
Commitment loop
Slower, more expensive, higher confidence.
Upscale, finalize, export, publish.
This split matters because it maps to real system constraints:
It also maps to how people create:
“Magical” is a word people use when they can’t explain a system.
But as engineers we can define it:
A generative product feels magical when it consistently delivers these three feelings:
Those feelings come from:
So if you’re designing your own generator, stop asking:
“What features should we add?”
Start asking:
“What are the smallest actions that let a user steer the distribution?”
Midjourney’s UX implies a backend architecture that looks very different from a typical request/response API.
At minimum, you need:
A job system
Prompts become jobs with IDs, state transitions, retries, and quotas.
A real-time channel
Users need updates: queued → running → complete → failed.
Stateful sessions
Variation and upscale require remembering the lineage of an image.
Cost enforcement
Every action spends compute.
Budgets and rate limits must be first-class.
This is the same architectural move we’ve been making all year in 2023:
treat probabilistic inference like production work.
Not like a function call.
If your product supports:
…then you are no longer generating outputs.
You are building a graph of derivations.
A useful internal model is a lineage DAG:
This lineage becomes:
The loop only feels good if the user experiences:
Which means your compute layer needs:
A silent queue turns curiosity into frustration.
One reason Midjourney works so well socially is that the process is visible:
That visibility does two things:
If you’re building internal tools, you can still use this pattern:
It makes the system learnable and trustworthy.
Even if you never generate images, Midjourney offers patterns you can steal.
Give users cheap ways to explore:
Give users a deliberate “finalize” step:
Store:
If you can’t explain outputs later, you can’t operate the feature.
Stop shipping “prompt boxes.”
Ship operations:
A good loop can hide problems as well as solve them.
Here are the failure patterns I’ve seen teams hit when copying the “iteration” idea:
Symptom: users keep retrying but never feel they can “commit.”
Cause: too little control, too much variance, no commitment gate.
Fix: add stronger constraints in “final mode” (and make the transition explicit).
Symptom: users think the model is “wrong” when it’s actually underspecified.
Cause: single-shot UX; no visibility into alternative samples.
Fix: return candidates, show variability, teach steering.
Symptom: engagement is high but margins are negative.
Cause: no budgets, no quotas, no friction where it matters.
Fix: enforce compute budgets and make high-cost steps intentional (commitment loop).
Symptom: you can’t trace how an artifact was produced.
Cause: no lineage graph, no versioning, no audit trail.
Fix: provenance as a first-class data model (inputs, params, model version, checks).
Midjourney isn’t just “a good image model.”
It’s a full-stack system that treats generation as:
That is the architecture move I keep repeating in 2023:
Don’t ship a probabilistic component.
Ship the system that makes it usable.
December takeaway
“Magical” is what users call a well-designed feedback loop.
This wraps the 2023 series: Software in the Age of Probabilistic Systems.
From here, the blog shifts into a deeper, more operational track:
The through-line stays the same:
reliability is designed.
See you in the next series.
Prompting is Not Programming: Contracts, Schemas, and Failure Budgets
Prompting feels like coding until it fails like statistics. This month I start treating LLMs as probabilistic components: define contracts, enforce schemas, and design failure budgets so your system survives outputs that are “plausible” but wrong.
DALL·E: How Text Became Images (and Why It Changed Everything)
DALL·E wasn’t “just a cool generator.” It turned language into a control surface for visual distributions — and forced product teams to treat image creation like a probabilistic runtime with safety, latency, and cost constraints.