I'm going back to coding by hand
In work we use LLMs exclusively. Nobody writes code anymore. It's all hands off and we have a high level understanding of how things work but no more than that.
When it comes to my side project, I was adding features at breakneck speed with Claude but I realized I have no clue how the new code works or what it changes or breaks. I spent many years of my life working on this project and I don't want to turn it into another vibe coded black box, especially without an org of other engineers to help.
So last night, I abandoned my Claude branch with all the fancy new things and started hand coding again.
It was very very satisfying. Sure, there was monotony. I changed some variable names and I had to chase down all the places they were referenced, comment out tons of stuff to get things working and then slowly bring it back in, but it felt like coming home to an untidy house after living in hotels for half a year, and starting to clean up. Yeah there's work to do, but this place is mine. My own. I know where things live.
It's given me love and energy for the project again (at least for now, I hope it continues!) and I'm delighted to say I took a good look at code I myself had written pre Claude and I still found many ways to write it better, refactor, make it more readable and efficient. I haven't forgotten.
If anyone is feeling the despair of not coding anymore, stairs you're losing your edge, I would suggest you ditch Claude for a few days at least and see how you feel. Your mileage may vary, but it's given me back something I thought was gone forever
54 comments
[ 0.20 ms ] story [ 4.1 ms ] thread"I can quit any time I want to."
You can still very much get ahead by working smarter not harder, even when working with your hands
I started building a Claude which retains some brain power. After each pass it ablates a function or a portion of code and forces you to write it out by hand. My hope is that I can get something that deals with boilerplate and makes me focus on the interesting stuff. We'll see.
It’s like using a linter: you do it because it’s the right thing to do and doing it without the tool confers no benefit and is prone to error.
That _is_ the refactoring tool in my IDE (emacs). i demonstrated replacing _all_of them at once, not replacing them each by hand.
> ... because it’s the right thing to do and doing it without the tool confers no benefit and is prone to error.
There was nothing in my post done "without the tool." Shell/find/perl _is_ the tool for C refactoring, and has been for decades.
It's long been my experience that that only works with high-level languages (specifically, those with bytecode), not C (especially once symbols are generated from macros). (OTOH, i've not touched an IDE in well more than 10 years.)
It's long been that your experience is outdated. A modern IDE will refactor C code just fine, and emacs is a pale shadow of a proper IDE. I understand you are proud to be using an old tool and doing things "the old fashioned way" but you are just using an objectively worse tool for this thing you're talking about throughout the thread. Find and replace is not the correct way to rename a method or variable for obvious reasons.
Emacs.
You don't have to just give it a task, let it do whatever it wants, then accept the result. You can tell it how to do things. You can read the changes. You can ask it to do things differently.
You choose to relinquish all control and then complain that you don't like not being in control. It's all about the level of involvement you choose for yourself. It's not all or nothing, you don't have to go full vibe coder it's a spectrum and you choose where you want to be on that spectrum.
For me it works great. My judgement is that I get things done significantly faster, and generally with comparable or better quality than I would doing it manually. It's important to lay a good foundation, if you are careful with the broad strokes it helps the LLM lay the rest down more consistently. It's also a lot easier to refactor things when the need becomes apparent.
I wouldn't say I make the LLM restrict it's output, rather I'd say I just don't ask for a lot at once. If I want to create a new page in our web app I'll split it up into multiple tasks - create the new page with the required layout and add it to the navigation. Create a new component we need for this page, put it on the page so it can be tested. Create another component. Add an endpoint to the API for getting the necessary data. Use these existing components and the new ones to build the final page. At each step I test and verify that it works properly, and review the code to make sure it's reasonable. I might make several pull requests or just one depending on the size of the task and what makes sense to me. In general I want a PR to be testable, just a component isn't testable if it isn't used so it has to be used. I also don't do a PR that isn't production ready, so I won't submit a PR with just a test page.
If it's a very simple page where we have most or all necessary components I might just send a screenshot from Figma along with instructions to use existing components and what data to use, CSS variables and whatever else and have it try to one-shot it. I generally don't want a PR to have more than a few hundred lines total. I review and test the code at each step and finally I review the whole PR myself before submitting it to colleagues.
And then you look up one day and you don't recognise the codebase
One thing I do is try to keep prompting. I do take time to look at the code and think if I need it, but when I'm unsure of what to do I use the LLM to help me work through it. Here is a problem, I'm not sure whether to do x or y or something else, what do you think?
It will reason around the issue and generally come up with some good suggestions. If I'm not happy I'll just talk to it further, explain what I don't like etc until we get to something I'm happy with.
I try to avoid being super specific and spending tons of time on prompts, rather I give it a vague description of what I want and ask it to plan the change, then I review the plan which will usually be pretty close, explain what I want different and when I'm happy I tell it to do it.
I do think it helps a lot that I've already put in a lot of work to build a clean and consistent application, for many problems there is already a ready-made solution. The core architecture is already there so mostly it just expands on it.
That is how I think it should be done.
I've had tremendous success with this approach as well.
It sounds like having another AI telling the first AI not to “drift” away from the fundamentals would do the trick? Does this activity require some kind of super human abilities that can’t be done by an AI?
What exactly is it that gives satisfaction? Bossing around a junior developer or reviewing code generated by said junior. What's the point of being a “programmer” when one is really just some middle manager defining issues and pushing them out to a factory floor of digital monkeys.
If the satisfaction lies in role playing middle management then I can understand all the hype. Certainly it has nothing to do with programming any longer.
Just as I speak, it is reworking a UI compositor design, after I told it to use the reactive framework I have built for damage restoration, because in the end, this is a reactive problem. The implications, it drew on its own. But I had to nudge it.
Also reverse engineering an existing product and using the information to map out behavior and structure is incredibly valuable
But the right move is to find a way to increase the rate at which you generate ideas and offload the coding almost entirely to AI. Because if you’re not doing that, someone else is. They’ll eventually build something better than your app.
And when people stop choosing your product, if you can’t come up with the next idea and this is your only source of income... well, good luck.
For me, it definitely is. Hell, my idea generation outpaces my ability to delegate it to agents. I can't do all the things I want to do because I don't have enough time in the day to vocalise them all, let alone hand code.
But in my case, I choose to handcode sometimes because I value the certainty of the results more than the speed of development.
It's the choice between a well-engineered application that does a handful of things reliably through a well-tested UI, or a rough-around-the-edges app that does 50 different things passably well, most of the time, with an inconsistent UI and lots of small bugs
People here might question the "lots of small bugs" but I have developed some apps solely with LLMs and despite using test-suites and spec-driven development I still face constant regression and UI bugs creeping in with every revision.
A good example - in React Native, in Android, Claude cannot keep the controls above where the onscreen nav appears, no matter how many times I ask it to. It'll solve it until three iterations later when the issue will return on another screen.
Forget all the technology involved. One of them is yours, you made it and know it. The other one is something you bought.
Quite literally, something phoned in.
But I think it's really about finding the right abstraction. As a staff or principle engineer in the beforetimes, I also didn't understand most of the code being written by the org. I dove in where needed, but more importantly I found the right layer to understand what was going on - dependencies between teams and services, data flows and data models, etc. And where I found myself most effective was when I was shaping and understanding those effectively.