
This was my first experience doing something major with Claude Code that wasn't generating small algorithms or writing docstrings or simple tests.
My API for Indieweb endpoints, is in a project I called Divebar a few years ago and was written in Pyramid. Many years later, I felt urge to upgrade this to FastAPI, not only because it's a more modern framework, but because I also need the practice to be familiar with it.
I had a couple of false starts before. I just requested Claude Code, "Hey, let's migrate this to FastAPI" and sure it went ahead and changed a LOT of stuff so it just worked.
That amount of PR to review was scary and I did not trust, or most likely, I could not retain the mental model of everything that changed to achieve a big change.
So this time I went with a much much slower approach. I first had to determine things I wanted to do before the migration, I didn't want my terrible old patterns to be contorted just to fit in FastAPI way.
I first asked for a migration path in a file MIGRATION.md and from there I was able to get a much better grasp of what could be attempted. I tinkered with it adding a few steps or asking to simplify some of the proposals into more granular changes. Later, I needed to identify deployable spots to make each change incremental and reduce the disruptive changes to a minimum.
Forcing myself to find this was paramount to the whole process, I realized that it was in my benefit to make some architectural changes before Claude hacked its way through. This conversation back and forth was critical to make sure we were both in the same page (yeah right, because it understands ).
I requested a quick summary of all the endpoints exposed, like minimal docs. Then proceeded to ensure that it was all test covered.
After doing that, and a couple minimal bugs found in the process, I had a promise to maintain before refucktoring. With this, I then told Claude to reorganize my code into an api and services modules, so just the HTTP bits are in api, that would reduce the scope of my migration changes very visibly if I saw any file out of there being changed. I did the same with the tests so I can be alert of what's being changed.
All changes were within scope, so I was good to deploy and had the code in a good state. Other changes that helped to do this in parts was to upgrade from python 3.5 to 3.8 and finally to 3.11. Along the way, start using uv. All changes I could make without putting in risk the API contract and controllable changes.
At this point, I was ready review my code and found it in a much more confortable spot to read the mess I had written in the past, make small changes but thankful of the improvements.
Now it was time for the FastAPI upgrade, there was no more chunking that I wanted to do here, and it was a bit of radical PR but very scoped because thankfully this API exposes very few endpoints, so it was reasonable to look at them one by one to make sure it all kept in check. There were some inevitable changes on how FastAPI handles errors, but for my Grumble Micropub client, this is irrelevant, so I proceeded. Then, migrated out of unittest into pytest, which was trivial and now I am where I wanted.
Took me one evening instead of a week, but I can see the major risks of doing this. Claude is too happy to refucktor when asked unshepperded. It will maintain and exaggerate your bad code if the task is too ample. In huge PRs is easy to be lazy and just trust that it's all OK. Had I not asked for the migration paths, deployable checkpoints, test coverage, gradual upgrades. This could have gone riskfully correct leaving me in the dark or with a lot of cognitive debt to try and maintain this.
I feel that now the code is in a spot where I can go and do more manual changes like I enjoy, but Claude was a good assistant to do the gruntwork of non business that I kept a voiding.
For my next trick, migrate a Django2 and Python 3.5 app to modern versions. And then my most embarrassing of all, a huge Python 2.7 and Django 1.11 codebase with thousands of users to modernity so I can resume coding on it again. Today was just an entree.