LowCode CTO
Stephan Smith LowCode CTO
← Build in Public

I’ve been writing software for fifteen years. For most of that time, good engineering meant building abstractions, writing defensive code, and designing systems that could survive ten years of scope creep.

Those habits are hard to shake. And most of the time, you shouldn’t shake them.

But when I started building AI-native features into Fractional Tools, I kept running into a specific kind of friction: the patterns that had made me effective were slowing me down in ways I didn’t immediately recognize.

The specific patterns I had to unlearn

Abstraction layers everywhere. I kept wanting to build a clean abstraction over the AI layer — a provider-agnostic interface so I could swap models without touching business logic. This made sense at the time. It also added two weeks of work before I’d written a single feature that worked.

The reality: at this stage, I’m using one model for one task. The abstraction was solving a problem I don’t have yet. I deleted it and moved on.

Over-validating inputs. I had validation logic checking every field before passing data to the model, because that’s what you do when you’re talking to a database or a payment processor. With LLMs, the model handles malformed input far better than any rigid validation I could write. What actually matters is the output — and I was spending almost no time on that.

Treating prompts like configuration. I stored my prompts in a config file, versioned them carefully, and wrote a whole system for swapping them per environment. This made sense until I realized I was changing prompts every two hours during development. They needed to live close to the code that used them — not in a separate config layer.

What AI-native actually means

It’s not about using AI as a feature. It’s about changing what you reach for first.

Old pattern: I define the data structure, write the logic, handle the edge cases, and add the AI as a finishing layer.

New pattern: I give the AI the problem, see what it does, and build the structure around what actually works.

This sounds like a small shift. It isn’t. It changes how you scope work, how you estimate time, and what “done” means on any given day.

The uncomfortable part

The uncomfortable thing about unlearning is that you can’t always tell when a pattern is a legitimate best practice versus a habit that made sense in a different context.

I still catch myself writing code the old way. Usually it’s fine. Sometimes I notice it’s wrong for the problem at hand, and I delete it.

The only reliable signal I’ve found: if you’re spending more than two hours on scaffolding before you’ve confirmed the core thing works, you’re probably carrying a pattern that doesn’t belong here.