The old way

Rethink Everything

Almost every best practice I taught was an optimization for the human programmer. The human isn't the one writing the code anymore, so I'm rethinking all of it.

By Avi Flombaum 10 essays 5 min read

I tweeted this the other day:

If you aren't rethinking every single assumption, preference, and workflow about programming (and infrastructure/devops etc), you're just not fully prepared to leverage AI. The old way is dead. Kill nostalgia. The future is bright.

A lot of people agreed. A lot of people got mad. Either way, I owe the argument.

Quick context, and I'll only do this once. I co-founded Flatiron School and taught thousands of people to code, mostly Ruby and Rails. For years I stood in front of students and preached: code is written for humans to read. DRY it up. Write your unit tests. Never do the big rewrite. Keep the monolith majestic. And please, for the love of god, stop reaching for microservices.

I believed all of it. I was right, too, for the world we were in.

What I used to preach

Years ago I wrote an essay about why we taught Ruby first. Rereading it now is strange.

I wrote that Ruby was the only language I knew of that was invented for your happiness. That it "values you, the programmer, over the machine." I wrote that programming is an art, like poetry or music, and that the most important thing a student could learn was to "fall deeply and profoundly in love with code."

I meant every word. I still do, mostly.

I also quoted Dijkstra: "The tools we use have a profound (and devious!) influence on our thinking habits." My point was that Ruby's values shape how Rubyists think. Happy programmers play. Free programmers invent. That's why Rubyists gave us Rails and Bundler and GitHub.

Here's what I didn't see coming. Dijkstra was right, and the tool changed.

Who is the programmer now?

Ruby valued the programmer over the machine. So did almost every best practice we have. Each one was an optimization for a human who had to read the code, maintain it in two years, get hired and onboarded, and hold a system in their head while getting tired and forgetting things.

Readability was for humans. DRY was so a human wouldn't forget to update the second copy. The testing pyramid existed because humans hated maintaining slow browser tests. Picking the language your team already knew was about hiring humans. Shipping an Electron app instead of three native ones was about the humans you could afford. Paying Vercel was because a human didn't want to learn nginx.

I'm not the programmer anymore. Not mostly. Agents write the code. Agents read it. Agents maintain it. I plan, I verify, and I decide. My own happiness at the keyboard, the thing Ruby was built around, isn't the constraint.

So the values reshuffle. Maintainability, team familiarity, speed to expertise, one language everywhere: all of that has slid way down the list. Context, isolation, fast feedback loops, and parallel work streams have shot up.

Once I started asking "is this optimized for me, or for the agent?" I couldn't stop. Nearly everything I believed failed the test.

What I've changed my mind about

Each of these gets its own post with a real example and an honest comparison, old way next to new way, because opinions without examples are just tweets.

  1. 1 Code is written for humans to read Stop writing and reading code

    You're never going to maintain it. My job is plans, specs, and verifying behavior. Reading every diff line by line is the new bottleneck, and the bottleneck is me.

  2. 2 Never rewrite from scratch Rewrites might be better than massive refactors

    The old codebase is the perfect cheat sheet for an agent to plan against. Wrap it in e2e tests, have one good planning session, and a working port is often a one shot. "Never rewrite" was advice for a different economy.

  3. 3 Use the language your team already knows Language strengths over language familiarity

    I'm a Rubyist shipping Go and Swift. The agent is fluent in everything, so pick the language that's best at the job, not the one your team happens to know.

  4. 4 Build it once for the web and wrap it Go native everywhere

    We used the web as a platform because it was easier for humans. Electron, web views, React Native, one codebase for every screen. Agents write Swift and Kotlin just fine. Stop settling and build the real native app.

  5. 5 Keep the monolith majestic Microservices in a monorepo

    I hated microservices. Agents excel at them. Small services mean small context and no stepping on each other. One monorepo means any agent can still see the whole system when it needs to.

  6. 6 Pay someone else to run your servers Own your infrastructure

    Manage your own until you really need managed. Bare metal over cloud. Leave Vercel behind. Coolify on a cheap box plus an agent that knows Linux better than I ever will.

  7. 7 Don't repeat yourself Duplication over abstraction

    Not ActiveRecord. I mean the app level modules, mixins, and dependency injection that force everyone through one shared file. Two agents editing the same concern is a merge conflict waiting to happen. Let things duplicate.

  8. 8 Types are ceremony Types help agents

    TypeScript, I don't hate you anymore. The cost of types was paid by the human typing them. Now the compiler is a free, instant feedback loop for the agent.

  9. 9 Respect the testing pyramid More e2e tests, fewer unit tests

    E2E tests were brittle to maintain, and now the agent maintains them. Left alone, agents write piles of unit tests that prove nothing. Test that the user can do the thing.

  10. 10 Refactor for readability Optimize for the agent

    Refactoring for my readability isn't worth it anymore. I ask the agent to refactor the code so it's easier for it to work with. Explicit over magic. Greppable over clever.

Kill nostalgia

I know how this sounds coming from a Ruby guy. Rails is still home. I build on it every day, and I still think Ruby is the most beautiful language I've ever written.

But most of the pushback I get, and most of the pushback I give myself, isn't technical. It's identity. We spent years getting good at a craft, and admitting the craft moved feels like a betrayal.

In that same essay I told students not to define themselves by their first programming language. Languages are tools. The real skill is learning how to learn. I said it about Java versus Ruby, back when that felt like a big deal.

Turns out the advice was bigger than I knew. Don't define yourself by your first language, or your favorite framework, or the practices you spent a decade teaching. This series is me taking my own advice, a little late.

Some of these I'll be wrong about. I'd rather find out by building than by defending what I already believed.