I've created an Advanced CDK course, you can check it out here!

BlogAbout MeTimelineGitHubLinkedIn

AI and the Future of Software Development

Cover Image for AI and the Future of Software Development

Since the release of ChatGPT in late 2022, AI has been a hot topic in the tech world. Whether you think it's an overhyped fad, the next big bubble, or the future of everything, it's clear that AI is here to stay. While initially bearish on the subject I decided to embrace the tools at the beginning of the year. There was a growing dread in me that if I didn't learn to use these new tools that I'd be left in the dust. I'm already starting to age-out of this profession and regardless, any developer that doesn't leverage the best tools at their disposal will fall behind the crowd.

Through my normal day-to-day work tasks, and a game I've always wanted to see made, I purposely used AI first to see where I benefited from it, and where it got in the way. After nearly 11 months of using AI tools, I've come to some conclusions about the future of software development.

My Background

I have been developing software for the better part of 3 decades now. Technically I think I could go back to the 90s, but I was in high school or early in college, and I wasn't really producing anything of value (even though I did technically get my first contract writing a Java app back in 1999).

I've primarily focused on Line of Business applications for the first part of my career, building applications that were used internally to help businesses run more efficiently. Around 2014 I transitioned into public facing applications which continued until approximately 2019 when I was working for Rackspace and was moved from a development role into DevOps. I initially liked the position as it allowed me to write software for my fellow developers, a space I felt I knew well and I enjoyed bringing efficiencies to my fellow coders.

The last few years I've primarily been doing DevOps work in the AWS space and architecting solutions for our clients. While it has allowed me to do some development work, it's certainly not enough to scratch my coding itch.

To try to evaluate these tools more, I picked up a side project which has been lingering at the back of my mind for the better part of ten years. It's a game that takes cues from Tradewars 2002, an old Bulletin Board System (BBS) game that I played in the 90s. The game is a space trading and combat game where you fly around the galaxy, trading goods between planets and fighting other players. I call my game Ethrwars.

I had built part of it many years ago using Ionic and NodeJS. Being pretty familiar with Javascript at the time meant that I focused mostly on the game logic and less on learning anything new, although the Ionic Framework did take some time to learn and adjust to.

This time around I wanted to do something very different. I wanted to build it using Flutter for the game client and use AWS for the backend, with Rust being the language of choice for the Lambda Functions. I picked Flutter and Rust because while I could read the code, I wasn't proficient at writing the code. I'd be forced to rely on AI for writing the majority of the systems. Also, both seem to be their own "best" technologies right now and felt like a good technical footing for which to build my game.

Tools Covered

I've used 4 tools during this process to varying degrees. There are certainly others in the space, and I'm confident that readers will point to their favorite and say "why didn't you use ___" or "you didn't use ___ right". That's fine, because my goal wasn't to do a comprehensive review of all the tools, but rather to see how AI augmented my workflow which I don't think was highly dependent on the specific tool. But, I did try a few different types of tools to see how they compared.

  • GitHub CoPilot - minimal, it mostly popped up from time to time while using Jetbrain's WebStorm IDE
  • Cursor - heavy use at the beginning but tailed off with increase Kiro use
  • Kiro - heavy use during the private preview period (end of June) through mid-August
  • Claude Code - mostly used since mid-August onward
  • Q Developer - only used sporadically to compare to Claude Code

While I initially felt that the tool of choice wasn't a big differentiator (because the underlying model was the magic) that opinion changed over the course of the year and certain tools fit better into my development approach then others.

Getting Started

(Using Cursor)

I began with bootstrapping the project and immediately ran into problems. I asked it to set up the Flutter project, and it struggled to make anything compile as I didn't have Flutter installed. Asking it to get Flutter installed was unsuccessful causing me to fall back to doing it manually, yuch. This was all through the 'vibe coding' process.

However, early decisions or unclear requests resulted in easy fixes. For example, I asked it to create a project directory but in another subdirectory in ethr/ethr. Asking it to clear this up and move everything up one directory was fine and honestly, something I always dread doing as there are all these edge cases with hidden files and nested directories that always trip me up.

From here I started getting into the UI development and things cruised along rather nicely. I kept asking for high level changes like adding a page here and there and filling out the basic flow of the game. Theming decisions and look and feel were equally easy to implement. The power of AI was showing through as all of these things would have taken me a significant amount of time to do manually.

A pattern was already starting to emerge, the more detail I gave the AI the better the results. I even started drafting requests in a notebook so that I could easily change them without accidentally starting a request which could charge me money. This was before Cursor changed their pricing so that wasn't a huge concern, but I was trying to be mindful of token usage.

I estimate I put in about 5 hours of work to get the basic app running. There was no backend and no meaningful data or logic at this point, but flowing from screen to screen in the game was nice and gave me the opportunity to tune things without worry about big refactors.

Using Kiro

Kiro was released in private preview and thanks to the Heroes program I was able to get access to it. I was skeptical at first but found it pretty enjoyable, albeit slow, at first. I continued asking it to make changes like I had been doing with Cursor. "Vibe coding" the way through Kiro was working as well as Cursor.

It was time to start putting actual work on the backend. Something I learned a long time ago was to make authentication the first thing you implement, since it can have side effects on how your backend code is going to work. I had success with Clerk on another game, so I asked Kiro to set it up for me.

After a few hours of work I was unable to get Clerk working. Their Dart/Flutter SDK was/is in Beta and Kiro was unable to create a working solution. I stashed the work and went back to flushing out the UI, which was the more interesting part of the game and where my head kept spinning on ideas.

Skip ahead a while and I had a working authentication system with Firebase which enabled me to start building out the backend. This felt like a great opportunity to try out the Spec Driven Development that Kiro focuses on. I began giving it a prompt for the first API endpoint, providing details about authenticating calls against Firebase, using Rust for the language, and CDK for resource definitions. It went off and created the requirements, design docs, and tasks just as advertised.

I didn't read any of it. I mean, I glanced over it but nah, I wasn't going to read all that stuff. At first, I thought maybe I was just lazy, or my brain-fog was hitting hard. But, then I saw Theo's impressions of Kiro and I realized that I'm just not the audience for Spec Driven Development. I also have doubts that Spec Driven Development is going be that important for the average developerin the future (more on that later).

The other features like hooks and steering docs are interesting, but not valuable enough to keep me using Kiro.

Oh, and now Kiro has a CLI version too, just reinforcing the idea that people don't want to adopt your new IDE.

Using Claude Code

During my time with Kiro I felt hampered by its interface. It's not that VSCode and it's derivatives are bad, but an IDE is a tool and the best tool is the one you are efficient with. I've been using Jetbrains products for over 17 years and all the features of their IDEs are so ingrained in my development behavior that switching to anything else (I've tried VSCode and neovim in the past) have felt restrictive. I could spend the time to customize those tools to work the way I'm used to, but why waste that time when I've already got a tool that works well in my workflow.

This is where Claude Code stepped in. Cursor just announced they are now a CLI too, and there has been Q Developer Pro for a while now (something I've only used a few times). With Claude Code I was able to stay in Webstorm and still get the AI assistance I wanted.

As of this writing, Claude Code is my preferred tool. That will likely change over time. I've tried Q Developer and found the experience to be very similar.

Junior Developers

AI is taking entry level positions and junior developers are screwed and we're all seniors now. There has been a lot of pontificating and prognostication on what AI will do to the software development profession, so let me add my two cents:

AI is going to accelerate learning for entry-level/junior developers.

Here me out...

I don't see AI replacing developers. I had to do way too much baby-sitting and reviewing of code and correcting things to ever think that I could just throw a task at it, and it'd produce the right thing after hours of work.

It will augment developers. This isn't a radical idea, but I do want to focus on why it will help junior developers specifically.

Often with an entry level position tasks are tossed at the developer which should be pretty trivial to implement. That's the idea, after all: give the entry level people the tasks that are well-structured, uncreative, and undifferentiated. These are the tasks easiest to accomplish for someone new to programming or new to a project, just look at what others have already done and copy-pasta.

With AI that same developer can churn out more work and start practicing the skill of reading and reviewing code. Deadlines will be easier to hit. Stress will be reduced. Room to breathe and grow and learn will increase.

This doesn't remove the need for mid-level and senior-level developers to mentor the juniors, but it'll allow that mentorship to focus on the unique business problems, the integration of systems, and other things that LLMs don't really handle (and likely never will).

I suspect that this ability to focus on the less mundane aspects, as LLMs take over that work, will allow mid-level and senior-level developers thrive as well.

Mini Apps

A lot of development work isn't flashy. It isn't adding a neat button that makes cash rain down from the drop-ceiling or spray confetti from the printer everytime a sale is made. A lot of development work is utilitarian. Heck, we have an entire category of engineers, DevOps, dedicated to the software that rarely gets seen. There are also those 'one-off' type of applications that are needed to handle a single task one time. I spent about 15 months on a contract with Starz building these internal "micro" apps; just small automations to help someone's day.

For example, at my company we sometimes have to off-board AWS accounts from our organization. Part of doing this requires taking a few dozen CloudFormation StackSets and removing the accounts from them. This can be done manually but is very tedious and boring work. Thankfully asking AI to create a small bash script to handle this was a trivial task for it. We find ourselves often addressing request from clients with "I'll vibe-code a script for that".

But sometimes you need something that's more than a few basic inputs. While recently working on Ethrwars I needed an admin panel that would allow me to visualize data in the system. It was invaluable in finding and fixing a bug in the location logic of the game. I had AI write this up for me in about an hour whereas it probably would have taken me at least 4-5 hours to get it done. It required me to know a mapping library in a browser and if I had to learn that library from scratch it would have taken me much longer.

I have another task coming up for the game that requires a dialog editor. I'd struggle finding the motivation to find the many hours it would take to write this myself, to the point where I'd probably skip it and try to just brute force the data into the system. That's likely a horrible solution for the long-term despite any short-term gains I'd make. But, with AI I can get it done quickly and easily.

This might be my favorite place to see AI coding tools shine, as it makes doing the right thing the easy thing.

Observability

Over the last few years I've had the privilege to work with a number of startups and small businesses. Without any doubt, the place they all struggle is in observability. They either don't have the time, money, or expertise to build out good logging, tracing, and metrics for their applications. They often will come to us and say "It doesn't work, but we don't know why". In a lot of cases they're stuck trying to reproduce the issue locally where they can debug the problem in real-time.

Good observability is time-consuming. You have to think about what you want to monitor and what's important during debugging. You can't just dump everything - this often causes data overload and cost problems - so you'll need to be judicious. How will you trace requests through your distributed system? These questions often come after features are deployed and problems are occurring, which means solutions are rushed.

This problem gets more difficult when you've used AI to write your application. When we write code ourselves, we have a mental model of how the application works. We've built the maze of twists and turns through classes and functions and network calls in our heads. As soon as a problem is reported we start mentally tracing the pathways that data take through a system, envisioning where something could have gone astray. As the imaginary odyssey continues we start to evaluate check points in our code. "Did this function get called? Was the input X like we expect? Was the output Y?". To answer these questions we have to A) know the system and B) understand how it should function at runtime. Think about who you call when a system is failing, it's usually the person that wrote the code. They have the mental model of how the system works and have less to learn on the fly.

When AI writes the code for us, we have to build that mental model a different way. We can't turn to AI (for now) to debug a running system. This means we have to debug a system based on what we can see happening in logs, traces, and metrics and build that mental model as we go.

Tools like AWS's X-Ray, DataDog, OpenTelemetry, and others can help with this, but only if the application has been instrumented correctly. Like reading code, good instrumentation and reading logs and tracing is a skill that takes time to develop.

Practice the skill of observability now as it is only becoming more important in the AI world.

Specs from Code

One thing I love about Kiro was the hooks and the ability to have specs regenerated from code. It worked pretty well with updating design docs anytime AI or I modified the Lambda Functions code.

While Kiro has Spec Driven Development (SDD) as a core feature, I haven't seen it take the development world by storm. I'm betting you might be reading this saying "we've adopted Kiro, and we love the SDD". I'm sure some are adopting, but I don't see my LinkedIn feed filled with Spec Driven Development posts, whereas I do see it filled with posts about models, MCP, and other non-AI related things. Is this conclusive? Of course not, so I'd love to hear from you if you're using SDD.

What I've started adopting in my Claude guidance files is directives to have it update specs as it makes changes. It's not quite as flawless as Kiro's approach with hooks.

What It's Bad At

I have to admit, there is something magical about asking Claude Code to go make a change to my codebase and seeing 15 new lines of Rust code that are exactly what I wanted, even taking into some consideration things I didn't ask for.

However, there are a LOT of times it got things just plain wrong. I got in a habit of checking file changes through Git after most requests, and it gave me an easy and familiar way to see what it was doing.

Consistently, I found it struggling with anything that involved less-popular SDKs. See my earlier comment about Clerk and it's utter failure at being able to implement something. Asking vague questions wasn't usually a problem, as it could be refined in most situations.

I also learned not to make changes myself in a "vibe session" as it would go back and undo my changes. At one point it had added an environment variable to a Lambda function that I knew it didn't need, so I removed it. Moments later during another change it had added it back in.

A Bubble?

Yeah, we are, and it's going to be painful when it bursts. Ed Zitron has been covering this plenty, so I'm not going to just repeat his words. But others are saying it too, including the CEO of the only company making any money off of the stuff.

Final Thoughts

I get it. I see why there is such a push in the industry for LLMs. It's pretty magical what they can accomplish. But, they are not the silver bullet for all software issues and I do firmly believe we've got a massive bubble on our hands. They are a tool, a very very expensive tool that nobody has figured out how to be profitable, sans Nvidia.

I now turn to Google about 10% of the time now when looking for technical answers to problems. If I need a quick configuration block for CloudFormation or Terraform. Claude Desktop is my go to. AI has dramatically shifted how I get development work done. But, it has not replaced me, will not replace anyone, and cannot solve all our problems. We have complex problems that LLMs cannot solve, because it cannot learn.

I also see LLM model getting more tuned. Sure, it's great going to Claude and asking it any old question about software, and it does a pretty good job at answering it. But, I don't see the value in having a model trained on Java and Python when I'm writing Javascript and Rust code. Will models get more narrow in their training data and focus on specific development use cases? Will I someday pick a 'React 19' or a 'Node v24' model? If so, does it now behoove organizations to train their own LLM models? Would Netflix benefit from having a model trained on the code of all of their internal projects so that development of new projects can follow the same principles and patterns already established?
This past week AWS had their re:Invent conference and, like the last couple of years, there were endless announcements about new AI products. They have a way for you to build your own frontier models called Nova Forge. It'll be interesting to see how well this works and if a year or two major corporations are using it (or something similar) to create their own internal models.

But here's the thing: I live a pretty sheltered life and I really don't know how any of this will shake out. And honestly, anyone who does is probably pulling your leg. But, there is something that keeps sitting in the back of my mind for the last few months:

If OpenAI, Anthropic, Microsoft, AWS, Facebook, and the other big players, can't figure out how to make this a trillion-dollar product, then what happens to all the capital expended so far? We'll have data centers that are full of AI-specific chips that can't be used for any other purpose. The data centers will be over-built for anything but AI work. Using these chips, outside of small organizations building models and reselling inference time, will require a huge amount of AI experts, not just 'Vibe coders'. Those don't grow on trees either.