Why AI Can’t Write Good Software
On their own, large language models cannot write good software, but they can help you write good software. Why can’t they write good software? Because good software is both elegant and effective.
Elegant in that the software achieves its goals with minimal complexity—each component serves a clear purpose with no unnecessary abstraction. Effective in that the software solves the immediate problem while remaining adaptable for future needs. But why can’t they do this? Because finding one of the rare optimally simple solutions requires a depth of vision that LLMs do not possess. LLMs are simply too shortsighted, their abstractions are not abstract enough.
LLMs are great at starting from scratch but they struggle with software design. Implementation is like walking a well-trodden path, whereas design is choosing where to put the new path. LLMs succeed at the former because the path is well-trodden—it’s just pattern matching what it has “seen” before.
Asking an LLM to implement something with no prior art is essentially asking it to design, and LLMs often get design wrong because they will try to shoehorn an old square peg into the new round hole, and it just won’t fit.
This is why “vibe-coded” software quickly crumbles under its own weight. The LLM’s shallow design plots an ill-conceived path directly into an architectural dead end; and this lack of vision that you brought you into this mess is definitely not going to help you out of it.
Take your “co-pilot” out of the pilot seat. Lead the design. Do not ask the LLM to write a 20-page design document. Instead, you write a high-level 2-page design document for humans. Then, you split your design into components, and again, you design the first small component. This is what you hand over to the LLM: a well-scoped, small scale, clearly defined piece that specifies the software at a level it can run with; this is where the LLM can excel—by being micro-managed into implementing your vision rather than inventing its own.
This is how you produce good software with AI: you first acquire some architectural vision and a good feel for software design, then you meter out bite-sized chunks of work to the LLM. You let it write code within tight constraints, using unit tests and agent directives, and most importantly, don’t let the LLM write more than about 500 lines at once. Large code changes often suggest the LLM has fallen onto the design side of the fence, where it’s likely to mess up the path, and the rest of the garden. You must choose where the path goes; and then you help the LLM walk it.

