Bram Cohen
A Guide to the Basics of Programming (Including Using AI)

This is a guide programming for people who know already how to code. It explains the craft, including new parts related to AI. It is not a guide to ‘vibe’ coding, which is when someone who doesn’t know how to code at all uses an AI coder, or ‘agentic’ coding, which is when the machine does much longer self-directed runs. This only explains the basics of using AI as a coding assistant, so you’ll be limited to a mere 10x improvement in your productivity. Agentic coding can, under some circumstances, produce much greater gains, but it more often results in people having reams of worthless code and a mindset somewhere between delusion and psychosis.

Practices from before AI: Test Driven Development

Code must first and foremost be high quality. In some ways this is more art than science, but many specific things can be done, including:

  • Code should be well organized.

  • It should not have repetitive sections which can be consolidated into a single thing.

  • It should be organized into coherent modules. Maintenance should usually only require changes within one module. Making this happen is again more art than science, but generally related functionality should all be within a single module.

The number one rule for high-quality code is no broken windows. If you have any known bugs, you should drop everything and fix them. Do not debate whether it should be done now or later. Simply fix it. Only very hard to reproduce bugs should ever be allowed to persist in the codebase for more than a fleeting moment. If you let a bug fester in the codebase when you get around to fixing it you will find out you don’t have one bug; you have ten bugs, all with the same symptom.

Write extensive tests. Make the tests run fast enough that you run all of them constantly. Ideally, all tests run in less than a minute, and you run them before every single commit. Have a policy that you don’t move forward until every single test passes. Tests should achieve good code coverage. How much is good is not clear, but 100% by lines is often achievable. You want tests to continue to work unchanged across code changes as much as possible, and you also want them to run through reasonable scenarios rather than simply asserting that the code is exactly what it is. This is generally done by using the APIs as designed,, both at the module level and application level, running them through a variety of different scenarios. Don’t make your tests simply assert that the code is exactly what it happens to be right now.

The cycle of programming is that you decide what you’re going to do. You design your APIs and algorithms and what your test scenarios are going to be. Then you turn off your brain and you implement the code and you implement the tests and you run the tests repeatedly until they all pass. What order you do those things in and how large of a unit that you do at once is the subject of many religious wars, but the general framework of test-driven development is universally viewed as a good thing. The details often come down to personal preferences and the needs of the project.

Using AI

All of the above still applies when using AI coding assistance, but now there are new parts of the process. First and foremost, for AI to be able to work effectively on a project, there must be extensive up-to-date documentation. The AI is coming on as a new employee at the beginning of every single conversation, figuring out what’s going on by reading the code. Historically, code was mostly written by human beings who had extensive knowledge of the code they were working on, so documentation wasn’t particularly necessary, or helpful. But AI can read documentation a lot faster than humans can and critically needs it.

Thankfully, in addition to needing documentation, AI is very good at writing documentation. If you have a project which doesn’t currently have any documentation, you can ask AI to get it started for you. You shouldn’t take what it builds without review, but what it comes up with is a good start. You can then read through the documentation yourself and note any things which seem off. When something does seem off, this means one of three things:

  • The documentation is wrong

  • The code is bad

  • Your understanding of it is wrong

It’s important to figure out which one of those three applies and fix it. The AI, of course, is very good at helping you figure this out. You should also mention higher level things which you think aren’t already in the docs to the AI and explain them to it. The AI is very good at figuring out whether they’re already in the docs and incorporating. It’s also good at getting clarification, mostly by echoing what you said back to you badly and getting corrected.

Once there are project docs, the AI should be given instructions to read them at the beginning of every session and to update them as necessary after every change. Docs can quickly get to the point where AI will refuse to read the whole thing because doing that will blow their whole window, but they can be organized. Make an overview doc which links to other docs which the AI can individually read when the task at hand requires it. AI is also very good at auditing docs to see if they have become stale by comparing them and the code.

The code/test cycle includes some new steps when using AI. Most of the typing is now the machine’s responsibility. At the start of every task, you should put the AI in ask mode. Otherwise it will run ahead and start coding before it understands what’s going on. You then get into a conversation with the AI about something that needs to be done or something that’s problematic in the code, or how you’re having a bad day or how someone was mean to you once in high school. The AI is in ask mode. It’s okay to vent. It can’t do anything crazy. Once the conversation has coalesced into a general idea of what you want to do, you then tell the AI all relevant context and details of implementation that come to mind. It will respond by trying to repeat back what you said to it, but badly, and you have to correct it a lot. Once you’ve run out of details to give it about context and what to do, and it’s gone a few rounds of conversation without saying anything which needs to be corrected, you should tell it to make a plan, which is a fancy term for a to-do list. It’s a good idea to skim/read the plan, but it usually gets it right on the first pass if you’ve already had an extensive conversation. Plans should always include:

  • running all extant tests until everything passes

  • updating the architecture docs

Once that’s done, you tell it to build the plan, and it will usually ‘one-shot’ it, although calling it one-shotting after you’ve spent two hours explaining in an interactive conversation is very misleading. If it starts flailing you usually have to stop it and help it get back on track because it tends to get increasingly worse once it goes off the rails.

Subscribe now

Posted
jwz (Jamie Zawinski)
"Blink twice if Zuckerberg is an asshole"
Facebook whistleblower Sarah Wynn-Williams was forced to sit in silence on stage at an event at Hay festival, after lawyers advised her not to speak because of ongoing legal action brought by Meta.

Wynn-Williams, whose bestselling memoir, Careless People, details her years working at Facebook, was due to appear in conversation with the investigative journalist Carole Cadwalladr and academic Tim Wu.

Instead, Wynn-Williams sat on stage for the duration of the hour-long discussion between Cadwalladr and Wu, without speaking or responding. She was unable even to nod or shake her head.

Introducing the panel, Cadwalladr said: "I think this might be a Hay first, in which we have an author in a hostage situation. Blink once if you can hear us, Sarah, twice if Zuckerberg is an asshole." [...]

During the event, Cadwalladr read a letter from Wynn-Williams' lawyers outlining the company's latest legal claims. The letter stated that, in March 2026, Meta filed a sanctions motion alleging that Wynn-Williams violates the emergency arbitration order "any time she appears in public in a place where she should know that her book is available for sale and her presence might draw attention to it".

Previously, previously, previously, previously, previously, previously, previously, previously, previously, previously.

Avery Pennarun
The software industry: annealing, but wrong

In recent months I've heard of several teams with an interesting policy: each pull request should be no more than a few files, and no more than a certain number of lines (say 500). And do just one thing and do it well. And be easy for a human to review. And be fully tested by the test suite.

All those are good requirements, right? Surely this is quality software engineering.

And often, the results are good. Sure, splitting a single 6000-line feature or fix into twelve 500-line PRs is more work, but each of those PRs is surely easier to review. And you can git bisect them when there's a bug! And maybe revert the individual change that broke something.

...and also cause 12x as many context switches for your reviewers as they review each one sequentially.1 But that's just the cost of software quality! Right?

Mostly, yes. My analogy here is simulated annealing. In that process, you start your problem solving with a high energy -- making big changes to move quickly through the problem space -- and then slowly reduce the energy level so that your "hops" get smaller and smaller. In real physical annealing (used eg. for metallurgy), the result is stronger, more stable, more crystalline structures. In simulated annealing, you use it to find solutions that aren't obvious, by rapidly exploring the solution space and then zooming into the areas that look most promising.

In software the analogy is clear: sure, you might start with big jumps, but once your system is more mature, you should make smaller jumps. Big jumps break the crystalline structure. They cause bugs.

Fear of breaking the crystalline structure sounds cooler than fear of change

The main problem with annealing-driven intuition happens when things do need to change quickly. It's not made for that. You usually don't build a hammer and then decide one day you want it to be a different shape. But every day, there are compelling-sounding reasons to make your software a different shape. Annealing is the enemy of change.

Modern AI-driven coding (ironically, with LLMs trained using a process quite similar to annealing) does not care about your annealing and your risk management and your fear of change. It produces changes as big and interconnected as you want, jumping all over the solution space as quickly as you can prompt. And it has all the outcomes the math would predict: the output is less strong, less coherent, more likely to fail. LLMs have no fear of change because the LLM instance will be long gone before the consequences materialize.

But, it's a new and special feeling to suddenly be able to take a large, mature code base and suddenly explore any kind of large change you want. Most of those changes turn out to be bad ideas... and it's nice to be able to discard bad ideas quickly. But some turn out to be good ideas. Then what?

Well, follow your development processes. Break the big changes into 500-line patches. Review them one by one. You already did the research! You know it's worth it.

Not every big step is made of small steps

But it's not about being worth it -- some changes simply don't lend themselves to small steps.

In the early development of Aperture, I wanted to implement dollar-based spend quotas: across all your LLM backends, let a given team or person or node spend up to $x per unit time. But to do that, we first had to add pricing information (it's mysterious how LLM vendors don't to tell you how much your queries cost), which meant assigning prices to provider definitions, and then we had to assign quotas to particular identity+model+session combinations. And quotas are one of the first key value propositions of Aperture. We had to have them, but we had to have all that stuff.

So, I made a giant change that included three major areas: first, the Grant syntax for applying attributes to sessions; second, a query cost approximator that combined multiple sources and a messy heuristic; third, the actual quota enforcement system. Each of these parts was imperfect, but we needed all three parts in order to make anything work at all, before we could refine them. That's the high-energy big-jump part. It came out to something like 12000 lines of code.

Now, I'm not a monster. After I made it all work, I split it into three parts: the grants, the pricing, the quotas.2 Otherwise it really would have been an unreviewable mess. But also, I could not have developed the quotas feature in real life in that artificial order. The grants structure evolved as my understanding of pricing and quota enforcement evolved. The original quota semantics sucked, so I rewound back to the data structures, which affected how the pricing got imported, which changed how the quotas were stored. The code reviewers didn't have to worry about that but I did.

Mercifully, because Aperture was new, everyone on the team understood that three 4000-line patches were better than twenty-four 500-line patches when implementing this series of feature. There was even some forgiveness when it came out later -- inevitably -- that each of those parts was not quite right and needed more bugfixing. That's how new software gets made. That's the annealing stage.

But the hard part was the philosophical difference between that and, say, core Tailscale. Tailscale has 7+ years of maturity behind it. It's been annealing for a long time and it has a reputation for extreme quality, hardening, durability, whatever you want to call it. If you start pulling stunts like that in core Tailscale, stuff absolutely will break and its millions of users will absolutely not be impressed. Which is why, for the most part, we don't.

But the feeling of moving fast again is such a wonderful feeling. Some people devolve the analysis to "founder mode" and call it a personality thing, but it's not. It's using the right tool for the right job at the right time. Sometimes you need to go fast, sometimes you need to go slow.

Pain does not cause gain, it's just frequently correlated

That feeling of moving fast again reset my brain a little. It reminded me that some changes to mature products can become impossible because we commit so hard to the math of annealing that we fall forever into a local optimum. Sometimes, when the well is too deep, you can't escape from it without a bigger jump.

We're entering a world where it's cheap to produce bigger changes, but that doesn't make it any safer. Or, it's cheap to ask an LLM to artificially break your change into a dozen rule-compliant PRs but then you just stuck on tedious neverending code reviews instead.

On the other hand, it's also possible to fork your own project a dozen different ways, add huge compliance test suites you never could have afforded to invest in before, rewrite your project in Rust in a week just to see what happens.

Sturgeon's Law says 90% of your big changes will be crap because 90% of everything is crap. When your changes were 500 lines long and you had to reject them, that didn't feel like a huge sunk cost. But now, it's okay if your 12000 line changes are crap and you have to reject them; it's the same cost to write3 as the old 500-line change.

You still have to figure out how to efficiently review, reject, and refine these big jumps. You definitely need a much heavier investment into CI/CD automation, specifications, UX testing, all of it. But also, all those things just got cheaper.

I wouldn't recommend overdoing it. The other thing is, customers don't like it if you change your product out from underneath them too often. But sometimes, you're just stuck in a rut. Sometimes you have to use a higher-energy jump to get unstuck. That doesn't mean you abandon smaller steps. Use the right tool for the job.

Footnotes

1 The reviews only need to be sequential because Github's code review system doesn't support stacked diffs, 18+ years later, leading us into this false dichotomy in the first place.

2 That's a slight oversimplification since there were a couple of other parts first. I had to define the data structures for the quotas before I actually added the quota system, so that I could use the data structures in the grant syntax, and so on in a big circle.

3 A 12000-line AI-driven patch might take as much time to write as a 500-line human-written patch, but by default it's much more work to review. In fact, so much work that people give up trying, and rightly so. Rather than abandon hope, I continue to think we need to invest more into (and will gain more from) non-annoying AI-assisted review workflows than AI-assisted development workflows. Imagine for example an automated pre-human-review step that says "no, this sucks, fix these 25 things first" and closes the pull request. Is it rude? Not really, if it's good quality advice that comes back fast. In a world where reviewing code is hard and writing it is easy, put more demands on the writers.

jwz (Jamie Zawinski)
Chad Valley Wooden Influencer Roleplay Set
This wooden influencer set brings roleplay fun to children who love creating content.

It includes 6 pieces a tripod stand, adjustable aperture lens, camera, smartphone model, tablet and microphone. The set encourages storytelling and imaginative play as children act out being content creators. The tripod adjusts to different heights and the ring light adds realistic detail. The smartphone and tablet models look like the real thing. The microphone completes the streaming setup.

Previously, previously, previously, previously, previously, previously, previously, previously, previously, previously.

Posted
jwz (Jamie Zawinski)
Fluck Flock
Flock is quietly training police to sway city leaders to buy surveillance tech:

As East Bay communities raise concerns about civil liberties and immigration enforcement, the license plate camera company is seeking support from its customers -- law enforcement officers. [...]

Brian Hofer, executive director of Secure Justice, a privacy and civil liberties group, said Flock's training reminds him of public relations strategies used by other surveillance technology vendors. [...]

"You wine and dine them, take them on golf trips, teach them how to write grants, and then you give them a job after they retire," he said. "Then, they go and sell contracts to other police departments, and who are they going to listen to? Other police who have used this technology." [...]

Hofer said he thinks Flock, like ShotSpotter, is seeking support from law enforcement officers in reaction to the dozens of jurisdictions that have canceled their contracts with the company. Since August 2021, 88 of Flock's contracts have been terminated, according to Secure Justice's most recent tally. As of publication time, that includes 45 since the beginning of the year. (Terminations also include non-renewals and non-awards, if there was a competitive bidding process.)

"At the rate that they're losing contracts, this is a big piece of evidence that they're panicking," Hofer said.

To date, Flock has contracts with more than 5,000 law enforcement agencies nationwide.

Previously, previously, previously, previously, previously, previously.

Posted
Richard Stallman
Urgent: Refuse plan to label Americans as "domestic terrorists"

US citizens: call on Congress to refuse to fund implementation of the bully's plan that could label millions of Americans as "domestic terrorists".

See the instructions for how to sign this letter campaign without running any nonfree JavaScript code--not trivial, but not hard.

US citizens: Join with this campaign to address this issue.

To phone your congresscritter about this, the main switchboard is +1-202-224-3121.

Please spread the word.

Posted
Richard Stallman
Urgent: Reject attacks on housing assistance programs

US citizens: call on Congress to reject the wrecker's attacks on housing and homeless assistance programs.

See the instructions for how to sign this letter campaign without running any nonfree JavaScript code--not trivial, but not hard.

US citizens: Join with this campaign to address this issue.

To phone your congresscritter about this, the main switchboard is +1-202-224-3121.

Please spread the word.

Posted
Richard Stallman
Urgent: Support cops who fought coup-leader's Jan 6 riot

US citizens: support the cops who fought the coup-leader's Jan 6 riot at the Capitol, as they sue him to block his self-settlement meant to give him lots of money to give the rioters as "compensation" for the punishment of their crimes.

Posted
Richard Stallman
Urgent: block Paramount - Warner Bros merger

US citizens: call on Congress to block the Paramount - Warner Bros merger.

US citizens: Join with this campaign to address this issue.

To phone your congresscritter about this, the main switchboard is +1-202-224-3121.

Please spread the word.

Posted
jwz (Jamie Zawinski)
Help me keep home.mcom.com online
I am once again seeking a contact inside the Yahoo DNS team.

Early this morning the "home" record vanished from the "mcom.com" domain. I need it put back. Oddly, the "mosaic" record is still there.

My last contact there was Paul Frieden, in 2023, but the only email address I have bounces. Ideally I would ask Paul, "Hey, can you introduce me to your replacement?" Failing that, I'd like to find anyone currently on the team responsible for Yahoo's DNS records.

Previously, previously, previously, previously.

Posted
jwz (Jamie Zawinski)
There are good heists, and then there's this one
David Rush is accused of:
  • Lying on his background check forms;
  • Time-card fraud;
  • Oh yeah, and also stealing $40M worth of gold bars.

Rush, a former senior executive service-level CIA employee in Virginia, was arrested on May 19:

FBI agents searching his home seized more than 300 1-kilogram gold bars valued at more than $40 million. [...]

The CIA says it informed the FBI of its suspicions about Rush, who apparently fell under scrutiny after he began asking for gold bars last November. That's when he began making "several requests ... to obtain a significant quantity of foreign currency and tens of millions of dollars in gold bars for work-related expenses," according to the affidavit. [...]

A review of a storage space Rush used at the CIA found that only part of the cash was there. The agency's inquiry into the matter is ongoing, but it has not yet found any record of why Rush said he needed the massive amount of money.

The FBI affidavit accuses Rush of taking gold bars and currency, making false statements to the agency and on national security background forms, and filing fraudulent timecards.

It is journalistic malpractice that there are no photos of the gold bars in question. Stock photos are insufficient here.

Previously, previously, previously, previously, previously, previously, previously.

Posted
jwz (Jamie Zawinski)
Today in Hot Superyacht Probs
Exhibit A:

Mark Zuckerberg's mega yacht docks in Seattle in the wake of Meta layoffs:

As of Wednesday afternoon, the $300 million, 387-foot Launchpad was stationed on Westlake, just a few blocks up Lake Union from Meta's offices. The yacht arrived as news broke that Meta's mass layoffs hit about 1,400 employees across the Seattle region.

Posted
jwz (Jamie Zawinski)
Rockbox
In this, the Year of Our Apocalypse 2026, Rockbox still cannot display EXIF album art if it is a progressive JPEG of any minuscule size or resolution.

I can't even.

Rockbox does not support RLE-compressed BMP files, nor does it support progressive and multi-scan JPEG files. JPEG files must consist of a single scan with interleaved components, as progressive and multi-scan images require much more memory to decode.

And yes, this is still true in the nightly build.

Also, while you can finally have a playlist with up to 32,000 songs, "shuffle all tracks" is still hardcoded to 2,000.

I'm starting to think that their heart just isn't in this any more.

Previously, previously, previously, previously, previously.

Posted
Richard Stallman
Urgent: Stop warfare-powering supposed-intelligence data centers

US citizens: call on your congresscritter and senators to stop the Pentagon's warfare-powering supposed-intelligence data centers.

See the instructions for how to sign this letter campaign without running any nonfree JavaScript code--not trivial, but not hard.

US citizens: Join with this campaign to address this issue.

To phone your congresscritter about this, the main switchboard is +1-202-224-3121.

Please spread the word.

Posted

Planet Debian upstream is hosted by Branchable.