Why I Prefer Opinionated Frameworks When Using LLMs

The more I use LLMs to write code in today’s brave new world, the more I appreciate old opinionated frameworks like Ruby on Rails. While I can’t say for certain if LLMs write better code using these frameworks, the output is certainly far easier to reason about in your head.

Since LLMs reduce the cost of writing code to near zero, there’s a tendency to move much faster and write more lines of code, which can lead to a drop in understanding what’s happening in a code base. And that’s dangerous over time.

A Brief Trip Down Memory Lane

I started building websites with HTML and CSS in the late 1990s. By the early 2000s, I had added PHP my repertoire, enabling me to build templates instead of trying to keep a bunch of static page designs in sync – and that felt like a superpower.

A few years later, I got a part-time job working for my university’s web team. They had built a CMS from scratch in PHP, and my job was to help improve accessibility (while fielding hundreds of password reset calls from students and professors).

That job taught me something I still think about: Bespoke software is incredibly hard to reason about as it gets more complex – especially if you weren’t the one that wrote it.

Then, I found Ruby on Rails.

The beauty of Rails is that it gives you a map. Models live in one place. Controllers live in another. Views follow predictable names. The entire database schema is visible in one file. The framework has strong opinions about nearly everything.

The “Rails Way” did not just eliminate boilerplate code with magic, it eliminated a whole category of decisions and made it easy for anyone to jump into a project.

What Does This Have to Do with AI?

LLMs generate code by predicting likely tokens based on patterns in their training data, which means they are influenced by the shape of code they’ve seen before.

In a convention-heavy framework like Rails, that shape is extremely consistent.

Ask an LLM to create user sign-in functionality in Rails, and I can make some reasonable assumptions about what it will produce. There will probably be a User model. Authentication logic will likely be in a controller. Views will live somewhere predictable. Migrations will follow a familiar structure. Routes will be wired through the usual Rails conventions. And so on.

The code may not be exactly what I want (e.g., if I want to use an email instead of a username). But I know exactly where to look to make any changes.

Compare that to a less opinionated framework like Express.

Express is designed for flexibility; but it comes at a cost. Routes might live in one file or many. Controllers may or may not exist. Database code might be organized by model, service or something else. And middleware may be composed in many different ways.

This isn’t wrong or incorrect, but it’s a larger review surface.

The Real Issue is Cognitive Load

It’s easier for me to trust AI-generated code when I can understand it at a glance.

With Rails, I can inspect a generated feature against a shared set of expectations. If the LLM adds roles to users, I know to check the User model that’s always in the /models directory. You can grep things much faster in your head.

With a less conventional project, I can still review the code. But I have to spend time figuring out the architecture before I can evaluate the implementation. And I have to remind myself of those past decisions for each subsequent feature.

If the project follows strong conventions, each new feature has a predictable shape. And I don’t have to rely on fuzzy prompting in CLAUDE.md, AGENTS.md or skills (although these are also useful for project-specific preferences of course).

Convention Helps Humans Verify Machines

Convention over configuration feels like it has renewed important in the AI era.

The benefit is not just that LLMs may produce more predictable code in convention-heavy frameworks – though I suspect they often do. The bigger benefit is that us humans can verify the output faster and reason about the entire system in our heads.

Convention-heavy frameworks give us a shared map. They reduce unnecessary choices. They make surprising code easier to spot. They let us spend less time asking, “Where did this go?” and more time asking, “Is this correct?”

And that helps a quazi-Luddite like me be more comfortable with LLM-generated code.