What I learned from AI Coding for Real Engineers

#ai#claude-code#ai-coding#workflow#software-engineering
Terminal window showing the grill-me command above a circular loop icon

I have used AI coding tools for a while, but the way I worked with them had no structure. I would type a prompt and skim the code that came back. Then I would fix whatever the tool got wrong. I was about to start a greenfield personal project, and I wanted to see if there was a better way to work with these tools than what I already do. To find out, I took Matt Pocock’s cohort AI Coding for Real Engineers, and the rest of this post summarizes what the course teaches and what I plan to apply.

The main idea of the course is that an AI coding agent has no memory between sessions and no knowledge of your codebase. Pocock describes the agent as “a new developer joining your team every 20 minutes”. The agent also behaves differently each time you give it the same prompt, because it samples from a range of possible answers instead of giving one fixed answer. The practical consequence is that you cannot hand the agent a task and trust the output. You have to supply the context, the constraints, and the checks, and most of the course is about how to supply those three things well.

The course is organized into six days of lessons. It teaches everything with Claude Code, but the ideas apply to any similar tool, because they are about how you work rather than about the tool.

Grill first, then execute, then clear

The default way to work with an agent is to describe a task, let it explore, and approve the plan it prints out. The course argues that this fails, because the conversation before the plan is short, and you end up reviewing a long document instead of building what Frederick Brooks calls a shared design concept. A plan document is easy to skim and easy to approve without reading closely, so misunderstandings survive all the way into the code.

The replacement the course teaches is an interview that the agent runs on you, which the course calls grilling. You give the agent a rough idea along with a skill named grill-me, and the skill instructs the agent to ask you questions one at a time until every branch of the design is settled. Each question comes with the agent’s own recommended answer, so you can accept the recommendation or push back on it. You can also ask what it would cost to change your mind later, which is a useful way to find out which decisions are hard to reverse. The format of one question at a time is what makes the interview work, because a single big list of questions invites a single big shallow answer.

After the interview, you tell the agent to implement, and you clear the conversation when the task is done. The course names the full loop grill, execute, clear, and uses the loop as the basic unit of work for everything that follows.

Write the destination down as a PRD

For work that is too big for one conversation, the course uses documents to carry state between sessions. A PRD, short for product requirements document, describes where you are heading, and it is written from the user’s perspective rather than the implementer’s. The course’s write-a-prd skill produces one, and the interview from the previous section is built into the skill as a step.

One step of the skill asks the agent to sketch the major modules and to look for opportunities to build deep modules. A deep module is a piece of code with a small, stable interface that hides a large amount of implementation, an idea from John Ousterhout’s book A Philosophy of Software Design. The agent benefits from deep modules, because the agent can read the interface and know where a change belongs. You benefit as well, because a test written against a stable interface keeps passing when the implementation underneath it changes.

A related skill, improve-codebase-architecture, applies the same thinking to code that already exists. The skill has the agent explore the codebase and note where it struggles, e.g., where understanding one concept requires reading many small files. The skill then has the agent design several different interfaces for the tangled area, and you pick one. The part I find most useful is that you compare the candidate designs in prose, and the agent gives an opinionated recommendation rather than a neutral menu of options.

Break the work into thin vertical slices

The course borrows the term tracer bullet from The Pragmatic Programmer. A tracer bullet is a small slice of a feature that works end to end through every layer of the system, built before anything else. The failure it prevents is the one where you build one layer at a time and discover at the end that the layers do not fit together.

The prd-to-issues skill breaks the PRD into these slices. Each slice cuts through all the layers, each one can be demoed on its own, and each one lists which other slices have to finish first. The skill also asks you to mark each slice as human-in-the-loop, meaning you want to watch the work happen, or AFK, meaning the agent can do the work unattended.

Build each slice test first

You build each slice with the red, green, refactor loop. You write one failing test, and you run it to confirm that it fails. Then you write the smallest amount of code that makes the test pass, and only then do you clean up. The course is strict about writing one test at a time, because writing all the tests first and all the code second produces tests of imagined behavior instead of actual behavior.

You write the tests against public interfaces, and the tests check observable behavior rather than implementation details. The course gives a simple warning sign. If renaming an internal function breaks a test, the test was checking implementation. Mocks are allowed only at the boundary of the system, e.g., for a third-party API or for the current time. Your own modules never get mocked, because a mock of your own module makes the test depend on the module’s internal shape.

Keep the agent in its smart zone

The course describes the context window as having a smart zone and a dumb zone. In the smart zone, roughly the first 80,000 tokens of the window, the model reasons well, and past that point its output gets less reliable. The course’s working rules exist to keep you in the smart zone. Clear the conversation between tasks instead of letting one session run all day, and start a fresh session when the context use gets near 40 percent. Avoid repeated compaction, where the tool summarizes the conversation to free up space, because a summary of a summary makes the agent harder to predict. A fresh session costs the agent a minute of re-reading the repo, and the course recommends paying that cost every time.

Keep the steering file small

Claude Code reads a file named CLAUDE.md on every request, and the course keeps that file as small as possible. The recommended contents are a one-sentence description of the project, the package manager if it is not npm, and any commands the agent cannot guess, e.g., a non-standard typecheck command. The course cites a rule of thumb that a frontier model can follow roughly 150 to 200 instructions at once, so every line in CLAUDE.md spends part of that budget on every request. You put longer guidance into skills, which are folders of instructions that the agent can see by name and loads only when they become relevant.

Feedback loops catch what the agent gets wrong

Because the agent’s output varies from run to run, the course treats fast automated checks as the main defense. Type checking, tests, linting, formatting, and pre-commit hooks all run without you in the loop, and when one of them fails, the agent reads the error message and fixes its own work before you review anything. The course’s rule of thumb is that types and tests give the strongest signal for the least effort, so you set those up first. For a brand-new project, you set them up before any feature code at all, because the quality of the agent’s output depends on the state of the codebase it works in. The agent copies the patterns it finds in your code more reliably than it follows your instructions, so a messy codebase produces messy output no matter how good your prompts are.

The full workflow

The course builds up progressively, and the pieces add up to one workflow. You grill the idea until you and the agent share an understanding. You research whatever the grilling could not answer, and you save the findings in the repo. You build a throwaway prototype if nothing in the codebase sets a precedent for what you are making. You write the PRD and break it into slices. Then you build the slices one at a time, each in a fresh session, and you commit after each slice. At the end, you review the result against the PRD and fold what you learned back into your steering files.

One more idea from the course that I plan to use is the decision record. An agent can read your code and your commit history, but it cannot answer the question “why did you do it this way”. The course’s fix is to write short decision records during the grilling phase, one per significant decision, with the alternatives you considered and the reason you rejected them. Future sessions of the agent can read the records, and you can read them yourself when you come back to the project months later.

What I am changing about how I work

The biggest change for me is where the effort goes. I used to spend my effort on writing the prompt, and the course moved that effort to the alignment before the prompt and the checks after it. I am applying the workflow now to my greenfield project, and a new project is a good place to practice because there is no existing code to fall back on. The grilling session should settle the design before any code exists. The decision records should keep the project understandable to future sessions of the agent. The red, green, refactor loop should catch the agent’s mistakes before I review the code.

If you want to read the skills themselves, they live in the course’s example repo on GitHub.