Developing with AI: guardrails, workflow, and the future of our craft

Published <2025-01-01>

Over the past year, our development routine has been evolving faster than ever. Not because we intentionally decided to reinvent how we work, but because the tools around us changed. AI became a constant part of our workflow - first as a helper, then as a collaborator, and now as something embedded into our daily loop.

But something unexpected happened along the way: the habits, structure, and discipline many of us invested in for years - testing, types, architecture, and static analysis - are now the foundation that allows us to embrace AI speed without losing control.

AI is not replacing our craft. AI is amplifying it. But only if we build the right guardrails.

Attention is becoming our least scalable resource

We live in an environment of constant interruptions, infinite content, and shrinking attention spans. AI doesn't reduce this flood of information - it accelerates it. When code, explanations, and refactors can be generated instantly, focus becomes our real bottleneck.

Disciplined engineering now matters more than ever. Not because we need to "beat" AI, but because we need to direct it.

AI is a powerful engine - but blind without a driver

AI is like a car with enormous horsepower but no vision. It can accelerate development dramatically, but it cannot see the road.

A more accurate analogy: AI is a hyper-competent intern with unlimited energy but zero intuition.

It can:

  • produce correct-looking but wrong solutions,
  • misread domain-specific logic,
  • hallucinate missing steps,
  • loop endlessly without noticing.

It has no sense of responsibility. That part stays with us.

Testing, types, and static analysis: our safety net

Years of investment in testing and strong architecture are paying off. AI can refactor or generate code at hyper-speed, but tests and types keep it safe.

Tests aren't just checks - they are trust-enablers. They:

  • confirm correctness,
  • catch wrong assumptions,
  • highlight regressions immediately.

Types are another invisible layer of protection. Often the task is simply: "Run the TypeScript checker and fix the type errors."

Static analysis is essential. AI often:

  • starts a refactor in one file,
  • forgets,
  • continues in another file,
  • or duplicates logic unintentionally.

Linters, type checkers, dead-code analyzers, and code smell detectors protect us from inconsistent or incomplete transformations.

With these guardrails, we can safely let AI touch far more code than we ever would manually.

A real story: migrating multiple libraries with breaking changes

Recently we migrated several major libraries - all with significant breaking changes. AI helped accelerate the restructuring, but the process revealed important lessons.

AI struggled with planning. Broad tasks caused it to:

  • loop,
  • hallucinate steps,
  • or over-apply changes.

We learned to force a new discipline:

  1. Break tasks into extremely small chunks.
  2. Provide file names, line numbers, and exact context.
  3. Only let AI handle one step at a time.

Mocking our RPC endpoints completely confused it. These parts were too custom; we had to take over manually.

Migration guides became AI's compass. When documentation said: "Before you used X, now you must use Y," AI performed flawlessly. Clear patterns eliminate guesswork.

To library authors: please keep writing migration guides - they are invaluable.

Our AI-assisted development cycle

We developed a structured cycle that keeps us in control:

  1. Prompt AI to solve one very specific problem (including file paths, lines, or references to other projects).
  2. Ask AI to reverse-engineer its reasoning into a TODO plan. We keep this file to track progress.
  3. Ask AI to write tests first.
  4. Apply or refine the implementation.
  5. Update the TODO and iterate.

This creates a predictable rhythm: Plan → Test → Implement → Verify → Update → Repeat.

And importantly: not everything should be solved through prompting. Every now and then, we stop, debug manually, and apply necessary changes ourselves. This keeps us connected to the logic, the structure, and the architecture of the codebase.

Human-in-the-loop workflow

To avoid wasting compute and time:

  • we keep a terminal open,
  • run tests and type checks manually,
  • tell the AI the results,
  • prevent it from looping on failures.

Sometimes: "Tests pass. Continue."

We also commit frequently and in small increments. Commit quality declines during intense cycles, but this isn't an issue - we squash everything into a clean final commit before merging.

AI makes big migrations faster - but reviews harder

AI can produce enormous volumes of code quickly. Execution is fast. But reviewing becomes the new bottleneck.

The mental load shifts from building to:

  • catching mistakes,
  • detecting silent regressions,
  • maintaining architectural consistency,
  • ensuring quality isn't degraded.

Long migrations used to be tiring because progress was slow. Now progress is fast - but review and verification are the new mental challenge.

Tests become a progress bar. Every passing test is motivation. Every fixed type error is a breadcrumb.

The "Three Little Pigs" lesson

We are entering an era where AI lets us build more, faster, and at larger scale - including tech debt. AI can generate tech debt at hyper-speed.

Like the story of the three little pigs, the hard work pays off. If we build our house with robust tests, strong types, and solid architecture, AI becomes a force multiplier. If we don't, AI becomes chaos.

A message for developers

AI will not take our jobs. We won't run out of software. We will simply build more of it.

But our responsibilities are shifting:

  • more reviewing,
  • more verifying,
  • more architectural judgment.

AI accelerates execution. We provide the vision.

Let's not stop learning how to code. Let's step up our game - because the only way to steer this powerful but blind car is to build the right guardrails.

When we do, AI can take us farther than ever - but always to the destination we intend.