Transcript
0:00 AI imposes super weird constraints on your code base. And most code bases out there in the world, probably including yours, are not ready. Your code base, way more than the prompts that you use, way more than your agents.md file, is the biggest influence on AI's output. And if it's designed wrong, it can cost you in a bunch of different ways. It can mean that the AI doesn't receive feedback fast enough, so it doesn't know if what it changed actually did what it intended. It can find it super hard to make sense of things and find files and work out even how to test things. And finally, it can lead you into cognitive burnout as you try to hold together AI in your code base and patch it all up and keep everything in your mind. And my thesis here is that software quality matters more than ever. In other words, how easy your code base is to change makes a huge impact on how AI then goes and changes it. And the stuff that we've known about software best practices for 20 years still holds more true than ever. And if you're interested in getting better at this stuff, then check out my newsletter AI Hero. I teach you all about AI coding, but this is not for vibe coders. This is for real engineers solving real problems. And if that's you and you're not sure how to handle these new tools, then you are going to love it. Now, let's imagine that this here is our code base. Each one of these little squares represents a module, and this module might export some functionality.
1:16 It might export a function, might export some variables, might export a component if it's like a, you know, a React or a front-end thing. I want you to imagine that this is the image of your code base that you hold in your head. Now, you might inside here have some vague groupings of different functionality. For instance, here you might have, let's say, a thumbnail editor feature, and all of these different modules contribute to that. Over here, you might have a little video editor feature or something. Down here is all the code related to authentication. Up here is a bunch of CRUD forms for updating stuff, maybe in a CMS. And over here are a couple of, for example, features that I can't be bothered to think of examples for. Now, this map that I've created here of all of the located modules in this particular code base, they're not actually reflected that much in the file system. They're all really jumbled up together. If I want to just grab, let's say, an export from this module and import it down into this module, I can.
2:04 There's nothing stopping me. And so, what you might end up with is a bunch of kind of disparate relationships between stuff that doesn't actually relate to each other. Now, you as the developer understand the mental map between all of these modules, but what the AI sees when it first goes into your code base is this. It doesn't see all of the natural groupings and all the natural relationships. What it sees is a bunch of disparate modules that all when it jumps into your code base, it has no memory. It has not experienced your code base before. It's like the guy from Memento who just steps in and goes, "Okay, I'm here.
2:36 What am I doing?" So, my first assertion here is that you need to make sure that the file system and the design of your code base matches this internal map that you have of it. This is because if you describe something over in the video editor section and you use it via a prompt, then you want the AI to be able to find it easily. The AI won't go in knowing every single function, every single module, and what they're supposed to do, and how they link to each other.
3:01 And the best way I have found to do that is with deep modules. Now, deep modules comes from this book here, which is a philosophy of software design. And the idea is that in order to make your system easily navigable and easy to change and also easy to test, is that you have a deep module, so lots of implementation controlled by a simple interface. What that looks like in terms of our graph is instead of many, many small modules, you end up with these big chunks of modules with simple, controllable interfaces. And this means that any exports from these modules have to come from that interface. Now, when I read that about deep modules, I immediately thought about putting AI in control of these modules. Because this is an opportunity to introduce a kind of seam into the code base. I don't really care about what's happening inside here, which is the implementation, I just care about what's happening in the interface.
3:51 Because the interface, which is you know, the publicly accessible API of this module, I can carefully control and I can apply my taste to and design. And then the stuff inside here, I can just delegate to an AI to control, and I can write tests that completely lock down the module in terms of its behavior. So these are not just deep modules with simple interfaces, they're also gray box modules. In other words, I don't actually need to look inside these modules. I can if I want to, if I want to influence their outcome or if I need to apply some taste to the implementation, or I need to improve their performance or something. But as long as the tests are good, then I don't really need to care about what happens inside. Now this has three massive benefits. The first one is that I can make my code base way more navigable.
4:36 Let's for the sake of argument just call each of these services, right? The video editor service, the thumbnail service, whatever. If I document these each inside their own folder, and I have the publicly accessible interface kind of like really obvious in a type section, then the AI when it's exploring my code base, it can see all of these different services on the file system. It can read and understand the types that they export before it actually looks at the implementation. And then it can say, "Okay, I've seen the interface, I understand what this does. I don't need to look inside cuz I can just trust what it's returning." In other words, we've designed our code base for progressive disclosure of complexity. The interface sits at the top and it just explains what the module does. And then when we need to, we can look inside the module and make changes to it or look at it to understand its behavior more deeply. The second one is that we reduce the cognitive burnout of managing this code base. Now, as a user, I can just go, "Right, I need something from uh I don't know this made up feature or let's say the authentication bit over here. Let's say what Let's see what the public interface is. Let's just grab that and use it." And instead of needing to think about the interrelationships between all of these modules, I can just keep kind of like seven or eight lumps of stuff in my head and go, "Okay, the AI manages the stuff inside that. I only need to worry about designing the interfaces and how they fit together. Now, this of course is still a million miles away from vibe coding because you need to apply taste at the boundaries of these modules. You need to be really good at deciding, okay, what goes into that module, what goes into that module. And what you really want to avoid are lots of little shallow modules, which is kind of what we had up here, right? Each of these modules is just like, sure, it's kind of interrelated and grouped together, but really they're lots of tiny shallow modules which are testable in these tiny units which are really hard to keep all in your head. And so, by simplifying the mental map of the code base, we reduce cognitive burnout that comes from managing this code base.
6:24 And again, this is nothing new. This is a 20-year-old software practice. And the third one here, I mean, I'm really just repeating myself, but this is what we've been doing all along. This is how good code bases have supposed to have been designed. So, what works here for humans is also great for AI. We need to stop thinking about AI as like this superpowered developer, as like, you know, it's going to reach AGI and understand that it's got some weird limitations. And the limitations that it has are that it's a new starter in your code base. So, you need to make your code base friendly and ready for new starters because you're going to be spawning like 20 new starters every day, or probably more, just to look at your code base and make changes. So, that means the map of your code base needs to be easily navigable and it needs to be enforced by using these modules. Now, some languages make this easier than others. For instance, in TypeScript and JavaScript, it's actually not that easy to make these services, make these modules sort of boundary in this way. I want to give a quick shout-out to effect because I posted a video on effect a few months ago. I'm actually using effect way more than I did back then, and it makes this kind of sort of seeming modularizing of your code base really simple. The final thing I want to say here is that you need to be thinking about these modules and how you're affecting them and how you're designing the interfaces in every coding session that you do. That means right from the early planning stage when you're writing your PRDs when you're turning your PRDs into implementation issues, you need to be thinking about the modules that you're affecting and the interfaces and how you are going to test them. Because tests and feedback loops are essential for an AI because of course they're essential for a new starter joining the code base. If you want a new starter to contribute effectively, you need a well-tested code base so they can see what their changes do as they ripple out. So that's my rant for today. Your code base is probably not ready for AI because you're not using enough deep modules. And instead you've got a web of interconnected kind of shallow modules like this which are really hard to navigate and really hard to test and really hard to keep in your head. Now if you dig this then of course you will dig my newsletter where we go more deeply into topics like this.
8:28 Thanks for watching folks. What else do you think goes into making a great code base for AI? I really love this metaphor for deep modules but I know it's not the only one going. There are plenty out there. Thanks for watching and I will see you very soon. So when you are thinking about your code base with AI, what are you thinking about? What kind of 20-year-old books do you want to recommend? Leave it in the comments.
8:46 It's the easiest way to keep up with all of my stuff and the link is below.
Summary
- The design of your code base significantly impacts AI's output more than prompts or documentation.
- A well-structured code base allows AI to receive timely feedback and understand relationships between modules.
- Cognitive burnout can occur when developers struggle to manage complex, poorly organized code.
- Deep modules with simple interfaces enhance navigability and reduce complexity for both AI and developers.
- Maintaining a clear mental map of the code base is essential for effective AI interaction.
- Good software practices from the past are still relevant and beneficial for modern AI integration.
- Testing and feedback loops are critical for enabling AI to contribute effectively to the code base.
- Languages like TypeScript can complicate the creation of modular services, but tools like Effect can simplify this process.