← Back to Blog

Six Iterations to Get Here: The Long Road to Launch

Team Bonjour

There's this idea in software that you should "ship fast, iterate later."

We tried that. We shipped fast. Then we realized the whole foundation was wrong. So we rebuilt. Then we shipped again. And realized we still didn't have it right.

Six times. We rebuilt Bonjour from scratch six times before we got to what you see today.

Here's what each iteration taught us.

Iteration 1: The React SPA (Too Complicated)

Our first real version was a React single-page app. State management with Redux. Complex routing. Optimistic updates everywhere.

It looked impressive. It felt like "real" software.

But it was a nightmare to maintain. Every feature took three times longer than expected. Bugs were everywhere. The bundle size was massive.

What went wrong:

We over-engineered for scale we didn't have. We were two people building for teams of 5-10. We didn't need a complex SPA architecture.

What we learned:

Start simple. Optimize for speed of iteration, not theoretical scale.

Iteration 2: The Rails API (Too Many Layers)

After the React nightmare, we swung the other way. A clean Rails API backend. A simpler frontend with just vanilla JavaScript and Stimulus.

Separation of concerns! Clean architecture! REST endpoints everywhere!

Except now we had two codebases to maintain. Every feature needed both backend and frontend work. We were moving slower, not faster.

What went wrong:

The separation was artificial. For our use case, the API layer was just overhead.

What we learned:

Sometimes monoliths are the right answer. Especially for small teams.

Iteration 3: The Hotwire Version (Almost There)

Rails 7 had just released with Hotwire (Turbo + Stimulus). Server-rendered HTML with sprinkles of JavaScript. Fast. Simple. One codebase.

This felt right. We rebuilt the whole thing with Turbo Frames and Turbo Streams. Real-time updates. Fast page transitions. Minimal JavaScript.

For the first time, we were actually productive. Features that took days now took hours.

But there was one problem: The AI integration was clunky.

What went wrong:

We wanted AI to feel conversational and real-time. But Hotwire wasn't designed for that kind of interaction. The chat interface felt bolted-on.

What we learned:

Pick the right tool for each job. Hotwire was perfect for the main app. But AI needed something more dynamic.

Iteration 4: The Hybrid (Hotwire + React Islands)

We kept Hotwire for the core app. But we added React "islands" for the AI chat and other interactive features.

Best of both worlds! Fast server rendering + rich client interactions where needed!

It worked. But it also meant we had two mental models in one codebase. Two ways of handling state. Two patterns for developers to learn.

What went wrong:

Complexity crept back in. Not as bad as iteration 1, but still too much cognitive overhead.

What we learned:

Consistency matters. Mixed paradigms work in theory, but they're exhausting in practice.

Iteration 5: Back to Hotwire (All In)

We decided: Hotwire everywhere. Even the AI chat.

We rebuilt the AI interface using Turbo Streams for real-time updates. It wasn't as smooth as React, but it was good enough. And now the whole codebase was consistent.

This version almost shipped. We were weeks away.

Then AI coding tools got really good. And we realized we'd been solving the wrong problem.

What went wrong:

Nothing was technically wrong. But we were about to lock ourselves into an architecture that would be hard to change.

What we learned:

Sometimes the best time to rebuild is right before launch—when you can still see the mistakes you haven't made yet.

Iteration 6: Laravel + Livewire (The Final Version)

Here's what changed between iteration 5 and 6: AI agentic coding became practical.

Tools like Claude Code and Cursor let us experiment at a speed we'd never experienced before. We could try things, break them, fix them, and try again—all in the same day.

We realized: We'd been optimizing for maintainability at the cost of velocity. But with AI-assisted coding, maintainability looked different.

So we rebuilt one more time. Laravel + Livewire. Similar philosophy to Hotwire, but in the PHP ecosystem:

  • Server-rendered by default
  • Real-time updates via WebSockets
  • Minimal JavaScript
  • One paradigm, one language, one mental model

But this time, we built it with AI as a partner, not just a tool.

What went right:

Everything clicked. Features that took days in iteration 5 now took hours. The AI understood our patterns. The code was cleaner than anything we'd written before. And most importantly: We were having fun again.

What we learned:

The tools you use to build shape what you build. When coding becomes faster, you can afford to experiment. When experimenting is cheap, you find better solutions.

Was It Worth It?

Six iterations. Two years. Countless rewrites.

Was it worth it?

Honestly? We don't know yet.

But here's what we do know: Each iteration taught us something we couldn't have learned any other way.

We learned what mattered. What didn't. What was essential. What was just complexity in disguise.

And we learned that building software isn't about getting it right the first time. It's about being willing to be wrong—repeatedly—until you're finally right.


Next: How AI Agentic Coding Changed Everything

Ready to try Bonjour?

A hyper-focused feed for your team. No endless lists. Just the work that matters.