Making surgical changes to large codebases
When you're confronted with a huge codebase you're unfamiliar with, it's tempting to go one of two ways: don't bother making changes at all, or make sweeping changes across the entire system. Both approaches are bad. The first leaves problems unaddressed, and the second introduces unnecessary risk.
The better approach is to make surgical, modular, incremental changes. Use this as a learning opportunity about the codebase. Instead of trying to understand everything at once, let the AI help you build a mental model gradually while making progress on your actual task.
The process
When you need to make changes to an unfamiliar codebase, start by asking the AI to do a deep dive. Give it context about what you're trying to accomplish—whether it's fixing a bug, adding a feature, or refactoring something specific. Then ask it to study the codebase within that context.
The key instruction is this: ask the AI to outline the top three things that need to be changed, and ensure those changes can be done incrementally and testably. This constraint forces the AI to break down the work into manageable pieces rather than proposing a massive refactor.
Here's the pattern I use:
Do a deep dive of this codebase, study it within the context of [your specific task], and then outline the top three things that need to be changed. Make sure each change can be done incrementally and is testable.
This approach does two things. First, it helps you build a mental model of the codebase by focusing on the specific areas relevant to your task. You're not trying to understand everything; you're understanding what matters for what you need to do. Second, it reduces cognitive overload by breaking the work into discrete, testable steps.
Why this works
The incremental approach has several advantages over trying to change everything at once.
Each change can be tested independently. You can verify that the first change works before moving to the second. This makes debugging much easier; if something breaks, you know exactly which change caused it. You're not left wondering which of twenty simultaneous modifications introduced the bug.
It also makes the work safer. Small changes are easier to review, easier to understand, and easier to revert if something goes wrong. You can commit after each incremental change, creating a clear history of what changed and why.
Perhaps most importantly, this approach helps you learn the codebase gradually. Instead of drowning in unfamiliar code, you're building understanding piece by piece. By the time you've completed the three changes, you'll have a solid mental model of how that part of the codebase works.
Building your mental model
The deep dive phase is where the learning happens. When the AI studies the codebase in the context of your specific task, it's identifying the relevant files, understanding the data flow, and mapping out dependencies. This analysis becomes your roadmap.
As the AI outlines the top three changes, it's also explaining why those changes are necessary and how they connect to the broader system. You're not just getting a list of files to modify; you're getting an understanding of how the pieces fit together.
This mental model building is crucial for future work. Once you understand how one part of the codebase works, that knowledge transfers to related areas. The next time you need to make changes, you'll have a foundation to build on.
The constraint of three
Why three changes? It's enough to make meaningful progress without being overwhelming. Three changes give you a clear sequence: do this, then this, then this. Each one builds on the previous, and you can test after each step.
If the AI identifies more than three things that need changing, that's valuable information too. It tells you that the work might be larger than you initially thought, or that there are dependencies you need to understand first. You can always ask for another set of three changes after completing the first set.
The key is that each change is incremental and testable. An incremental change means you can make it without breaking existing functionality. A testable change means you can verify it works, whether through automated tests, manual testing, or some other validation method.
See this in action
This practice connects to several core concepts throughout the book.
Automation philosophy
The Automation philosophy emphasizes systematic approaches to complex problems. Breaking down large changes into incremental, testable steps is exactly that: a systematic way to work with unfamiliar codebases. You're automating the process of understanding and modifying code by using AI to do the exploration and planning, then executing the changes methodically.
Testing practices
The emphasis on testable changes connects directly to the Testing chapter. Each incremental change should be verifiable, whether through existing tests or new ones you write. This ensures you're making progress safely, with confidence that each step works before moving to the next.
Refactoring approach
This surgical approach aligns with the Refactoring chapter. Good refactoring is incremental and testable. You make small changes, verify they work, then make the next small change. The same principle applies when working with unfamiliar codebases: make surgical changes, test them, then proceed.
The goal isn't to understand the entire codebase before making changes. The goal is to understand enough to make the changes you need, and to do so in a way that's safe, testable, and builds your understanding over time. Use AI to do the deep dive and planning, then execute the changes incrementally. You'll reduce cognitive overload, build a mental model of the codebase, and make progress on your actual task.