Randy Au, a quantitative UX researcher and self-described boring programmer, has been building small tools with LLM-generated code for months. His takeaway is not about coding skills. It is about product design: the hard part of making software usable is deciding what things should be, and that problem does not go away when an AI writes the code.

The LLM Code Is Fast, the Interface Is Slow

Au writes linear scripts and rarely reaches for object-oriented patterns or functional primitives. He takes no joy in coding itself. What excites him is the result. LLMs have made it practical to build tools that would otherwise be too esoteric and time-consuming to justify: a Bluesky-integrated forum, a world history simulation, a sky visibility calculator, a paper trading bot. In all of them, progress is fast while the work stays abstract, data flowing through calculations. It slows to a crawl at the interface.

LLM tools are, in Au's experience, bad at building human-centered user interfaces. But the deeper problem is that he has enough UX experience to know when something is unusable garbage, even if he does not have all the answers for what the right design should be. The gap between "the code works" and "the software is usable" turns out to be mostly product decisions, not engineering ones.

Storyindex as a Case Study

Au's latest project is Storyindex, a local Flask webapp for tagging, searching, and reading text archives. The concept: ingest arbitrary text files into a sqlite database, run local LLM prompts against them to apply tags (like TVTropes categories), and browse the resulting library with keyword search, tag search, and boolean operations. Everything runs locally, so there is no risk of a vendor seeing that you are, as Au puts it, Really Into ChArTs.

The tagging system supports arbitrary prompts. A user can ask the model to identify whether a story resembles a Cinderella story and emit a tag if so. The system also includes embedding clustering to de-dupe tags across the collection. For users with comic or manga archives, the same pipeline can work with OCR'd transcripts, linking each scan to searchable text.

The concept is straightforward. The interface went through four major revisions in a short time, each one a lesson in product design.

Four Iterations of a Single Page

The first version was a simple form: apply a prompt, pick a model, run it on all or some stories. The page also had a clustering pass for de-duping tags and a list of job histories. The top navigation had only the bare minimum features.

The second version added a "sync library from disk" feature, which pulls a disk archive and updates entries, like refreshing a wget-captured site. The sync job lived on the same page as the tagging job, which made the page feel cluttered. The top nav picked up more menu items.

The third version simplified walls of text by placing functionality behind expandable sections and moved less-used functions into a "manage" dropdown. Dark mode appeared so Au's eyes would not melt. The interface got cleaner, but the mental model of the program grew more complicated.

The fourth version had to put some of those walls of text back in because things had become too simple without them. The current version is still verbose, with calls to action that are not natural. But these are small complaints compared to the larger design problems that emerged from building a working tool.

Decisions the Code Cannot Make

Au's GPU is an RTX 3070 with 8GB of VRAM. One test dataset was going to take eight days to process. That constraint forced design decisions about crash handling, job resumption, and a job scheduler to maximize prompt cache hits. These are not coding challenges. They are product decisions about how the system behaves under real-world limitations.

Other decisions accumulated: story names should sort while ignoring stop words like A, An, and The. A "more from this author" section seemed like a good idea but turned out to be boring and needed replacing. Font size, color contrast, and horizontal text width all needed tweaking to be readable. Each one is a small judgment call that has nothing to do with making the software function and everything to do with making it not torture to use.

Au frames this as empathy for UX designers and product managers. With near-unlimited engineering resources, at least on a $20 monthly plan, the bottleneck is not articulating requirements to the LLM. It is deciding what the requirements should be: what layout, what wording, what features, what interactions. Once those decisions are made, telling the LLM what to build is generally easy.

What the LLM Era Actually Teaches

The common narrative is that LLMs are making programmers worse by letting them skip the deep work of writing code by hand. Au's experience points somewhere different. For someone who was never going to be a strong coder anyway, the LLM removes the engineering barrier and exposes the product design work that was always there. Anticipating user needs, composing features into a usable whole, and making judgment calls about interaction patterns, those are the skills that matter when the code writes itself.

This is not a universal lesson. Experienced engineers who enjoy the craft of coding may feel genuine loss as LLMs handle more of the work. But for the growing population of people who need software to solve specific problems and do not want to become software engineers, the LLM shifts the bottleneck from "can I build this" to "should it work this way." That is a product design problem, and it does not get easier with better code generation.