Borrowed Assumptions
A Good Product
Everyone knows what a good product is. It is simply a product that is good. Isn’t that obvious?
I admit I had not put much thought into this before becoming a software engineer. You use something and move on with your life. That is enough as a user but not when you are the person building it.
Once you move into industry, “good” becomes quantifiable: engagement, conversion, retention, downstream orders, funnel movement, or whatever metric is on the dashboard this quarter. You run an A/B test, X wins against Y, ship it, celebrate, and move on.
Online experiments are one of the best tools we have for not lying to ourselves, but statistical evidence is only as useful as the insight you extract from it.
Isn’t Statistical Evidence Enough?
Not really. An experiment can tell you users clicked more, booked more, or came back more often. It cannot, by itself, tell you that you understood the user’s needs. It cannot tell you whether the winning variant worked because it solved a real problem, exploited confusion, moved attention, or just fit the current page layout.
Trying to copy the exact winning variant repeatedly will not make conversion rise forever. There is something real behind the metric, but you are seeing it through a very small window.
This is where product work gets annoying. Metrics make it easy to pretend the situation is simpler than it is. Interacting with a product is complex. People have context, anxieties, habits, social pressures, time limits, bad internet, half-formed intent, and many tabs open. A product is good when it fits enough of that reality to become useful.
Often, people do not really want your product. They want progress in some situation. That sounds like business-book language, but the point is hard to avoid. A good product understands the situation it is pulled into.
Intentionality
I think a good product is mostly about intentionality.
By intentionality I do not mean “the founder had a vision” or “the designer made a beautiful Figma file”. I mean the product encodes deliberate assumptions about the user, the problem, and the trade-offs.
A book is an easy comparison. When you read a good book, you assume the author had a reason for what is on the page. The descriptions, the dialogue, the pacing, the thing they chose not to explain, the thing they repeated twice. Not every sentence is perfect, but you expect it to be there on purpose.
Now imagine someone sends you 50 pages of LLM-generated text. Would you read it? Maybe if you are paid to or trapped somewhere with no internet. Otherwise, probably not.
The sentences might be fine. The grammar might be fine. It might even be “useful”. But you do not trust there is a mind behind every choice. You do not trust the details carry intention instead of just filling space.
Products can end up creating a similar kind of distrust.
The Information Problem
LLMs can generate all sorts of things now: todo apps, dashboards, agents, landing pages, migrations, half-working games, full-stack prototypes, internal tools. Like many programmers, I have spent much of the past year talking to AI, materializing ideas, realizing many were not worth pursuing, finding new ideas, and creating more small products.
Were the created products good?
Mostly no.
Some were useful. A few became part of my daily toolkit. Maybe one or two got close to good. That is still amazing. I am not pretending this is not a big deal.
The way we work with LLMs is different. We give the model a prompt with limited information and ask it to create something much larger. The output contains more surface area than the input: more screens, states, copy, components, error handling, and assumptions.
Most of that extra information comes from training data and model priors. This is the trick. That is why you can say “make me a todo app” and get something with hover states, empty states, buttons in normal places, and styling like the average of a million SaaS screenshots.
Isn’t this great?
It is great until it isn’t.
You keep pushing the model to create more. The product surface grows. You review and fix obvious bugs. You feel in control. But the assumption surface grows faster than your ability to inspect it. The product accumulates choices that are not yours, not the user’s, and not anybody’s. They just fell out of the expansion process.
Eventually, you hit a wall in progress, not because the code is impossible to change. The code may be fine. You hit the wall because you no longer understand why the product is the way it is.
I’ll Just Write a Detailed Spec Then
This is everyone’s default solution. I will write a detailed spec. I will turn on dictation and talk for two hours. I will create a product requirements document. I will add examples. I will tell the model exactly what I want. This is just a skill issue. I will steer the AI better.
This helps, but only up to a point. If you remove all expansion, your spec starts becoming as large and detailed as the product itself. At that point, is writing the product in Markdown really that much better than writing it in code?
The harder problem is you do not know all your assumptions. Nobody does. If they were obvious enough to list, they would not be assumptions.
Web developers are spoiled here. There is a huge amount of web code, product writing, UI conventions, and SaaS sludge in the training data. The model often shares enough of your assumptions to seem smart. It knows buttons usually have hover states. It knows settings pages need toggles. It knows dashboards need cards. It knows login screens should not look like a spreadsheet from 2007.
Move into a space with less common training data, and you see the problem faster. Ask it to make a game, design menus, handle progression, pacing, difficulty, input feel, visual feedback, and the tiny moments that make games feel good. Suddenly, the defaults are much less useful. You find out how many assumptions you relied on without noticing.
So What?
Before AI, implementation and intention were more tightly coupled. Not perfectly. Bad products existed before ChatGPT, obviously. But when you built a working prototype by hand, many of your assumptions were forced through the act of building. You had to decide. You had to notice. You had to encode the choices yourself.
Now you can get working software in hours or days, but with assumptions that are not really yours. The prototype exists, but when you inspect it closely many decisions feel blurry.
Cheap prototypes make it feel like the product is almost done. In reality, the product is only available for judgment earlier.
The work shifts from “can I make this exist?” to “can I make this thing encode the right assumptions?”
That means watching users, understanding the job, and choosing what not to support. It means noticing the hidden states, making trade-offs, removing fake cleverness, and forcing the product to become more specific. It means asking boring questions that prototypes hide: what happens when the user is interrupted, when the data is missing, when the first attempt fails, or when the obvious shortcut creates a bad habit.
The Expansion Will Get Better
Yes, LLMs will get better. They will encode better defaults. They will improve at UI, codebases, product patterns, and maybe some kinds of taste. You can already improve the process with examples, style guides, evals, design systems, and those silly little Markdown skill files.
The part that matters is whether your product is so familiar, so previously solved, and so deterministic that the model’s default assumptions are good enough.
Sometimes the answer is yes. Most CRUD tools do not need deep philosophy. Sometimes you really do need a table, a form, a filter, and a CSV export.
But if the product is supposed to do something specific in the real world, then generic correctness is not enough. The product still needs intention.
Conclusion
It is cheaper than ever to create a product. I do not think it is cheaper to create a good one.
AI saves time on implementation but does not remove the work of understanding. It just moves that work around. You can get to a prototype faster, get in front of users faster, and face reality faster. That is valuable but also a little dangerous because the demo is usable before the hard constraints of the product are visible.
The annoying part is that the product work does not disappear. It starts later, after the thing works, and everyone is tempted to believe the hard part is over.
The prototype is not the product. The product is what remains after you replace borrowed assumptions with deliberate ones.