Great International Developer Summit (GIDS)

The AI-Native Codebase - Ragunath Jawahar

59:27 · 21 Apr 2026 – 24 Apr 2026 · YouTube

About this talk

This talk explores the concept of legacy code and how it influences software development, especially in the context of modern coding practices powered by AI agents. The speaker shares personal experiences in dealing with legacy code, emphasizing that legacy code refers to codebases that developers are unfamiliar with, regardless of age or technology. They discuss the significance of understanding software structures and team dynamics in maintaining and evolving these codebases effectively. Throughout the session, the speaker introduces tools and techniques for automating code production and verification, aiming to enhance productivity in software development. Finally, they address the importance of adapting to new paradigms, such as AI-native codebases, that facilitate more efficient coding processes.

Full transcript

I I I believe he gave a little bit of introduction about me. Um and before we both go ahead, I want to talk about what legacy code means because uh that is a overloaded term and it has like different meaning for different people. And the way how I would say what a legacy code is is basically um code that you're unfamiliar with. And code that uh you

were not really involved in creating. All right, that's what I call as legacy code, right? I mean, you're not talking about mainframes, you're not talking about other things. This These are just like code bases uh that you're not familiar with. And um you were not involved in creating these code bases, right? And by that definition, you could all say uh with coding agents in place, you all

you get involved in some parts of the process but not entirely every everything, right? So, to give you my background, I uh started working with legacy code in 2017. I was in a company um I was consulting a company in Delhi. They were a fintech startup and then they had um inherited a large code base from an agency. It was horribly horribly hard to work with, not

because the code was bad. They were like really good engineers, the kind of product that they built. It's just because I was not familiar with the patterns that they were using in the code base. So, the first thing that I did was I picked up this book called uh Working Effectively with Legacy Code, the uh one of the most popular books when it comes to working with

legacy code. And again in 2019, I started uh reading a couple of books by this person called Adam Tornhill. It's basically tells you how you can take a code base and understand the teams and how these teams interact with these code bases, right? It's like not the structural aspect, but then uh the organization organizational aspect and the aspect from teams that are maintaining these code bases, right?

So, these were uh some of the key uh milestones I would say in my career that actually changed the trajectory of how I started approaching software development. And what I do at Legacy Code where it falls into these four different pillars. Now that producing code is actually automated and it's sort of like an industrial revolution going on right now because the amount of code that each and

every one of you in this room is capable of producing using coding agents is humongous, right? So, it's basically mechanized production at this point in time. And if you have if you're producing code at a rate which is not human, like at machine speed, then everything else related to code bases has also should be mechanized, right? Uh, so in that case, since 2019, I've been building tools

that that are very specific to understanding code bases in general, right? So, 2019 till now, that's something that I've been doing like more algorithmically in the pre-AI era. And after 2019 um, you also see when you work with large large code bases, you have like large problems. Like you have like huge modules, you have huge files and you can't break these files down like say for example,

if you have a 5,000 line Java file for instance, how would you even break it down? Like it's very very hard to do that without tooling. So, we built tools that would help you visualize sub-networks inside a large class and then you can start breaking it down even with even if you don't have tests, right? So, that's also like a lot leaning towards deterministic tools, algorithmic tools.

And this year is where we've focused on a couple of other things which is one related to mechanized verification. You end up generating a lot of code and the primary way for a lot of engineers even today to verify code is to just review it, right? And a lot of us are feeling the heat and bottleneck when it comes to reviewing code manually because it's simply no

longer sustainable. So, we need alternative ways and alternative abstractions to verify code that is being generated. So, that's one thing. And the other thing is even when you are evolving systems, when you're building systems, right now we are prompting AI agents to do that, but there's a better way to do it and that's some of the some of those work is going into direct evolution. So, this

year is where we take a lot of stuff that is algorithmic and deterministic and then uh use it along with AI to amplify and and make different parts of your SDLC better. Right? So, that's what I do um and this is the question that's in front of you. Yeah, I'm pretty sure like all of you came in because you wanted to do AI native code bases, but

what according to you is an AI native code base? Anyone? There are no wrong answers. Like even like the the answer that I'm going to give you is probably going to be wrong. Nice. Yeah. I I would go go with that, right? Like it's optimized for agents to read and also evolve by the process, right? And often times like a lot of us could be hearing about

especially claims from a lot of frontier labs like OpenAI for instance. Like they run a harvest engineering experiment. Anthropic. A lot of these companies claim they uh agents contribute 100% of their code base, right? Like a lot of companies say we are like about 70% of a code code base is written by AI, 80% of the code base is written by AI. And I I am at

this point where I believe 100% of the code base can be written by AI and most of our code bases that I have are built and maintained by AI at this point, right? So, that's that's very much there. So, uh that's what we're going to talk about. Uh today we'll talk a lot of stuff, but then we'll also go back to the foundation so that regardless of

whatever stack that you're using, whatever programming language that you're using or whatever architecture that you're using right now, if you learn the basics, you can probably adapt them to the kind of capabilities that you to have with AI agents in your code bases. And before we go, um can I have a show of hands like how many of you have seen this diagram? No one? Okay. So,

this diagram is from a blog post by this person called Steve Yegge. Steve Yegge is X Amazon, X Sourcegraph, X Google. He's done a bunch of stuff um over 30 to 40 years of programming experience, professional 30, overall 40 years of programming experience. And in his blog, um it's called Gastown. Gastown is a agent orchestration tool. So, it allows you to use agents work simulta- like across

it allows you to spin up agents and orchestrate them across multiple code bases. Like that's what uh Gastown does. And in that blog, he puts this picture, right? And in this picture, you could see there are like different figures and I'll go through one of uh each of them at a time. And the way how he talks about it is um uh figure one, for example, is

how we used to build a software like long time ago. Like I I hope I hope most of you are still using not using just like plain old IDEs, right? So, earlier we used to use IDEs, no support. I think like the most AI thing we have is auto-completion in some of these uh old uh IDEs, right? Um and it was huge. So, level one, as he

calls it, is you are building software without using any agents at all, right? Like that is level one. And then, the And the second stage is you are using um an IDE, an AI-powered IDE, probably by a large language model. It has auto-completion and it you probably are using the chart mostly to like communicate with the agent, chat with the agent. And sometimes you also ask it

to do tasks, but you're not very confident with your agent, so you keep your permissions on all the time. So, every tool call, every operation that the agent does, needs your approval, like your explicit approval, right? And at this stage is where permissions, like you know, granting permissions become annoying. So, you want want the agent to like do most of the things without asking for approval. at

this stage uh you no longer are using the IDE uh too much because instead of editing multiple files or like, you know, uh editing the file on your own uh agentic development becomes default. So, most of the time you're only interacting with your coding agent, right? So, that's why like uh the the the amount of code that you see uh is also very limited. And at this

point you're completely out of the IDE. You no longer use uh I don't know, like IntelliJ with your Juni plugin or Copilot plugin or VC Cursor or whatever. Like so, those are like IDEs integrated with a coding agents. And at this point you just can work with agents without an IDE, right? And the form factor here is not just the terminal, and this could be anything. It

could be Claude Code, it could be CodeX, it could be Open Code. Like a bunch of other uh coding agents available that are you can use in the terminal. But when the when this blog was written, the form factor was a terminal, but right now you have Claude Code desktop, you have CodeX app, which is also a desktop application. So, When I say uh an agent outside

an IDE, it's basically it doesn't matter whether it's a terminal one or is it based off of desktop form factor form form factor, right? It's just a paradigm of having your editing and agent as a chat panel no longer is applicable. And then he calls it as another level where you have like multiple agents working on your code bases, right? And then and it gets like worse.

And at at the final stage is where you have orchestration, right? You have some control over uh dispatching tasks across agents, like, you know, reviewing, verification, a bunch of stuff. And if you look at this, all of you, you're going to place yourself somewhere in this box. And when something is presented as a level to you, like even the way how Steve presents this, he presents it

as a natural progression or like you know, increase in ability. There's nothing wrong to think about it, but it is more counterproductive in that case because moving from one level to another may not be necessary for your use case. Right? And moving from one stage to another also means, for example, if you want to be on level eight, like agent orchestration, which means you need to have

a budget. I I I believe the budget is about $4,400 uh dollars a month. So, that's like $4,400 a month per developer. Which a lot of organizations cannot afford. Right? Like I I've met organizations that can afford uh $20 a month. Right? They're like And then like they give you more usage if you ask for it. Right? And there are like organizations that set a cap of

$50 a day. Right? So, you always have constraints. So, even though you want to, you can't because like you are not in the environment where you are can do it or like doing that would be more expensive in your organization. Right? So, for example, if you have an orchestration layer, if you don't have a verification or like if you don't automate some parts of your verification, they're

going to have an insanely uh long queue at your review pipeline. Right? And you may not have enough engineers to even go through the queue. Right? So, it's not just like a a matter It's not a question of individual capability or ability. It's also what your organization is capable of and is set to do and what is available at your uh disposal. Any questions so far? So,

the way how I see this, uh like Steve calls this levels, but I call it mode of operation. So, where you want to be in any of those stages really depends on what your goals are. Like, what is your goal? What is your organization goal? Example, right? Do you want to move on? And what this diagram does not explicitly talk about is it only talks to you

about like, okay, I have different ways of interaction with the And I have like the number of instances of agents running on my system, right? But it does not really talk about there is another dimension like the number of code bases, right? Traditionally, developers tend to work on one code base at a time. And in some organizations you work on more. Like, if you do microservices, if

you are like if you're owning the entire stack, then you work on multiple code bases, right? But diagram does not make that explicit. Right? So, when we talk about modes of operation, then you also have to know what kind of qualities should your code base have in order to achieve that kind of operation like that mode of operation in inside your organization. Let's go against this one

at a time. Let's talk about how agents work on a single code base, right? Like, that's like the the thing. And the form factor here doesn't really matter because um here is a terminal, but you could if you're using Codex app or if you're using Cloud Code, it could still be different. How many of you using Cloud here? What about Codex? Cursor? Who said both? You use

both? Depends on limits? Anyone else using some other exotic coding agents? Vince Surf. Vince Surf? Open code? Sorry, Co-pilot. Okay, sorry. I forgot Co-pilot. Like, most of the enterprise people should be on Copilot. Is that it? Antigravity. Hero. Do you like Hero? It works. Okay. It's a It's a very different um model, right? It It forces you, I think like other agents let you pick and choose

the kind of workflow, but Hero has like two modes, but then it forces you to do certain things in a certain way. That's fair. That's fair. A- Anyone else? All right. Let's talk about this. And we're working with a single agent on a single code base, it's something that's very familiar with it. How many of you work on single code bases? Very few. This unlikely. Um how

many of you work on more than one Very nice. so in this case, uh if you look at the bottlenecks, the bottlenecks are basically the state of your code base itself, right? Like I'm not using the term code base quality because that's a term that has been used so much, so subjective, non-standardized, and means different things for different people, and it means different for me today versus

what it'll mean for me 3 days down the line, right? So I'm not using the word code quality, I'm using uh uh more about structure because you'll also know what I mean by structure, right? And also your understanding of the code base matters greatly. The The developers that are very effective in using agents are the ones who understand the problem domain, the prob- ones that understand the

solution that you're using, like whatever framework, library, whatever you're using, and then in addition to that, like the kind of code base that you already have in place. So the what the ones that understand the code base better are the ones that are like using are very effective in using agents as well. And at this point in time, um guardrails are a non-negotiable. I have seen teams

or deploy code bases without CI. I would like to say it's not your fault, but with AI I wouldn't say that it's not your fault. Um, so the god rails become a lot more uh important at this point, right? Because coding agents are not really good at producing structured format. Even if you ask it to say, "Okay, follow the guideline, like use two spaces for indents." It's

not going to do that because it does not understand what that means. So, even if you give it a sample output, right? So, if you have tools that are already doing this, you should rely only on those tools, like formatters are like great examples. Like some languages come up with their built-in formatters where you don't have like a lot of problem. But then for other languages, you

need to pick a side right now if you haven't already, right? Like that's the bare minimum if you started working with Um, reasons being merge conflicts, like you know, uh all of that part. Like it's it's something that you don't really want to deal with. And if you're still dealing with problems at that level, it will never let you go to a different level because these are

the problems that that are going to occupy your mental space. So, when it comes to god god rails, CI non-negotiable. Formatters non-negotiable. Linters tests, get hooks, none of these are like negotiable at this point because if you don't have any of these, you cannot go to the next level at all, right? And and we're just talking about a single agent working on a single code base. Right?

So, I would just assume that you have all of these things in place. And feedback loops also matter greatly at this point. example, for example, you have get hooks that can catch like some of these problems so that it doesn't like fail your CI for instance, right? Like linters and formatting issues. software that is going to take a lot of time to build, right? The agent is

also not going to be very effective because agents cannot They've become better at it, but they they're not wired to produce syntactically correct code. It's something that they can't really do. And they heavy rely uh heavily rely on uh lint like sorry compilers to do that. So, every time when agent makes a change it'll probably run a build or it'll try to run the compiler and then

see if there are any syntactic errors and then it'll start fixing those syntactic errors for you, right? So, at this point all of these are like absolutely non-negotiable. But if you have like a tool that like if you code base takes a lot of time to build, then the feedback loop is also going to be late because the agent will end up spending more time in making

these tool calls and editing your file before it gets its syntactic syntactic correct, right? So, this level of diligence or infrastructure setup was used to be a privilege in the pre-AI era, right? But right now it's not a privilege at all. It's like the new normal that you have to adapt. And now I'm going to talk about using multiple regardless of the of agents that you're going

to use we'll talk what it take to use multiple agents on a Now, when you start working on single I'm sorry. You spot the error here? Sorry. Oh, sorry. This is a multiple agent on the single code base, right? Sorry. Um so, everything that we discussed previously like the the fast feedback loops and the what do you call it? Um guardrails all of that still matter a

lot, right? And then and once you start using multiple agents on a single code base, you have to make sure that you can you can dispatch multiple agents to work on the code base in parallel, right? Which means your boundaries have to be very clear not only within um not in only in terms of layers, but also in terms of features, right? And in this at this

point, task decomposition also uh matters because the agent can do a lot of things in a very short amount of time, but you have to sequence them in a way so that they don't step on each other, right? So, if you have a code base that is sort of well-structured, has clear boundaries, you can spin up multiple agents on your current working directory. But if you do

not have that kind of segregation, the cost shifts elsewhere. One is how do you spin up these multiple agents? Then you have to start relying on Git work trees. So, you'll have separate instance of the work tree like, you know, working uh directory checked into separate work trees, and then you can dispatch different agents on it. But when you merge them, you there are risks where you

will lose changes. If you don't have tests, then you will have to verify them manually. And when you're merging them, there's a merge cost because there are changes where one agent may override the change that you dispatched, right? So, structure is also important, but then also how you sequence and ex- execute those tasks also become important, right? And there's one more thing that is um you should

also be aware of is the fact um different programming languages and frameworks are like use different kinds of built builds, right? Like say for example, if you're using uh Node.js, you do a npm install, all those dependencies gets installed locally in your folder, right? Like same I I believe it's the same with Python as well. But then in terms of uh Java or Kotlin, you have a

shared uh library directory, so you don't really pay that cost once in a while, right? If you're working with languages like Rust, then you get a target folder, but the target folder itself is like so huge, can run into multiple GBs at a time, right? So, if you're doing five work trees, and each target work tree is about like a GB, they you have to like recreate

that in every single work work tree, right? Which also is going to occupy your disk space, right? So, based on what kind of programming language and technology that you're working with, you also have to see how not only dispatch works, but also like the merge also works. And can you afford to run these many agents? Like say for example, if you don't have enough disk space left

in your machine, even though you have the ability to run five agents, you probably won't be able to run five agents, right? So, it's not only that the the ability to run multiple agents depends on cost like of course like how much token you tokens you have to uh like the capability to spend, the programming language and the uh library that you're using, um how are you

running these programs in your machine, right? Like you know, your RAM and as well as your disk disk space. Those also becomes They they also become constraints. It's just just not a matter uh cost, right? And in addition to that, how your code base is architected architected and uh how you have decomposed and sequencing your task, that also matters, right? So, it's not like a linear progression

from one stage to another. Like And it it becomes a lot more harder if you're using with code bases that have a long shelf life like using doing all of this on a code base that is 5 years old, 7 years old, or 10 years old is a lot more harder than to do it on a code base that is like a year old and has like

probably 100,000 lines of code, And verification, again like you have uh verification also becomes a very very painful bottle neck to deal with because when you have five agents running, if four uh agents would do what you want to do like in in a best case scenario and one fails and one fail the failing agent would also like additional work that you did not think of previously,

right? So, that is also falls on the developer in addition to meetings and everything that you're doing. So, verification has to be very strategic. It cannot be random um or it cannot be uh something that people assume that developers are supposed to do, right? It's it's something that has to be among um teams. Context switching again also becomes a problem, right? Like it's as human beings uh

I I believe like when AI came into the picture, a lot of people thought like we will have less work, but that's not true. Like it's just that we we like shifted the work somewhere else, and it's more intense than ever. Like the work has uh we you couldn't say like, "Oh, I was able to do it in 1 day whatever I was supposed to do in

5 days I was able to do in 2." Okay, like that's true, but what are you doing the for the other 3 days, right? You're doing more work, right? You're not doing less. And the more and more work you do, you also end up like uh switching context between a lot of uh tasks at hand. So, multiple uh agents also means multitasking ability, and like that's also

I believe is a learned skill, and like not everyone can pull it off uh and pull it really well as well. Again, the costs uh compound. Then you have like wasted token, because if you have failing tasks, then like all of that goes for a toss. Orchestration. So, this one is all like theoretical. I have no first-hand experience running an orchestrator. If you want like I I

believe there are like a bunch of orchestrators uh orchestrators available. Um Gastown is one. There's Conductor. I believe uh Intelligo has shipped something called air.dev, so that's also like a orchestration uh tool for multi-agent workflows. So, you can use some of those tools, but I personally don't have first-hand experience uh using an orchestrator. So, this is basically my hypothesis on what happens, right? Like you're uh uh

uh For example, a lot of times you would run out of work. Like if you work in an organization where there is not a lot of work, especially in smaller companies and startups, with AI, you constantly run into this problem of like like, "Okay, what do we do next?" Right? Like how do we build like what do we do next, and who's responsible for filling this backlog?

Is this your product manager? And often times it's mostly not people in your tech team, right? It's you can probably fill it up with technical debt items or like anything that is related to the code base itself, but in terms of product road map and product direction, someone else has to keep filling up this backlog for you. So, at this point um costs are very, very important

because like how much money can you afford to build build uh spend on tokens? And second thing is like who is keeping the backlog updated? And like how are you a- and how much work are you shipping and how how much work are you measuring in production, right? So, all of that is basically an organization con- constraint. If you want to be here, it's not just on

the tech team. Like right now, like everyone else across the organization has also should get involved in doing this. Now again, like the same thing starts to happen, right? Single agent and multiple code bases. I saw a lot of hands go up and people said like you use multiple What is your mode of operation? Do you use one agent across multiple code bases? Like how does this

work? Or you use a single agent on a single So, you use a single agent on a single code base at a time. Like you don't use it on multiple agents. Sorry? There's no need to actually do that. Okay, there was no need to do that till now. Interesting. So, here when I talk about single agent I could I could talk about a few things, right? Like

say for example, uh we have tooling. Most of them are command line tools that are meant to run on certain machines, right? But you would also end up having like a UI part of it. Like sometimes to debug, sometimes to let customers know what they are working with, right? So, you have a command line tool that is used by agents uh and uh is run headlessly, but

then you also want humans to sort of once in a while take a look at what is going on, So, in this case, what typically happens, the way how it we do it is we have a root directory and then you have like two sub modules. One is the command line tool and the other one is the uh what do you call it? The desktop application that

is sort of used to inspect the output of the command line tool, right? At this point, what is interesting is at some point in time you have to keep both at sync. When you're adding new capabilities to the CLI, you also have to make sure that the UI has access to those capabilities and can tap into those capabilities. And often times you you don't know how to

do that. So, what we tend to do is like we we generate a usage diagram, sorry, usage document from the CLI. And then find the diff between the old and new document and that becomes the input to the desktop application, right? And there is an automatic way how we do this. So, every time the CLI changes, you could just say like I would make a change with

the coding agent on the CLI. And then ask the same agent to make the changes on the UI, right? At that point, the agent has enough context not only about what the fly what flies were added, what data format was added, but it also knows what changes has to happen on the desktop application, right? So, at this point, when you if you think about context management, you'd

say, "Okay, like this these are two different applications." And sometimes the CLI is written in Rust or Go and then the command line to like the desktop application is written in Electron. So, you probably think like, "Okay, like this doesn't sound right." But surprisingly, it works, right? Because the agent can translate across different languages and it's also pretty fluent. Um so so uh if the task that

you're doing is coherent across multiple repositories, you can still choose to uh use a single agent across multiple repositories, And the topology also matters. We like talk about this because a lot of people will be comfortable with mono repos, but they're probably not familiar with the composable mono repo using Git modules. Uh if you're using a multiple agents even in your organization, there are cases where different

teams use different agents. Like some of them use uh Copilot, some uh Claude, and Claude is notorious for having its own standards. It has its own skill directory, it has its own uh Claude.md file, and it does not It is not compatible. Like say for example, if you take Codex, Codex can still work with Claude.md, Codex can still with work with Claude skills, but that's not possible

with uh what do you call it? Um a different agent, and most agents understand this uh naming convention. So, I'll I'll propose an alternative topology uh or a a structure how you could work with multiple um uh code bases effectively. Again, it the the general thing is you'll notice that the thing just gets more and more harder. Like it's it's not getting easier. Like so, even though

the diagram shows a linear path or like a simple representation of how the progression looks like, but then the progression req- requires investments in skills, in infrastructure, and also an an appropriate budget to work with uh multiple code bases. Right? Same thing. So, moving across operational modes um is basically a individual skill issue, and it's also an organizational issue, and we have to like sort of adapt

ourselves the way how AI has fundamentally changed your capabilities and has also removed a lot of barriers uh that are no longer true. For example, uh if you have been doing engineering [clears throat] from a AI pre-AI era, we only come from a scarcity mindset, right? Like if you do If you If you If you're going for a quarterly plan, then the first thing that your engineering

manager or your uh engineering lead does is like find out what is our capacity, uh what are all the things that the business wants to achieve and how much of this can we get done, right? So, it's always about uh limit limited number of resources and prioritization. Like that's the how every engineer is sort of trained to work in in in in that way, right? But with

AI, that has completely gone away. Like you you no longer have to sort of budget for capacity or even you don't have to budget for specialization, right? Because if you have engineers who understand the product well, they can work across technology stacks, right? Like language has is no longer a barrier. And just unlearning that we no longer have these limitations when you're working on engineering working with

software, that itself is like a huge change for a lot of us. It's It's a lot of unlearning to do. Right. And now, when we also talked about these things, right? Like everyone has a different kind of setup, right? Like some folks use separate code bases. You don't have to like combine them together. A a bunch of other stuff, right? So, when we talk about AI-native code

bases, come back to the point where we say, "Okay, can agents work on these code bases reliably?" Like not only single agents, but also multiple agents on And to do that, these are the four things that we want Right? Like there's nothing else. Like regardless of whatever you do or whatever stage that you are in your AI adoption journey, these are only the four things that you

have to worry about. Like the first thing is structure, the other one is behavior, the the third one is like verification, and the fourth one is topology. And we're going to see how we're going to take have some influence over all these four different things so that you can convert any kind of code base into the way that you want it to be, right? And I'm deliberately

using the word structure here because I don't want to go with design because when I say design then there is a connotation saying whether design could be good or bad. It's a load of loaded term, right? And like sometimes like we start thinking about design patterns. Like so design is not something that I'm going to talk about. If I talk about architecture, then it's like it's sort

sometimes it's very disconnected. It's like I'm not responsible for architecture, someone else is, right? Like the team manager like your architect or whoever, right? I want to talk about structure because structure exists regardless of whether you want to accept it or not, right? Like if you have working software program like which is non-trivial, you probably have five different classes that are connected to one another in some

way, right? The structure is there. Like you cannot deny it. You cannot uh pretend that it does not exist because if you pretend then there will be friction when you're trying to modify your source source code, right? And oftentimes when it comes to software, we have always conflated the two. Like when we think we don't think about structure separately and behavior separately most of the times. Like

probably when you're trying to do like block diagrams like for low-level design, that's sometimes when you do it. And the other time when you do it is your software has become so hard to change and you need to sit down and actually figure this out, right? And that's why you go look at dependency graphs or you know, like try to understand like what and how things are

connected with one another or like you try to speak with your colleagues or whatever, right? But in terms of software engineering, we've always emphasized more on behavior. What can What can the software do for me today? That's what like we get emphasized like a lot more. And that's what a lot of business people also understand. Like if you have like product owners, product owners understand behavior. Like

what can the software do so that we can charge more or we can like get more customers. Like that's what we over index on. And oftentimes like as engineers also we don't make this distinction. Like if you look at it, you let's go and make changes. You read the code, you do it intuitively, you make the changes to the structure, you make make changes to the code

and then you make it do new things, right? Like that's how it has been for a very long time. But what we all intuitively do, even though even though we don't think about structure and behavior separately, let's say if you are asked to add support to a new project management system. Let's say for example, you've built a system that can read data from Jira or like make

changes to Jira, right? Now, you wanted it to do more things. Like you wanted it to integrate with linear uh or Asana or like a different project management system. What is the first thing that you do? I look at the internal Yeah, you you look at what the current thing looks like. Yeah, you look at the configurations. You look at interfaces or abstract classes or whatever is

your thing, right? Then what do you do? You have to replicate it first. You'd say, "Okay, like there's a Jira connector, there's a Jira X, Jira Y, Jira Z." Then you probably say, "Okay, like can I do a Asana connector with the Asana XYZ?" Right? Like at that point in time, you're just like replicating structure, right? You're like not doing anything else. You're just like replicating structure.

And once you replicate structure, then you want it to or you will start verifying the behavior, right? You'll make appropriate API calls. You're like making a put appropriate database entries. You maybe introduce a new type, whatever that is, right? So, even though we don't talk about structure and behavior explicitly, every time you tend to extend a system, that's how you do it. Right? And when you have

agents that are trying to extend your system, you probably want to have a system in a state where you can work on these things in parallel, right? So, then you will talk about coupling, right? Like why is it too coupled? Like we need to make sure that you can build five different features parallelly, whether it's five different team members or five different agents. It doesn't really matter,

right? structure is something that we have been very underrated for a very long time, but now with agentic development, if you want your codebase to be uh in a state where you can have multiple agents can work well, then you need to have very clear boundaries between your features. You need to have very clear external boundaries. You need to have very clear internal boundaries. You also have

to have very clear extension boundaries, right? So, these are things that we have not thought about deliberately because like the work itself, which is writing code, took a lot of the time and we did not have time to think about these things, right? Like now that bottleneck is gone, if you're trying to understand existing then you cannot read like what 10,000 lines of code every single day

if like that's what you're checking into your repository, right? You need to be very strategic about like how you're going to sense and understand these systems on your own. Yeah, it's basically everything that we talked about. And a a lot of code bases, especially if you have like trouble with agents, like you know, if you cannot run parallel agents, uh if you are constantly running into merge

issues, merge conflicts, it's probably because you don't have the right boundaries or you don't have the right structure in place in your uh code now that like we we've been producing software in a uh much faster pace than we were able to produce like a a few years ago, um I have accepted that it's a fact that I will never be able to understand my code base

line by line. I won't be able to understand the entire class. I won't function. I won't be able to understand my entire module, right? Like that's the reality that I've accepted because um uh when you adopt AI and you become really productive at it like these implementation details need to be abstracted, right? So, one of the things that I've learned to let go is like, "Okay, it's

okay to not understand the code base entirely, right?" But, you still have to understand the system enough so that you can work with the system because if you don't understand how the system is structured or like what the system is doing, you really can't work with it effectively, right? So, here are these things that I pay attention to so the first thing is external boundaries in that

case is pretty easy if you have a web application is your UI like what are the user flows and all of that and if you have a back end system you know you have to like look into your back end API's and like the response shape all of that right and internal boundaries are boundaries between modules like how are they connected to one another like how do

you they communicate do they pass on value objects or do they have callbacks like that is like the how internal boundaries are modeled modeled and how data is transformed between two different modules like so that helps you understand what the internal modules look like right and then you have layer boundaries like then the here comes your logging analytics cross cutting concerns like a and then you have

also feature boundaries which is basically domain based and sometimes it's also carved out by how your teams are structured within the organization right and then extension boundaries is like basically whatever the one of the examples that I told you right like you have one feature and then you're trying to add support for more stuff right so those are those are the points so these are like plug-in

extension points like where you can keep extending systems without modifying your and right now the way how I see code comprehension working at least in the post AI era is paying attention to a boundaries a lot more than how and that and designing them more deliberately than the way how we were designing or using them in the past but the problem is structure itself is quite invisible

right structure is quite invisible and when was the last time someone in this room looked at dependency graphs when was it why was it are you in trouble so people look into dependency graphs or like you know dependency structure matrices only when you are in trouble right like that's the only time you look into dependency graph because dependency graphs themselves are like so complex so dense it

look requires a lot of concentration you just can't skim dependency diagrams and it's also like very difficult to work with so dependency diagrams are like quite hard to work with and like this gentleman over here he's in trouble and that's why he's looking at and like everyone in the room I'm pretty much sure when you're in trouble that's when you go and look at the structure because

like the structure won't let you extend the system, right? Like that Like my mega Okay. And then like then it went to dependency graphs, yeah. So that that's what happens, right? Like UML diagrams and all of the stuff you start working out when you have when you're in trouble. So now uh to be very effective with working with modern code bases and understanding them, this is something

the new abstractions that you probably have to look into and learn, right? I'll do a refresher. This is probably something that is redundant for you at this point, but we'll go through it quickly. Uh so you have two types. So this is also like language agnostic, it's Rust. And uh you have an author, you have book and then you have uh a reference to author from the

book. Then your dependency graph is going to look like this, right? Pretty simple. Repository, again, a bunch of stuff. Then uh this one depends on book repository, author, whatever, whatever, This is your graph. Very simple. Now if you look at this, you have five different concepts that you're looking at, right? Like you have a repository, probably an interface type or whatever. Then there's an error type for

result and then you have a couple of entities or domain objects. Look at this. What does it say? The arrows? You see they're all flowing flowing in one direction? Right? So when people say good design, a good design is where you have small things and all the arrows flow in one direction. That's what good design is. Like if someone tells you what is good design, that's good

design, right? Like everything else is just like nonsense, right? You can still go talk about instability metrics and cyclic dependencies like a bunch of stuff, but then the simplest way to explain good design is build small things and make sure they're moving in one direction, right? The directionality matters your data is flowing in one direction, So, the systems are easy to reason about, right? They're easy to

debug, right? And there's this one caveat here. It is And and and and it's also very interesting in this point because if you traverse the graph from right to left, right is where you'll have your low-level objects objects, right? Like your low-level components. These are small focused components. They just do one thing. And if they if they're named well, you can really understand what they're doing, right?

It's very easy to reason about. And on the right end is where you have your high-level components, right? Like more orchestration, hard to test, like needs mocking and all of that, right? And if you want to understand a system, if you can scope it down to a smaller space, you can always read the graph from right to left because you can build smaller mental models, and then

you can sort of like build the bigger ones, right? So, here you know, okay, there's a author, there's a book. There is a repository, and the repository has error, which means like repository operations can have can fail, right? And at the end you have an implementation detail. Right? So, it's a lot more easier to reason about. But you would also notice that even though we have a

very simple idea here, it's just like you have a repository that can store and like operate with two different entities, like you have to look at this entire thing, right? And dependency graphs become like very very hard to read. Like they're notorious because they are they have so many nodes. They're very very dense. And super hard to like make sense of them. Uh unless you scope scope

them really well. Right? So, let's something about structure. Now, let's let's do one more thing, right? Like now, whatever dependency diagram that you looked at, it was a type level dependency graph, right? Like the previous one was a type level dependency graph. Now, what we're going to do is we're going to sort of do a file level dependency graph. A file level dependency graph is basically you

construct dependency graphs and then like compress them so that they are like restricted to a file. Right? So, whatever you had earlier, you had like a book and an author, but then if you look at the file name, it's called types.rs. And if you're trying to construct a file level dependency graph, it's going to look like this. And if you're going to do a file level dependency

graph for this Right? The complexity is still there. Like the complexity is still there in the implementation details, but then you've just like shifted the zoom level, right? Like instead of doing from the type level, now do you you're doing it at a file level. And now if you're constructing it across two files, because the types file had both author and book, right now, it's just like

false simplification, right? It makes you feel that it's simple, but it's not simple. Like all the complexity is there. It's just that the microscope is focusing at a at a different zoom level. So, we have types.rs. In this case, what if you do this? If you just like split it into two different files, And in any in any language that has a compiler, when you make structural

changes like these, right? You know, extracting things out, breaking them down, putting it in different places, the compiler is your test, right? Like the compiler will fail. Like if you try to extract a function, and if you're not extracted properly, the parameters and the return type, it's going to fail, right? And it's going to happen with uh larger primitive sizes as well, like classes or even modules.

So, you can use your compiler as a test, and just by breaking it down into smaller pieces, now you have a simpler it's the same thing, like we're at different zoom levels, but then we're like sort of looking at the structure, how it looks like, right? So, you have two different structures here. One is a file level dependency graph, which is a lot more simpler. And if

you want to make changes to the policy, you know where to go to. And like if And that's where the details matter, right? Otherwise, it doesn't matter. Even for the agents, the other details don't matter. But for you, someone who's trying to understand a system from a slightly higher level, this gives a lot more sense of like what this piece of system is already doing. Like you

you you've not looked into a any piece of code at all, right? But you can still make sense of the system at Now, I'm not saying like one is better than the other, right? Like each and each of these kinds of visualization has its own purpose. You have to pick and choose what you want to do, right? And for me, when it when when it comes to

looking at boundaries and trying to understand the systems that I'm working with and building or uh maintaining someone else's, this is the default mode that I go to, right? Now, we've just talking about spoke we've spoken about structure, right? Like let's just like go and look at a simple case study because like that was a toy example. I'll show you how uh I use this on an

open-source and made the code base AI native. Like that's the the point of the thing and like the dependency graph was just the basics um so that you can see how uh I use some of these techniques uh to not only verify structure, but also verify um on a on a real-world code base, a few months ago I returned back uh after a couple of months to

work. I was looking at a piece of AI-generated code, right? And um it was a uh it was a code that was trying to migrate data from one database to another, right? It was a mobile application that was trying to migrate data from one to another. And this piece of migration code was written by AI, and I did not understand this entirely, right? I did not know

how it was structured, what it was doing because if it's a data migration code, you don't really want to like sort of the scrutiny has to be higher because you the the schema is different between the databases. Uh so, you have to make sure that you understand before you can actually run this on the database and then make sure and and and and you can ship it,

right? So, what I did was like I was struggling with this and and like I said at the beginning of the talk, I've been building tools for comprehension since 2019. So, there's like a lot of different kinds of tools that I've built. And uh one of my intuition told me that like you know, why don't you try to draw like how these files are just related with

one another? Like, why don't you try to do it? I took a piece of paper and just like did this, right? And after I was like looking at other sections of the code base that was generated by AI, and I started doing it by hand over and over again, right? And I started to see that this exercise was helpful, but then it was also to a point

where I cannot afford to do this with every single file, right? Because you open the IDE, figure out what the like imports look like, how are they connected with one another, and it becomes very, very hard. So, then what I decided to do is I decided to build a library that can tool that can do this for me automatically, right? Uh, so this is what I built.

It's called Clarity. Clarity is a tool that um, it's a tool for both design agents and engineers, right? It allows you to modify structures. It allows you to verify structure, validate structure. It's all the AI native. If you give it to your AI coding agent, your agent will know how to use it, right? So, like everything else is in the documentation. And the case study is basically

about how I used Clarity to build Clarity, and Clarity to make the code base AI native. It's a very recursive loop. And I'll go give you an example on how I was able to achieve verifying both structure and behavior, right? And earlier in the talk we were talking about different boundaries, right? We were talking about external internal, a lot of different boundaries. But with this example, we're

just going to talk about an extension boundary, right? Since Clarity is a tool that generates file level dependency graphs, it also needs to support multiple languages, right? At the point where I was trying to make this change, it had support for two languages. One was Go, the other one was Dart. Dart was the target language that I was working on on a on a project, and Go

was like Clarity itself because I was building Clarity. I was using it to look at the structure of Clarity, right? So, you So, so that's why it supports Dart because Dart was the the project that I was working on, and clarity is written Golang. So, if you look at this thing, what does it show? It shows you your It shows you a dot parser, there is a

go parser, and there is a go simple parser, right? So, there's like a bunch of stuff that is going on here. And for anyone who's looking at the system, if you look at a dependency graph, it's what? A data structure, right? Like the dependency graph is just a data structure, it's nothing else. And for me, if I look at this diagram, I would expect to see something

like this. Like I would just expect to see there's like a bunch of nodes and edges, right? But then, if you look at the diagram, the diagram sounds fishy, right? Why would a dependency graph, which is a data structure, have access to parsers of different languages? That's a design flaw, flaw, right? Like if you if you want to add like more language supports, then I would have

to change make changes to the dependency graph, but dependency graph is just a data structure. Like why would I have to make changes to it? The moment you start visualizing this, you can already spot design problems in this uh solution, right? Like the solution was created by AI, and you can already spot there are problems here, right? Because it's not going to scale. So, what you can

do is like at this point I tried I decided that I need to spend some time on this because this is also the code that I not completely understand. So, I need to understand, okay, like why do I have a relationship from the graph to different language parsers? Like that's a question that I asked the coding agent. And the coding agent can actually look into the code

base and then tell me what was going on, right? And usually when this is happening, one is like there are missing abstractions, right? There are conflated responsibilities, like responsibilities that are part of dependency graphs which should not be there. Um and then there are like types that are undiscovered, right? And for each of these questions that you ask, you can ask the agent to make those changes,

and the agent was able to make this change. Got it? So, none of this was like manual. This is like me interacting with the agent and then asking the agent to generate the new diagram, right? And asking it to extract a type or do a bunch of stuff. And what you want to understand is the shape of how the structure looks like. Right? The structure looks identical.

And now the other thing is like the only thing I have to do is like when I add support for a new language parser like Rust, I just have to replicate the structure. And I can verify that the structure is in place just by re- rendering the diagram. And the next thing is behavior and verification, right? Like just the presence of structure does not guarantee any verification

at all. And when you're going to verify, you also have to be strategic about what you're going to verify here, right? And when you're adding support for a new language, you need two things to verify. One is like does Can it parse the new language? That is one thing like And the other thing that you have to verify is like can it resolve dependencies across files? Right?

These are two things that I want And how do you veri- verify this? Right? Like And even In this case, you look at like the kind of things that I have to do. First, I have to pick a real-world repository. I have to choose what is the suitable Rust repository so that I can test this on real Rust repository because if you are not a Rust developer,

you don't know the language grammar, you don't know how dependencies are resolved like or how dependencies are like resolved by the compiler. You don't have any of that knowledge, right? So, you have to sort of like choose a repository. You also have to select commits like because scoping in Clarity is done by commits working directory directory like a bunch of ways how we do scoping. But the

for the test, like commit level repository changes are fine, right? So, I just have to pick a commit that has like X number of Rust files. I have to see if those are connected in the way that I I expect them to be connected. Right? And then run the Clarity command to generate the dependency graph. And then look at the graph and say, "Okay, like this is

a Rust repository. There is a book and there is a book test. Book changed, but then book test book changed, but I don't see a connection between book test and book, right? Like that's a that's a red flag already, right? Like you'll say like, "Okay, did the person um why why isn't there a connection between the book test and the book?" Like you're expecting that connection to

be there, right? So, that's an anomaly. So, then you visually expect the graph, write a failing test with a sample, and then you fix the bug. Right, like that's that's it. of all of these things, most of them are mechanical. Like, I don't have to find a repository. I don't have to clone a I don't have to select commits. I just have to give criteria on what

commits to be selected. Um I don't have to run the clarity command, right? And then the only thing is I have to look at the graph and tell whether it's right or wrong. And then I have to tell the agent to hey, write a failing test for this use case for Rust. And then once it writes the failing test, then it can run all the tests. Uh

then it builds the binary automatically, and then it changes the diagram. Right, like if everything goes, I just have to make sure all the tests are passing in the bit. Right, like there's nothing else. So, what I did was I created an interactive loop where you just say, "Okay, like these are the criteria, run this criteria." And the agent just like picks 10 different commits, and then

it starts doing this entire thing on its own, right? So, now you as an engineer, you're verifying behavior of the new feature that you extended, but your only job is to provide your judgment because your judgment and attention is the most expensive and the most valuable thing when it comes to humans. Like, everything else is just mechanical work, yeah, here is how it worked. Uh this is

a complete sequence diagram. So, this this is also very uh interesting because we did not have uh uh we we did not have an actual code base as part of our test set, right? You clone an actual code base, but then you only capture failing requirements. So, that requirement becomes part of your test. So, your entire test suite, if you're supporting 15 different languages, you don't have

to clone 15 different different repositories as part of your uh verification uh on the CI. And then what you do is you just say, "Okay, like whatever happened now, convert it into a skill and check it into the repository. Now, it's part of your repository. And and one of the one of the problems is like say for example, the state of the code that I showed you

earlier when I'm trying to add new language support, I would not have accepted PR from anyone else because I know like the code base is not in a state where someone can contribute to it, right? But now that this is converted into a skill, and second thing is we have clearly designed well-designed extension points, even if it is a review, I just have to know if there

is a structure in place. And the second thing is I have to know if the developer actually ran the skill that actually verified the behavior. Right? So, at this point, this code base is ready for code coding AI native agents. And and and after this change, I believe I was able to add support for five different languages at the same time, right? Like that was it my

stress test whether this was able to work, right? And in one of the releases you you should see we added support for like five or six different languages at once, right? As a completely deterministic tool, it does not use any What do you call it? Tokens. It just like parses your code base and then um does stuff. Yeah. And last thing is topology. Um it's basically how

you structure your code bases. Um if you're using multiple agents across multiple code bases, like this is the topology that I would recommend. Uh one is basically you create symlinks. So, you don't want to like duplicate I I use both Claude Codec and CodeX. So, you have symlinks so you have Claude pointing to agents. So, everything is always in sync. Like different agents don't get different contexts

and you are not uh responsible for synchronizing synchronizing different uh agent instruction files. And the other one is what I call signposts. A lot of these coding agents um it's it's very tricky. You cannot reference directories separately. You can only reference files, right? There's no way to reference directories uh by yourself. So, what I do is I generally create a file uh empty a file called dot

project and signpost which just says like look at the agents.empty file or the claude.empty file. That's what it says. But this is just for auto completion, which is not available um in most of the coding agents at least at this point. Like, sometimes it works, sometimes I'm able to choose a directory, sometimes I'm not able to do it. I I don't know. But, uh until then, this

is like the fix that I have for uh using agents across multiple directories. So, there it is. So, we've looked into all uh structure, behavior, verification, topology. Especially when it comes to behavior and verification, I showed you one example of how you delegate most of your mechanical work to agents and also make them reusable, but then you only provide judgment or like whatever you want to And

uh the funny thing is, you can even get yourself out of out of the verification loop if you know how to use language servers, right? Uh that's that's something that um is an interesting thing for you to think about. So, you can like completely have autonomous run when you're extending uh new behavior. Uh that's all there is. Um so, don't think of Steve Yegge's things as levels,

those are operational modes. And uh to get a different operational mode, you have to have funds, and also the state of your code base has to be in a state where you can actually afford to be able to do all of Um and it's a lot more easier if you're like keeping this in mind when you're building new code bases because new code bases are a lot

more easier to shape up than to rescue existing ones. And these are all the four pillars for an additive code base. I am um easy to find on social media. Um legacycode.com, that's my organization. >> [music]