Skip to content
BETACurrent release v2025.12Release notesGitHub

My thoughts on AI

I’m a BT (Before Tokens) developer. I’ve embraced AI, but I haven’t handed it the keys to the building.

I’ll get something out of the way immediately.

I use AI. A lot.

It writes a considerable amount of my code these days, and I make absolutely no apologies for it. I think it’s an extraordinary technology, and I’m genuinely excited about what it makes possible.

But I also think we’re developing some rather strange expectations about what it means to be a software engineer.

I hear people talking about AI replacing developers, entire applications being built through prompts, and how we’ll soon have no need to understand programming languages.

Perhaps I’m getting old, but I think we’re confusing the ability to produce code with the ability to engineer software.

They’re not the same thing.

I remember programming before ChatGPT, Claude, Copilot, and all the other AI tools appeared.

I’m what I like to call a BT developer. Before Tokens.

Back in those dark ages, if you had a programming problem, you had to investigate it yourself.

You’d find yourself thirty Stack Overflow tabs deep, reading documentation, digging through GitHub repositories, experimenting with obscure examples, and occasionally consulting a book.

An actual book. Made of paper. With words printed on it.

Barbaric.

You’d spend hours tracking down a problem, only to discover that the solution involved changing one line of code.

And Stack Overflow, bless it, wasn’t always the friendliest place for beginners.

You could ask a perfectly reasonable question and find yourself downvoted into oblivion, told it was a duplicate of something vaguely related from 2009, and informed by someone with 400,000 reputation points that you clearly had no business being a programmer.

We’ve all seen it.

But there was something valuable about that process, even if it was occasionally infuriating.

You learnt how to investigate problems. How to read documentation. How to reason about code you didn’t write. How to experiment, fail, and eventually understand why something worked.

You developed an instinct for when something didn’t look quite right.

That’s the experience I bring to working with AI today.

And I don’t think developers coming into the industry now should have to suffer through precisely the same process to develop those skills.

Quite the opposite.

I think AI can make learning considerably better.

Where AI helps my work, and where it does not

Section titled “Where AI helps my work, and where it does not”

I don’t particularly enjoy writing code for the sake of writing code.

I enjoy building things.

A mechanic doesn’t become a mechanic because they love unscrewing bolts, and a sculptor doesn’t spend years learning their craft because they particularly enjoy hitting things with a chisel.

Those are tools and techniques used to achieve something.

Programming is much the same for me.

I have an idea, a problem to solve, or something I want to create. Code is how I make that happen.

And AI has become an incredibly useful tool in that process.

Think of the difference between a manual screwdriver and a power drill.

The drill can drive a screw considerably faster than I can by hand. But I still need to know where the screw goes, what angle it needs, how deep to drive it, and whether I should be drilling into that particular wall in the first place.

The drill doesn’t design the building.

It just makes part of the work easier.

That’s how I see AI.

Imagine having an extraordinarily talented junior developer who can write code at ridiculous speed, knows the syntax of dozens of languages, has read an enormous amount of documentation, and is available whenever you need them.

Sounds brilliant.

Now imagine that same developer occasionally invents functions that don’t exist, confidently misunderstands requirements, and introduces subtle bugs while insisting everything is working perfectly.

Still brilliant, but perhaps don’t give them unrestricted production access just yet.

That’s broadly how I approach AI-generated code.

I explain what I’m trying to achieve. I provide context, constraints, architectural decisions, and expectations.

It produces an implementation.

Then I review it.

Not just a quick glance to check whether the code looks pretty. I want to know whether it’s correct, maintainable, secure, efficient, and consistent with the rest of the application.

I’ll change things I don’t like. I’ll reject unnecessary abstractions. I’ll question why a particular dependency has been introduced. I’ll ask for alternatives when something feels wrong.

Sometimes I’ll throw the whole implementation away and take another approach.

And sometimes AI produces something genuinely better than what I had in mind.

Fantastic. I’m quite happy to learn from it.

The important thing is that I’m still making engineering decisions.

AI can write my code. It doesn’t get to make my engineering decisions.

We’ve been using tools to automate programming for decades.

Code generators, scaffolding tools, IDE refactoring, project templates, ORMs, compilers, build systems, and deployment pipelines.

I can run Vite, select a few options, and have an entire project structure generated for me without writing a line of it myself.

Nobody seriously argues that I’m not a developer because I didn’t manually create every configuration file.

AI takes that idea considerably further.

Instead of generating a predefined template, it can create code tailored to a specific task.

That’s an enormous improvement in what automation can achieve.

But just as I wouldn’t blindly trust a scaffolding tool to make every architectural decision correctly, I don’t blindly trust AI to do so either.

The output still matters. The implementation still matters. The consequences still matter.

AI chat is useful, but I’ve become particularly interested in working with coding agents.

There’s a difference between asking an AI to generate a function and giving an agent a task within an existing codebase.

The latter requires considerably more discipline.

An agent needs to understand the project, the conventions, the architecture, and what it’s allowed to change.

Otherwise, you risk something I’ve encountered often enough: a tool confidently producing a perfectly reasonable solution to a problem you didn’t actually have.

I like to start projects with an AGENTS.md file.

It’s effectively a set of working instructions for anybody, human or AI, interacting with the project.

It can describe the technology stack, architectural boundaries, naming conventions, development commands, testing requirements, and decisions that shouldn’t be casually overturned.

For example, if I’ve deliberately chosen not to introduce an ORM, I don’t want an agent installing one because it happens to be familiar with Entity Framework.

If the project uses a repository pattern for storage, I want new functionality to respect that boundary.

And if we’re building a small standalone binary, I don’t want a dependency tree the size of Greater London appearing because the agent needed to parse a command-line argument.

Which brings me neatly back to The Floppy Rule.

Giving an agent context is no different in principle from onboarding a new developer.

You wouldn’t reasonably expect someone joining a project to understand every architectural decision by looking at three source files.

So why expect an AI to?

I try to give agents clear, bounded pieces of work.

Implement this component. Add these tests. Refactor this service. Investigate this performance issue. Compare these approaches.

Something with a defined objective and a result I can evaluate.

For larger work, I prefer breaking things into sensible stages, with opportunities to review the results before continuing.

I don’t particularly like the idea of asking an agent to build an entire product, disappearing for a few hours, and then deploying whatever comes back.

That’s not my idea of engineering.

That’s gambling with a keyboard.

One of the most useful things you can do when working with AI is review the changes it has made.

What files were modified? What dependencies were added? Has existing behaviour changed? Are the tests meaningful? Has it introduced unnecessary complexity?

And perhaps most importantly, do I understand what it’s done?

If I don’t understand an implementation well enough to explain it, debug it, or modify it, I’m not comfortable approving it.

AI doesn’t change that standard.

In fact, the speed at which it generates code makes reviewing the work even more important.

A developer might spend a morning writing 200 lines of code. An agent might produce 2,000 lines before you’ve finished your coffee.

That’s a lot of potential mistakes arriving very quickly.

I’m also careful about the permissions and access I give coding agents.

There’s a considerable difference between allowing an agent to modify source files and allowing it to deploy production infrastructure, delete databases, or access sensitive credentials.

I don’t believe every action needs a human manually pressing a button. That rather defeats the point of automation.

But risky operations should have appropriate safeguards.

Use limited permissions, isolated environments, tests, version control, and approval points where the consequences justify them.

An agent having the technical ability to do something doesn’t automatically mean it should be authorised to do it.

As someone once observed in Jurassic Park, the question isn’t simply whether we can do something.

It’s whether we should.

I don’t have a particular problem with AI generating a function, an API endpoint, a database migration, or even a substantial part of an application.

But there are responsibilities I don’t intend to hand over blindly.

Before deciding how to solve something, I want to know what the actual problem is.

Who needs it? Why? What constraints exist? What happens if we get it wrong?

AI can help explore those questions, but it can’t replace understanding the people, business, and circumstances involved.

Sometimes the correct solution is a small function.

Sometimes it’s changing a process.

Sometimes it’s telling a stakeholder that their idea doesn’t quite make sense.

And sometimes it’s not writing any code at all.

I want to own the important decisions about how the software is structured.

That doesn’t mean refusing suggestions from AI. Quite the opposite. I enjoy asking it to challenge an approach, identify weaknesses, or propose alternatives.

But I want to understand the trade-offs before committing.

I’ve made enough architectural mistakes myself to know that an impressive diagram doesn’t guarantee a good system.

I don’t need AI to help me build five APIs, three frontends, RabbitMQ, Redis, and a Kubernetes cluster when one API and a database would do.

I’ve already managed that mistake perfectly well on my own.

This one is particularly important to me.

If AI generates some code and I approve it, merge it, and deploy it, that code is my responsibility.

Not ChatGPT’s.

Not Claude’s.

Mine.

I can’t reasonably turn around when something breaks and say, “Well, the AI wrote it.”

I chose to use the tool. I reviewed the output. I accepted the change.

The same principle applies when another developer contributes code to a project I’m responsible for.

Delegating the implementation doesn’t transfer accountability.

AI can sound incredibly convincing, even when it’s completely wrong.

And because it produces answers so fluently, it’s tempting to accept them without questioning the assumptions.

That’s dangerous.

I want to retain the ability to look at a proposed solution and think, “Hang on, that doesn’t seem right.”

To investigate. To test. To challenge.

To disagree with the machine.

Especially when it’s being very polite about telling me something utterly ridiculous.

This is where I think AI has some of its greatest potential.

I don’t subscribe to the idea that new developers should be banned from using AI until they’ve suffered through several years of traditional programming.

That sounds suspiciously like the argument that because we had to struggle, everyone else should too.

What a load of rubbish.

If somebody is learning programming and doesn’t understand a loop, AI can explain it.

If the explanation doesn’t make sense, it can try another approach.

It can use diagrams, analogies, practical examples, or step-by-step exercises.

It can adapt to how that particular person learns.

And crucially, it doesn’t get irritated because you’ve asked the same question seventeen times.

Compare that with the experience of being a beginner on Stack Overflow, where asking the wrong question could occasionally feel like wandering into a pub and announcing you’d never heard of beer.

Nobody should be made to feel stupid for trying to learn.

I think that’s a genuinely wonderful opportunity.

But there is a distinction between using AI to learn programming and using AI to avoid learning programming.

I wouldn’t hire a developer who couldn’t explain an if statement.

I don’t particularly care whether they learnt it from a university lecturer, a book, YouTube, Stack Overflow, or an AI chatbot.

I care whether they understand it.

Can they reason through a problem? Can they explain the code they’re working with? Can they investigate a bug? Can they recognise when an implementation is wrong?

Can they make decisions without needing an AI to tell them what to think?

Those are the skills that matter.

And I suspect they’ll become more important, not less, as AI makes generating code increasingly easy.

Since we’re discussing AI, I think it’s worth being transparent about something.

A considerable amount of the wording on this website was generated with AI.

There you go. I’ve said it.

I’ve got plenty of opinions, experiences, stories, and occasionally questionable jokes. What I don’t particularly enjoy is spending hours turning those thoughts into perfectly structured articles.

So I use AI to help.

Take my software engineering manifesto, for example.

I didn’t simply ask ChatGPT to “write me a software engineering manifesto” and publish whatever came back.

I worked through the principles individually, explaining my opinions, sharing experiences from projects I’ve worked on, giving examples of mistakes I’ve made, and occasionally having a good moan about something that irritates me.

AI helped turn those conversations into coherent, readable prose.

Then I read it.

I questioned things I disagreed with. I asked for changes where the wording didn’t sound like me. I added details, removed unnecessary bits, and refined the explanations until they reflected what I actually wanted to say.

The same approach applies to other articles across this site.

The wording may be AI-generated, but the ideas, experiences, opinions, and final approval are mine.

I think that’s an important distinction.

If I dictate an article to somebody who helps organise my thoughts, improves the grammar, and makes the writing flow better, those thoughts don’t suddenly become theirs.

AI is performing a similar role for me, although I still have to watch for the occasional sentence that makes me sound like a motivational speaker addressing a conference of management consultants.

And I’ll happily admit that AI sometimes suggests wording or arguments I hadn’t considered. If they’re useful and I agree with them, I’ll incorporate them. If I don’t, they’re gone.

That’s collaboration, not surrendering authorship.

I’m not trying to pretend that I personally typed every word on this website.

I don’t think that’s particularly important.

What matters to me is whether I understand what’s being published, whether it represents my views, and whether I’m willing to stand behind it.

AI helped me write this website. It didn’t live my experiences, form my opinions, or approve the finished articles. I did.

And yes, AI helped write this explanation too.

Naturally.

I don’t have a crystal ball.

If I did, I’d probably have made some considerably better technology investments over the years.

But I do have a few opinions.

I sometimes wonder what a software engineer from the 1970s or 1980s would think if they sat down at a modern developer’s workstation.

Back then, programming could mean working with punch cards, terminals, limited memory, expensive computing time, and debugging techniques that make today’s error messages look positively luxurious.

Debuggers existed, of course, but we’re talking about an era when you couldn’t necessarily set a breakpoint, hover over a variable, inspect an entire object graph, and casually step backwards through execution.

Many early programmers came from mathematics, science, or engineering backgrounds. Computing was a considerably more specialised discipline, and understanding the underlying hardware was often a necessity rather than a curiosity.

Then came the personal computer revolution.

By the 1990s, developers increasingly had access to graphical IDEs, integrated debuggers, higher-level languages, reusable libraries, and tools that automated work previous generations had done manually.

Imagine telling a programmer from 1975 that a future developer could drag a button onto a form, double-click it, write a few lines of code, and have a working Windows application.

Would they consider that person a real programmer?

Perhaps some wouldn’t.

And yet, here we are.

I remember Visual Basic, early Visual Studio, and the days when autocomplete and graphical debugging felt like magic.

Nobody seriously argues that using IntelliSense means you’ve forgotten how to program.

We didn’t stop being developers when we stopped writing assembly for everything. We didn’t stop being developers when compilers became cleverer, memory management became automatic, or IDEs started generating code for us.

We simply moved further away from the mechanical details and gained more time to concentrate on what we were trying to build.

I think AI is another step in that evolution.

Admittedly, it’s a rather enormous step. Unlike autocomplete or traditional code generators, AI can propose entire implementations and make decisions that look remarkably like engineering judgement.

Which is precisely why understanding and reviewing its output matters.

But I don’t believe spending six hours hunting through documentation makes someone inherently more skilled than somebody who reaches the same understanding in twenty minutes with AI.

The value of an engineer isn’t measured by how difficult their tools make their job.

It’s measured by what they can understand, solve, and build.

I think we’ll spend progressively less time manually translating our intentions into syntax.

That doesn’t mean programming languages are disappearing tomorrow, or that developers will never need to understand code again.

It means the mechanical process of producing an implementation will increasingly be assisted by tools.

More of our time can go towards understanding problems, designing systems, evaluating trade-offs, testing assumptions, and reviewing results.

And personally, I welcome that.

I’ve always been more interested in building things than typing them.

Small teams will be able to achieve considerably more

Section titled “Small teams will be able to achieve considerably more”

One of the things that excites me most is what AI could mean for independent developers and small teams.

Tasks that previously required several specialists may become achievable with fewer people, provided those people understand what they’re building and know how to evaluate the results.

A developer can explore unfamiliar technologies more quickly, prototype ideas, generate initial implementations, and spend more time concentrating on the difficult parts.

That doesn’t mean expertise becomes worthless.

It means expertise can potentially accomplish more.

And as someone who enjoys experimenting with far too many projects, I find that rather appealing.

We’ll generate more bad code than ever before

Section titled “We’ll generate more bad code than ever before”

Here’s the less cheerful prediction.

If AI makes it extraordinarily easy to generate code, we’re going to generate an extraordinary amount of code.

Some of it will be excellent.

Some of it will be dreadful.

And a considerable amount will be perfectly functional code that nobody properly understands.

I suspect we’ll see applications with unnecessary dependencies, convoluted abstractions, questionable security, and entire layers of infrastructure that exist because an AI decided they were a good idea.

In other words, many of the same mistakes developers have always made.

Just considerably faster.

Which is why I think good engineering judgement will remain valuable.

The ability to generate 10,000 lines of code in an afternoon isn’t particularly impressive if you only needed 200.

Am I worried about my job?

Not particularly.

That’s not me claiming AI won’t change employment or that every existing development role is guaranteed to survive. I think the industry will change, and some of those changes could be uncomfortable.

But I’m not convinced that removing the need to manually write every line of code removes the need for software engineers.

The job has changed repeatedly throughout my career.

We’ve moved through different languages, frameworks, development tools, deployment models, and architectural fashions.

We used to do a lot of things manually that we now take for granted as automated.

AI is another significant change, albeit a rather substantial one.

My response isn’t to reject it.

It’s to learn how to use it properly.

And to make sure I still understand the work I’m responsible for.

I’m enthusiastic about AI. I use it regularly, recommend it as a learning tool, and expect it to become an increasingly important part of software development.

I also think there’s something slightly amusing about developers worrying that AI-generated code somehow makes them less legitimate.

Imagine a programmer from 1975 watching us use graphical debuggers, IntelliSense, package managers, garbage collectors, and entire frameworks that do enormous amounts of work on our behalf.

They might wonder whether we’re doing any programming at all.

And perhaps, fifty years from now, somebody will look back at us manually reviewing AI-generated pull requests and wonder why we were doing things the hard way.

Technology changes. Our tools improve. The mechanical work becomes easier.

But I don’t think prompting a machine automatically makes someone a software engineer, any more than owning a power drill makes someone a carpenter.

It’s the understanding, judgement, experience, creativity, and responsibility behind the tool that matter.

If AI helps me build better software faster, fantastic.

If it produces something questionable, I’ll challenge it.

If it suggests something better, I’ll learn from it.

And if it tries to introduce fourteen interfaces, six factories, and an entire dependency injection framework to return a string constant, we’ll be having words.

I’m a BT developer.

I remember what it was like before tokens, and I’m quite happy to be working with them now.

AI is my power drill, not my architect.

I’ll happily let it drive the screws. I’ll still decide what we’re building.

Support the project: Buy Me a Coffee or GitHub Sponsors.