Write code like a human will maintain it

239 points179 comments4 hours ago
cadamsdotcom

Write yourself a /review command. That is an empty markdown file at `.claude/commands/review.md`. In it, put a checklist of things the agent should look for. When you’re ready to have your agent review the code, type `/review`. The checklist will be examined and it’ll plan out some findings to ask you if you want them fixed.

Mine starts with “Enter plan mode. Examine the differences on this branch vs. main. Consider: ...” and proceeds to a bullet list of things.

Any time I notice something in code review and have to get the agent to fix it.. I throw it on the list!

My list is like 200 items now. Know what? Agents don’t care that they just got a wall of generic feedback, they happily look into all the bullet points.

I added “ensure the new things aren’t duplicating code that already exists elsewhere” and it gave me such a surprise - it really truly started planning cleanups!

We are just scratching the surface. We have to give tools to our tools so they can use them to be better tools for us.

show comments
davnicwil

> The next time you ask the LLM for another endpoint with the same access rules, the model won't start from first principles. It'll start from the other four copies already sitting in your repo.

To be honest I'm not sure how true this is. I think it's more that there does seem to be quite a baked-in bias to repeat basic structures and not reuse (much less come up with) abstractions. So where that is the existing pattern it looks like it's keeping with that, when in reality it would often do that either way.

There have been many cases where I've started a piece of work by laying down very rigid abstractions and a few examples of using them, and I explicitly prompt to not only exclusively use the specific abstraction API but also copy the way I've used it. And the (frontier) LLM does neither, it just steams ahead re-implementing things from scratch from bottom up basic structures, partially and often totally ignoring the abstractions.

I don't know exactly why this should be the case but my naive suspicion is that there's just an awful lot of this type of stuff in the masses of training code and the weights just somehow 'know better' how to get results this way, rather than using your more novel abstractions/patterns.

show comments
jwpapi

Crazy how many engineers in here just say they are using another prompt on top. From my experience that makes things worse. It does abstractions, but the wrong ones. It overcomments, confusing future calls of the LLM.

To me building on multiple scalable systems this has been the most dangerous part of LLMs. On a good codebase it will work good, but it will maek it worse, so you keep using it, till it doesnt work and then you have to pay the bill and fix for what you didn’t build before.

If you put an agent on a fresh codebase 2 things are often given:

-> You have a mental model of the code -> The code is somewhet concise

After multiple iterations both is lost and LLM performance degrades. To solve this you can regular refactor, but it’s not a nice experienc. So my best solution is:

I use LLMs for exploration and for review, but I write the code myself. I find it hard to believe why so many engineers try to avoid it. It’s not consuming much of my time. And it’s actually the most enjoyable part.

Sometimes I race AI i give it a prompt /bug to fix and at the sametime im greping/symboling through the codebase and tryto fix it myself. AI isn’t always faster.

show comments
koinedad

Maybe we should start writing code like the LLM will maintain it. I’d be curious if there are weird optimizations that the LLM can drive that might not be things that help us humans like DRY etc.

Edit: this small things drive me crazy when I’m coding with LLM… which is basically all the time these days, but I also read all the code as well.

planb

I have good results with this prompt after every larger change: Now do a final code check. Is everything tidy and do the components adhere to the principle of separations-of-concerns. Is everything in an understandable and maintainable state? Do we make any assumptions that may not be true anymore? Is any code left over from previous edits or experiments that does not belong into the codebase? Is the documentation still representing the current state of code?

show comments
egonschiele

In a similar vein, here's my favorite prompt: "Please review the tests you've written. Will the tests actually test what they're meant to? If the code breaks, will the test fail?" It's amazing how often LLMs will write tests that don't test anything.

show comments
alexpotato

There is an old quote:

"Add comments to your code under the assumption that the next person to maintain it is a homicidal maniac who knows where you live"

show comments
hollowturtle

We still need to discuss this things for real? Aren't they already taken for granted after all this "experimenting" with LLMs? I'm wondering when we will discuss hand coding again without treating it like a taboo anymore. LLMs can be useful in so many ways it's tiring knowing people are delegating the entire source code typing to agents, to me it's like hearing from people that the web is good and we should be happy with it

carimura

I continually run codebases through different models to have them look for bad code smells like repeated code. That's been pretty effective. You do have to maintain over time or else you end up with a sloppy mess which I can only imagine compounds.

show comments
andai

It might just be me, but AI has made my code more human-maintainable. They've been complaining about obsolete comments, separation of concerns, testability, global mutable state...

(Also performance and security issues, addressing which doesn't make the code more readable, but does make the program itself more robust.)

That being said... I have found them weirdly unsuitable for some tasks though, e.g. asking frontier LLMs to assist me with game development, I found that they were not able to add simple features to a simple Pong clone (nor even port a working Pong implementation) without constantly breaking things. (Yes, Pong, from 1972!)

So, I want to say YMMV, but just the past 2 weeks, my own mileage has varied very much! They seem to be extremely domain specific.

"Half the time, it works every time!"

baptou12

I agree, but “write code like a human will maintain it” can also be limiting: if LLMs reduce the cost of maintaining more explicit or verbose code, we should use that to raise the standard, not preserve compromises made for human convenience.

show comments
jtr1

Most programming best practices were created to solve for the same problem LLMs face: limited context. The principles around well-crafted code strove to make it modifiable by future agents who are not the author. Maintainable code stabilizes around the invariants of the domain it address while providing a spectrum of modifiability to future users, running from UI > configs > cleanly abstracted code > core.

illuminator83

I've seen lots of code that people have maintained for 20 years and its full of these duplication and worse. In fact I'm sad to say that majority of code I've seen people write and maintain is worse than what LLMs produce today. Often it is inexperience, sometimes it is willful negligence, but most often it is just tight deadlines and pressure to do finish whatever is being done right now. People know how to do it better, but nobody got the time and budget to actually do it. LLMs also learned from that.

Snoopfrogg

Or we start writing code without LLMs.

show comments
MattyRad

This is an agreeable article, sure, but the idea that an LLM fueled group or team will collectively have this discipline is... idk... bemusing and saddening at the same time.

alexsmirnov

The problem of duplicated code described in the article, goes in a different way in reality: AI does not update 4 places in the same way, but implement them a slightly different. I found diverged business logic all the time. For example, file upload dialog for a document with the same meaning: in one place, it accepts pdf only. Another allows to upload pdf or docx. The last accepts pdf, doc, docx, and txt.

hakunin

I have been on a quest to get AI to code like me, using pi harness, and any model that it can support. I'm mostly a Ruby programmer, so here's my journey so far.

1. Created a "coding" skill with every practice I posted on my blog website, as well as a bunch I had in the queue to blog about but never got a chance, summarized into "do this" kind of language. This is more or less good for any PL, but a bit Ruby-slanted.

2. Created a "rails" skill because that's my framework, where similarly I explained my approach to architecting Rails apps.

3. Created a "writing" skill where I literally fed it my entire blog, and tried to get it to write more like me (mixed success, weaker models did better for some reason, but I haven't tried the GPT-5.6 series yet).

4. Next, I really wanted it to format code exactly like I would, even things like "let's make this `if` into a ternary, let's split these assignment groups with a line break, let's vertically align here, but not there", but with GPT-5.5 (my primary driver up until yesterday) there's almost no way to make a skill of reasonable size that will be consistently applied. So instead I instructed the agent to write me a Rubocop cop for every single situation I ever encounter where I would've formatted code slightly differently. This was quite powerful, because I usually thought of linters as enforcers of objective consistency decisions in the codebase, but this was me going full format nazi on the agent. And the nice part is that these cops can contain some non-autocorrectable feedback, which AI will follow.

5. I'm working on a review loop where the most easily missed parts above get double checked. This is the first thing I'm doing with pi subagents. (I feel like I'm getting better results if I don't use subagents for code exploration, other tool calls). The idea here is that I want reviews to be in the implementation loop. I always read/review code in the end, but so want it to have gone through the review loop before it gets to me. Since implementation is already context-heavy, I want to be able to orchestrate this loop without adding to the implementation context.

6. I'm also adjusting all of the above for GPT-5.6, because it requires less guidance, so I'm carefully trimming the verbiage to save tokens.

So far the results have been surprisingly good. I want to experiment with GLM-5.2 running under these constraints.

One invariant in all of this: I read the code. My end product is not working software, it's good code (which also incidentally produces working software).

exabrial

What I'm seeing is the organizations that had written code standards:

* define the software layers, their function, and the max depth allowed

* establish a corp code formatter for each language, along with a process to PR it

* establish a business vocabulary and what the terms mean

* establish a data dictionary, make it part of the database schema/table/col comments

Are far more successful with LLMs. You _should_ have been doing this years ago, but with LLMs its a super power.

godshatter

Could someone show me what a shared helper would look like in this case? This code looks easily readable to me and I fear abstracting it will just make it harder to reason about. Is it just variable_with_a_better_name = that conditional?

wxw

The key idea here is that your codebase is context that will be used for future changes. And context determines the model’s output, so it’s still worth having a well-designed codebase.

Easier said than done to be honest, especially if there are many people (and their agents) pushing code. It’s hard to keep up these days.

show comments
snarfy

## HARD RULE - design scope must always be maintained and no function should ever be longer than XXX lines and no class should have more than Y methods. Create new classes and subclasses and refactor until the criteria are met.

You'd be surprised how readable this makes the code when XXX is about the size of your vertical screen and Y is relatively small.

show comments
MariusGjerd

Start asking your peers to explain what their code does and alot will be surprised that they dont know

steilpass

Coding Agents are the best reason to write Clean Code (TM)

RALaBarge

I think the biggest conceit here is the expectation that humans will continue to do this task in the medium to long term. This was good advice in the past but when inference is ubiquitous and most code ends up being Claudewritten anyways, there is little point. If you are writing C for NASA/ESA then yes of course. For the 99% of the rest of us, probably not so much in the coming years.

dualvariable

I think the usable counterpoint here is that you can refrain from excessively DRY'ing code up and defer it until later.

There's a huge cost to Clean-Code-style DRY'ing of your codebase which is that you wind up creating all kinds of little functions that all add cognitive overhead to reading your codebase, and that premature DRY'ing can lead to picking the wrong abstractions.

If you can tolerate a bunch of copypasta, you can sit back after you've written 5,000 or 10,000 lines of code and can look at the actual result, instead of speculating, and make better-informed decisions about how to clean the codebase up. If you're making those decisions the first time you copy a bit of code around, you can wind up making a worse mess, since you often don't know where you're going.

show comments
luciana1u

Write code like a human will maintain it — and that human is you at 3am six months from now, fueled by regret and cold coffee.

dsagent

Very much this. LLMs are not producing code humans can maintain unless you take your time with them and still care about the quality of the output.

Maybe someone has the perfect claude.md that solves this problem but I have not seen it.

show comments
metalspot

code review is a dead end. the only way building with AI makes sense is in secure systems that can run unaudited code.

code review has always been a liability fig leaf. it is much harder to understand a system from reading the code than writing the code. if AI can write code 100X faster than humans it is simply impossible for humans to do real code review. effectively it is just pretending to do code review, and then running unaudited code without the proper systemic security guardrails in place.

praveer13

For writing for human consumption, I’ve taken to hand writing the docs and having agents review and suggest improvements.

vorticalbox

> There's a much cleaner way to do this - a shared helper

disagree, then you end up with something this this

function checkAll(target, conditions) { return Object.entries(conditions).every(([path, expected]) => { const value = path.split('.').reduce((o, k) => o?.[k], target); return typeof expected === 'function' ? expected(value, target) : value === expected; }); }

and const ok = checkAll({ user, account }, { 'user.isActive': true, 'user.isSuspended': false, 'account.status': 'open', 'user': u => u.hasPermission('read'), // predicate for the trickier bit });

how is that better?

show comments
rconti

I have very mixed results with LLMs, but I actually find they're really GOOD at, unprompted, pointing out existing code that is redundant and could be simplified and so on.

Where it really, really struggles for me is in existing complex infra codebases.

schnebbau

That sounds like a good idea, but shipping 10x as many features and bugfixes sounds better.

I started using AI with the best intentions. Checking everything before committing. Improving output by hand if it didn't quite follow the existing code style guidelines or variables were not named as well as they should be. Or if it did something sloppy or hacky.

Now, AI GOES BURRRRRRRRRRRR! If the tests pass it's good to ship. AI can deal with the problems it may create. No problems so far.

show comments
jaredcwhite

Write code like an agent will never touch it, that's my motto.

(Because it's true.)

phaser

The first line of my AGENTS.md is: You are an engineer who writes code for *human brains, not machines*.

Taken from: https://github.com/zakirullin/cognitive-load/blob/main/READM...

ramshorst

So the new prompt is "Write code like a human will maintain it" ?

trjordan

AI is so miserable for this. It's so focused on doing what you ask, it forgets that there's stuff worth doing that you didn't ask for, like defining reasonable abstractions.

Getting away from stuff like this is exactly why I want to use AI. When I say "implement this for idle but active users," I _want_it to define isUserActiveIdle() and stuff these 4 conditionals in it. Having to check the generated code for stuff like this undoes, like .... all the benefit of using AI.

AI makes all these little decisions for us. I can about some of these decisions. I just want to notice when it's doing this without having to make my eyes bleed reading 10k lines of generated code a day.

internet101010

No. I will generate code in a way that makes it easier for clankers to maintain it, because they will actually be doing the maintaining. In practice, this means that most of my time is dedicated to improving the repo harness because the state of the repo harness directly determines the quality of the codebase as a whole.

At a minimum, there should be precommit checks and CI workflows that cause PRs to fail if the documentation is not up-to-date and synced with the other docs.

Then regular codebase analysis for improvement. This is where you find the bug sources, make new modules for consolidation, and get those +5000/-4000 PRs that people stuck in the world of manual code review hate.

dofm

Do you think the steel birds with the food in will come back if we light torches in long lines on the plateau again?

acedTrex

The fact this is controversial is wild and a grim sign for an already struggling industry.

cebert

It's interesting that the author didn't mention considering updating their agentic code review prompt to keep an eye out for repetitive/duplicate code.

francisofascii

Before LLMs we didn't have time for code quality. LLMs make our jobs faster, so now we have time to dedicate to code quality, right?

show comments
uhhhd

Counterpoint: This no longer matters because we are not going back to hand-writing these functions. These patterns were designed to make code easier for humans to read and write, but that is no longer the primary way software is built.

show comments
ge96

Been getting these vibe coded PRs ugh code PR submitter can't even explain

__MatrixMan__

> Who cares about DRY? You don't have to be the one updating the same long conditional in four different files - the AI will just do it for you! Right?

One pattern I've really been enjoying lately has to do with a language called haxe. It's designed to be compiled into other languages (java, python, others). There's this extension called reflaxe which lets you make mini compilers for compiling haxe into pretty much anything.

So if I have anything with duplicate structure... like maybe I want the CLI subcommands to resemble the http API.

    $ foo bar --baz 6 # produces similar output as HTTP GET /foo/bar?baz=6
...and `docs/generated/foo.md#bar` should have documents both the CLI and the http usage. Then I have the LLM maintain a haxe source of truth and then have it compile that source of truth to the other stuff.

Previously I was using OpenAPI spec's and generators for this, but they wound up feeling like a black box that I ended up debugging all the time. The reflaxe setup is much more generic. So you end up with this mountain of generated code, but unlike LLM-generated code it's obviously generated (in .../generated/thingy.py or whatever) and a comment at the top of the file says where to look to learn how it's generated). I'm generating docs this way, accessor functions for database tables and SQL for making those tables, matching clients and servers in different languages... it replaces a lot of purpose built tools with just one, and LLMs are pretty good at it.

So even though the repo is large, the parts of it that are authoritative remain small. I find LLM's manage this boundary much better because it's so crisp an in their face. But they have to be told to do this, otherwise they'll just create context-size problems that they'll later struggle with.

Of course you could do this with yaml files or some such, but unlike yaml, haxe has a type system, you can write tests in it, so the agent can notice fundamental flaws before the generation happens... with yaml those flaws would be propagated into the generated code before they'd get noticed.

bdcravens

Humans have been writing unmaintainable code well before LLMs came along.

show comments
383toast

this article according to pangram was AI generated, ironic

k4200

I'm not sure this guy is using the same LLMs as we do. A small AGENTS.md or CLAUDE.md easily prevents issues like that.

DCKing

I run various forms of workflows to run dedicated QA, code review (of various flavors) simplification and text simplification agents. Especially the simplification goes a long way to remove dumb padding, duplication and efficiency. Dedicated docs/comment simplification is also becoming more and more necessary on recent models. For things like feature development in my workflow, the majority of time the agents run and tokens spent is critiquing the code from various perspectives and it's not close.

Of course, this doesn't solve the overall issue that agents don't write code like you and still requires a lot of human attention in planning and code review out to clean up leftover issues, and e.g. challenge bad assumptions about architecture and real-world context. A human is still very much needed to cull the slop (or, more gratuitously: align the agent). But IME it does help avoid a lot of pitfalls and makes the code high quality a lot more quickly.

imilev

What happens when shit hits the fan in my exp is that I have to crack open the codebase and debug some portion of it, so I can explain it to myself in order to be able to explain what is wrong to the LLM.

Otherwise what I have found is that the LLM will add a new if statement which will handle the newly discovered issue and you start stacking them ifs. As the article mentions LLM's unlike humans aren't lazy, they will copy, paste add patches for every issue, why bother think and understand root cause :d.

So as part of our review we have a rule against that as well.

show comments
willtemperley

Yawn. So people are discovering SWE hasn’t actually changed in its basic principles. Is this going to be the new “how I use LLMs” article? Good night

lowbloodsugar

SOLID is a good idea that most coders I know don’t follow because they can’t be arsed. Turns out AI is really good at writing SOLID code (if you tell it to) and SOLID code is much easier for AI to reason about.

andrewjneumann

Have a bit of a contrarian view on this tl;dr don’t write code for human consumption if you use AI; BUT you have to accept AI coding lock in and change how you work.

Funny enough, discussed this yesterday

Stop Optimizing Code for Humans https://youtube.com/live/eLn4-XA-KdQ?feature=share

esafak

Just run weekly cron job to assess code quality and highlight candidates for refactoring. In addition to doing the same in each PR, of course, but things can get through.

deadbabe

I absolutely will not write corporate code like humans are maintaining it anymore, because I don’t have any confidence actual humans will be maintaining it.

For personal projects, I can trust that I myself will be maintaining things so I still write things like it matters, but I do not extend the trust to others.

dionian

my LLM does this pretty well with my coaching. i use a good model and i encourage it to make such improvements. and since the llm is trained on human maintainers it works fine.

jasonlotito

linting tools, static analysis, CPD, etc. These are all old things you can continue to use and are much more robust than anything you can prompt. These should be standard when using LLMs. In fact, you can tighten the rules even more enforcing more restrictions so you ONLY get the output you want. put this behind a pre-commit hook and a CI job that runs on a PR, and it will work wonders.

You can have all the prompts you want on top of this, but if you don't have this automated stuff running behind the scenes, you aren't serious about these issues.

Looking through some of these comments here, I see lots of people rewriting concrete rules in markdown willing to spend tokens on the hope AI won't miss it where an actual program won't.

jdw64

Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. Code for readability.

— John F. Woods (1991)

cyanydeez

AI isnt taking my job. my company is supporting local AI for development. who ever comes after me will have the same hardware and models or better. unless a MBA is put in charge, my boss and predecessors can maintain and build out as needed.

bottom up AI use seems a godsend compared to the corporate AI rat race.

i setup some slop reporting systems and ensured my boss knows theyre great starting points but serious use requires real time investment.

ing33k

And hope it works?

I’m pretty sure many people who use AI to write emails or blog posts add "make it sound like a human wrote it" to their prompts. We all know what the result usually looks like.

If AI is writing my code, I'd rather have it focus purely on correctness and efficiency than on making the code easy to read.

heck! I might even ask it to imitate Arthur Whitney’s style.

/s

tristan666

u right