Automate the Pattern, Not the Typing
August 23, 2026 · Johannes Werner

Automate the Pattern, Not the Typing

TL;DR: I don't automate code because I dislike typing. I automate it when a team has repeated something often enough to understand the pattern behind it. A good generator turns an agreed convention into the easiest way to write new code. It saves time, but more importantly, it reduces opportunities for inconsistency. The trick is knowing when a pattern is mature enough to automate, and when the thinking is exactly the part you should keep doing manually.

Vuesion has had code generators from the beginning.

Today, you can generate components, pages, forms, field sets, tables, state management stores and complete CRUD APIs.

At first glance, the reason seems obvious.

Writing boilerplate is boring.

A generator is faster.

And that's true.

But saving keystrokes is probably the least interesting thing a generator does.

What I actually want to automate is the pattern.

The first time, just build it

I have a simple rule for abstractions:

If I've used something three times, I probably know enough to identify the pattern.

That doesn't mean I automatically abstract everything after exactly three occurrences. Three isn't a magic number.

It's a useful threshold.

The first time I solve a problem, I'm solving that particular problem.

I don't know yet which parts of the solution are fundamental and which parts only exist because of this specific use case.

So I build it.

Then a second use case appears.

At that point, the easiest thing is often surprisingly unsophisticated:

I copy the first implementation.

Then I change whatever needs to be different for the second case.

That is fast, simple and, importantly, deliberately avoids creating an abstraction too early.

Because I've made that mistake plenty of times.

Two examples are often not a pattern

It's tempting to look at two similar implementations and immediately extract the common parts.

I've done it.

Then the third case arrives.

And suddenly the abstraction doesn't fit.

Now I have to change the abstraction, change the two existing implementations that depend on it and still implement the third case.

Instead of saving time, the abstraction created more work.

With three implementations in front of me, I usually have much better information.

I can see which parts actually stay the same.

I can see which parts vary.

I can start distinguishing coincidence from structure.

Sometimes even the third example isn't enough.

That's fine.

I copy it again.

An abstraction doesn't become more valuable because I created it earlier.

I would rather tolerate some duplication for a while than spend the next two years maintaining an abstraction based on assumptions I made after seeing two examples.

Once the pattern is clear, make it the easy path

When a pattern does become clear, I start thinking about automation.

My other rule is roughly:

If I repeatedly have to do something that takes more than five minutes, I look for a way to automate it.

This is where generators become interesting.

Not because a generator can type faster than I can.

But because once the team has agreed on how something should be built, there is very little value in asking every engineer to reconstruct that decision manually.

If we know how a component should be structured, generate that structure.

If we know where its tests belong, generate them.

If we know how a page should be organized, generate it.

If we know how a CRUD API should be structured, don't make the next engineer create fourteen files by hand just to demonstrate that they understood the convention.

Automation should remove decisions we've already made, not decisions we still need to make.

I stole the idea from Angular

The original inspiration for Vuesion's generators came from my work around Angular CLI.

Angular CLI itself was originally built on top of ideas and tooling from Ember CLI, and I loved the experience of generating a component and immediately getting a predictable structure around it.

You didn't just get a file with some code in it.

You got a starting point.

When I started building Vuesion, I wanted something similar without having to build and maintain an entire CLI.

I eventually used Plop.js for it.

The first generators were simple.

Components.

Pages.

State management stores.

Then the patterns grew with the product.

Forms became worth generating because there was a consistent validation setup around them.

When Vuesion gained its backend, backend generators followed.

Today there are generators for things like field sets and tables as well.

The list grew because the number of patterns we understood grew.

Not because I had a goal to generate as much code as possible.

Consider a CRUD API

A CRUD API is a good example because almost every engineer has built one.

In Vuesion, creating one manually would involve quite a few pieces.

There are the endpoints themselves.

Each endpoint needs its implementation and its test.

For the usual CRUD operations, that's already around ten files.

Then there are DTOs.

They need a location, structure and naming convention.

There is a service and its tests.

There are access policies.

Altogether, you're quickly dealing with around fourteen files before you've written much code that is actually specific to the feature.

An experienced engineer can do that manually.

Maybe it takes an hour.

You could also copy an existing API and modify it.

That's often faster.

It's also how you eventually discover a variable called workspaceId inside the user API because someone forgot to rename it.

We've all seen some version of that.

A coding agent can do the same work faster. Perhaps it takes twenty minutes instead of sixty.

But neither of those is the real question.

The interesting question is:

Why are we asking a human or an AI to make the same fourteen structural decisions again?

Fourteen files are fourteen opportunities to drift

Every manually created file creates a small opportunity for variation.

Maybe the test is named slightly differently.

Maybe the DTO goes into another directory.

Maybe one endpoint handles an error differently.

Maybe the service has a slightly different interface.

Maybe someone forgets the access policy.

Maybe an engineer simply prefers another structure.

None of these things necessarily break the application.

That's almost what makes them dangerous.

They accumulate.

Six months later, there are five slightly different ways of implementing the same concept and every new engineer has to figure out which one is the current standard.

A generator changes the equation.

The agreed pattern becomes the path of least resistance.

You answer a few questions.

The generator uses those answers to create as much of the predictable structure as possible.

The engineer can spend their time on the parts that are actually different.

That's why I don't primarily see generators as productivity tools.

They are executable conventions.

A convention you can execute

Documentation can tell you how an API should look.

An architecture decision record can explain why the team chose a particular structure.

An onboarding session can teach the pattern.

Examples in the codebase can demonstrate it.

All of those are useful.

But a generator can do something they can't.

It can produce the agreed structure.

That makes the convention executable.

And that matters because humans are humans.

We forget things.

We take shortcuts.

We copy an old implementation.

We don't notice that the example we're copying predates a decision the team made three months ago.

Or we're under deadline pressure and today's easiest solution seems more important than tomorrow's consistency.

A generator doesn't solve all of that.

It just removes some opportunities for it to happen.

And I've found that to be incredibly valuable.

Generators should evolve with the team

An executable convention should not become a frozen convention.

Teams learn.

Products change.

A pattern that made sense six months ago might no longer be the best one.

I've worked on projects where we changed generators because we decided to change the way the underlying code should work.

The order matters.

Change the generator first.

From that moment on, every new implementation follows the new convention.

Then look at the existing code.

If the change can be migrated safely through automation, great.

Do that.

If not, I usually follow the Boy Scout Rule:

Leave the code better than you found it.

If I touch a file that still follows the old convention, I don't close it until I've moved it to the new one.

Over time, the old pattern disappears.

This is another reason consistency matters so much.

A consistent codebase is easier to search.

It's easier to identify what follows the old pattern.

And sometimes a migration that initially looks like a large refactoring turns out to be a regex and a few minutes of verification.

Not everything should be generated

There is a danger in taking this too far.

Once you start enjoying automation, everything starts looking like something that should be automated.

I deliberately don't generate database models, for example.

Could I build a generator that asks a series of questions and produces a Prisma model?

Probably.

I don't want to.

The data model is one of the places where I explicitly want an engineer to slow down and think.

What are the actual entities?

What are their relationships?

Does this concept belong here?

What will depend on this decision later?

These aren't repetitive implementation details.

They are product and domain decisions.

Automating them would optimize the wrong part of the process.

There are also things I'd like to automate but don't because the automation itself becomes too fragile.

Generating new files is relatively easy.

Modifying existing source files is much harder.

You can start using AST transformations and build increasingly sophisticated tooling that understands the existing code.

I've experimented with that.

The problem is that these tools tend to depend heavily on the exact structure they expect to find.

Someone deviates slightly from the standard and the generator fails.

Then you spend time maintaining the automation.

Eventually it fails often enough that developers stop using it.

At that point, the automation is creating more work than it removes.

The goal isn't maximum automation.

The goal is useful automation.

Code review gets smaller

There is another benefit that is easy to overlook.

Generated code changes what needs to happen in code review.

If I already know that a set of files was produced by a generator that represents the team's agreed convention, I don't need to review those files as if every line contains a new architectural decision.

I can focus on what wasn't generated.

The business logic.

The unusual case.

The thing that actually changed.

That makes reviews faster, but it also makes them more meaningful.

Instead of repeatedly reviewing the team's existing decisions, we can spend our attention on the new ones.

And attention is one of the most limited resources in a software team.

Generators are also documentation

Generators have another useful side effect for new engineers.

They document how the team works.

A new developer doesn't have to find fourteen existing files, work out which ones belong together and reverse-engineer the intended structure.

They can generate the starting point.

That doesn't mean they automatically understand why the structure exists.

And I don't think automation should replace teaching.

Especially with junior engineers, I still like asking:

Do you know why we do it this way?

Sometimes they do.

Sometimes they followed the existing pattern because that's what the rest of the codebase does.

Both are useful starting points for a conversation.

The generator gives them the guardrail.

The senior engineer can explain why the guardrail is there.

Then coding agents arrived

This became even more interesting with coding agents.

Vuesion's generators weren't designed for AI.

They existed long before today's coding agents.

But the underlying problem is remarkably similar.

Give an agent a task in an inconsistent codebase and it has to infer what you probably want.

It searches for examples.

It finds several implementations.

It tries to identify the pattern.

And if those examples disagree with each other, the agent has to decide which disagreement is intentional and which is historical accident.

That's not fundamentally different from onboarding a new developer.

A generator removes part of that ambiguity.

If a task requires a new component, API, page or another known structure, the agent doesn't have to invent the starting point.

It can run the same generator the humans use.

I've seen Codex do exactly that in Vuesion.

So far, it has reliably used the generators when they're appropriate.

I suspect this can also reduce token usage because the agent doesn't need to reconstruct as much of the pattern from the surrounding codebase.

I can't prove that yet, so I won't pretend that I can.

But even without the token argument, there is a simpler benefit:

Humans and agents start from the same implementation of the team's conventions.

That's useful.

The interesting part is what you don't automate

If we keep pushing this idea, software development starts to look slightly different.

Generators can create predictable structures.

Tests can verify predictable behavior.

Design systems can encode UI conventions.

Figma can describe visual decisions.

Coding agents can implement a surprising amount of what remains.

So what is left for the engineer?

I think the answer is:

Thinking.

Automation is good at executing something that has already become a pattern.

But someone still has to discover that pattern.

Someone has to notice where it fails.

Someone has to understand why users struggle with a feature.

Someone has to realize that a concept in the domain model is wrong.

Someone has to decide that a convention which worked for the last two years no longer fits the product.

Someone has to understand what the business is actually trying to achieve.

And a large part of that information doesn't live in the codebase.

It comes from conversations.

From customers.

From meetings.

From watching people use the product.

From understanding the industry.

From experience.

A generator doesn't have that context.

And an AI agent shouldn't magically be expected to have it either.

Automate execution, not thinking

I don't want engineers spending an hour creating fourteen predictable files.

I don't want them debating the same naming convention in every pull request.

I don't want a junior developer reverse-engineering architecture from whichever implementation they happened to find first.

And I don't want a coding agent burning time trying to infer decisions the team already made years ago.

Those problems don't require creativity.

They require execution.

So automate them.

Then use the time you saved to look at the things that aren't predictable yet.

Find the fourth case that breaks the abstraction.

Talk to the customer.

Challenge the domain model.

Question an old convention.

Simplify something.

Teach another engineer why the pattern exists.

Figure out what should be automated next.

The goal of automation isn't to remove engineers from software development.

It's to remove the parts of software development that don't require an engineer to think.

This is how I build Vuesion

These aren't just ideas I write about. They're principles I've been building into Vuesion for more than eight years.

See how Vuesion works →