Great International Developer Summit (GIDS)

Architecture as Code - Neal Ford

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

About this talk

This talk introduces the concept of 'architecture as code', a collaboration between the speaker and Mark Richards. They explore the reasons behind the failure of software architecture in various systems, noting common pitfalls that lead to architectural degeneration over time. The speaker emphasizes the importance of expressing architecture in executable code rather than traditional diagrams, aiming to create an architectural definition language (ADL). This language allows for better feedback loops to ensure alignment between architecture and the development process. Furthermore, the importance of building deterministic structures and guardrails around AI-generated code is discussed, highlighting the need for new practices in a world where generative AI assists in code generation. The session concludes with an outline of the intersections between architecture and various aspects of software development, including implementation, data management, and team dynamics.

Full transcript

For this session, I want to talk about the book that I'm currently working on with Mark Richards called architecture as code. This is actually a problem that Mark and I have been thinking about for several years about fundamentally why doesn't architecture work in software systems? We started thinking about this actually before not before GenAI, but before agentic development and we've incorporated that as you'll see into this

material, but it's really this fundamental question of why doesn't architecture work either it collapses for some reason or we didn't account for some sort of boundary condition or maybe it's just mixed division where different teams got together and put a building together. While this looks AI-generated, it's not. It's a real building. It is a museum in Toronto, Canada in North America. It's an art museum and it

is supposed to look like that. But I've seen a lot of software projects that sort of accidentally look like that because one vision versus another vision collided and they couldn't get things together. But even in really well-functioning software projects with good software architecture, you can start out with something that's pretty nice, but then gradually over time it turns into a dumpster fire. And we want to know

why dumpster fires happen so often in software systems when we know architects are pretty effort into designing things so that it doesn't turn out like this and yet it still manages to turn out like this in too many cases. And this of course is aggravated significantly if you have little agentic arsons running around your project setting fires and creating a havoc for you, it gets even worse.

Mostly the problem is that we've been expressing our ideas in architecture as diagrams when what we'd really like to do is be able to express those things as code. But what does it really mean to have architecture as code? When we first came up with that the name of this idea, I told Mark, "That doesn't seem to make any sense. It's like saying pasta as spaghetti or

spaghetti as pasta because they're they're they're made of the same thing. As architecture is made up of code, but the way we express it typically is not in code. It's in diagrams or architecture decision records or other non-executable things. And so that's what Mark and I set out to do is to can we describe all the ways that software architecture intersects with all these different parts of

the software development ecosystem? And that's this idea of architecture as code, these nine different intersections. And now the question becomes, well, we want to describe these intersections, it doesn't seem that useful to spend 10,000 20,000 words of prose describing how teams and software architecture fit when there's no action you can take from that. What we want is code that you can execute to see how well your

architecture and your team is aligned with each other. And that's exactly this idea of using a language to describe these intersections that is in fact executable so that you can get feedback for how well is my architecture working? one of the first times I'll say that today, but not the last time that this architectures code stuff we're talking about is not a testing framework. It's a feedback

framework. The real essence of agility is not lack of planning. Because for sophisticated things, you still need to do planning. The essence of agility and architecture in particular is how can I wire in fast feedback to make sure that what I think we're building we are in fact building. And that's what we find is missing throughout the software development ecosystem for architects are good feedback loops to

say is this place where my architecture is intersecting with part of my ecosystem, is that actually working? This of course is in a long series of things as code, infrastructure as code, and policy as code, configuration as code, security as code. for all of these, basically what you had to wait for is the ecosystem sophistication to reach a level where you can start expressing these things as

code. I remember before infrastructure code existed, people wanted it for a long time. We had virtual machines, but we didn't have a way that you could spin it up purely from code, and tool tools like Puppet and Chef came along, and of course that led to containerization and a whole bunch of other beneficial things. And that's exactly the same thing as true of architectures code. We sort

of been waiting for the ecosystem to give us the proper tools and isolation to be able to do architectures So, let's talk about what this means. When you look at a building plan, there are reasons an architect a building architect put those things together in that way. So, what if somebody comes along and says, "Can we move this bathroom to the other side of the floor plan

here?" Can we? Well, sure yeah, we can, of course, but there's a reason the bathroom is where it is, right next to the kitchen, because plumbing is expensive. If I move it to the other side, I can do it, but it's way more expensive than we than we would have before. Uh what about walls? Can I get rid of this wall? Well, some you can, some you

can't. Load-bearing walls, these are the kind of questions you ask about buildings. We can ask the same kind of questions about software architecture in terms of components, because components have responsibilities, they have dependencies on one another, and so we can ask questions like, "Is it okay for order placement to communicate directly with payment processing?" Maybe it is, but maybe we don't want them to communicate for some

very good reason. This is the kind of thing we can express in code, just like an architect can express those things in building plans. We can assert here between two components, "I do not want dependencies between these two comp- two components." Or if those are services, uh services in something like a microservices architecture." This is this ability to express architectural ideas in code that we can uh

actually execute. I'm not sure I've seen that. It's got in here twice somehow. Shh. So, when you take definition in architecture as code, this is a little language we've created called an architecture definition language, which is meant to be a very, very, very lightweight pseudo code. It has no grammar, there's no compiler for it or anything like that. It's meant to be as bendable and as flexible

as possible. There are some other languages out there, calm, which I'll talk about, which has a formal language back, it's expressed in JSON, etc. But we are just trying to express our intent in as few words as possible in pseudo code. And this is something that would end up in an architecture decision record somewhere, for example, as a way of defining what I want to have in

my architecture. So this may be a section of something like an ADR. But it's also a fantastic communication medium with some other parts of that intersection. For example, for infrastructure, as an architect, when I decide how scalable my system is going to be, I'm going to write up a long architecture decision record that explains my rationale and the conditions that led up to it and the possible

consequences, But if I hand that ADR over to operations, they don't care about all those details, they just want to know the facts. And this is a great communication medium for other parts of your ecosystem because that has just the facts in it, no extra details that they don't care about. And so it's a very clean way to express these ideas to other humans and it turns

out to agents as well. And one of the arguments I'm going to make here very shortly, as we talk about is that we're going to want to express our architecture goals in two different formats. One of those formats is going to be in our architecture decision language, which is pseudo code, and we're going to wire that directly into agents to constrain their agentic code generation. We need

to be able to do that to have them produce proper code. For example, I want you to build just these components and no other components. I can wire that into the ADL, but I also need, because LLMs and agentic coding is fundamentally non-deterministic. It's a feature, not a bug, that it's non-deterministic, but it is fundamentally non-deterministic. We need deterministic wrappers to make sure that it's doing the

right thing. You we always want deterministic wrappers around non-deterministic things, and that's where we can also utilize GenAI as an interpolator. It's not an interpreter, it's not a compiler, it's not a transpiler, it's not a cross-compiler. It's an interpolator. I I credit my former colleague Birgitta Böckeler for this distinction, because when you hand our architecture definition language, you can take that and hand it to an LLM

and tell it produce concrete code for me in one of these very specific platforms. Our intent in our architecture definition language is to create something that is platform and technology agnostic. But to build a concrete guardrail, it needs to be platform and technology specific. And so, creating it as a general rule like that, and then converting it into concrete fitness functions, works very nicely in a in

surprising number of ways. This is leveraging that second L of the LLM, its ability to translate from one language into another, all of these things are just different languages to translate that intent into. And so, our ADL for that kind of dependency becomes this concrete fitness function in uh the .NET world. That's using GenAI as an interpolator. Now, when you do this, you still have to check

what it produces. Because it could hallucinate and create something crazy. So, you still need to understand this code and be able to check it yourself. And in fact, uh if you generate it five times, it may produce really good code, and the sixth time, it may hallucinate and create something crazy. So, there's always that non-determinism in there, but this is a way to express the same intent

in both formats, both in a deterministic verifying way and in a way to guide the LLM. So, let's talk about that and know that these intersections. So, the intersections that I will touch on briefly in this talk, implementation, we'll see a couple more examples of that, engineering practices, team topologies, integration, enterprise generative AI, which I'll start with, infrastructure, data, and finally, uh the business itself. Let's talk

a little bit about some of the things I was alluding to here, an architecture and agentic AI. We've seen this evolution recently from prompt to context engineering. And the two things that we really care a lot about as we've evolved toward context engineering are these two things, system architecture and data flow, and ensuring consistency and eliminating hallucinations. That's part of these deterministic guardrails handles the second half

of this. and we'll talk about the mechanisms to handle the the first half of this in just a second. What we are seeing with, particularly for agentic code generation over the last year or so, is just an evolution of the level of abstractions that we deal with. I grew up in my first book was actually a book on this platform called Delphi. Uh and it was a

based on object Pascal, which was a non-memory garbage-collected language. So, you had to understand memory management to be able to code in Delphi. Uh I've also coded in C and C++ and a bunch of other older languages where you had to understand the implications of memory management. But then tools like Java came along and platforms like .NET came along and suddenly memory management was something I never

had to worry about as a developer anymore. There are special exotic cases where you really have to know how it works, but for the most part, this just magically happens behind the scenes. And this happens over and over to us. When I first started coding, one of the first questions you had to ask yourself for every system was what kind of network are we using? Is it

IPX/SPX? Is it NetBIOS? Or is it TCP/IP? Cuz all three of them were fundamentally incompatible with each other and none of them could easily talk to one another. It was a big deal which network to use. And then TCP/IP won and that just did not become a question anymore because that whole abstraction just melted away and now it's just the internet. It's just the network. This happens

to us over and over again in the software development world. These abstractions come along and eat things that we used to have to care a lot about. I'm as an architect, I've had to built a lot of scalable systems using physical machinery, but now you can build scalable systems on the cloud just with some configuration settings. So, yet another level of abstraction that's just sort of disappeared

for us. And that's sort of what's happening now with agentic code generation in that the literal creation of the code itself has been abstracted away from us. But in a fundamentally different way than all of these other abstraction layers have come about. Cuz these are in fact abstractions which sometimes leak, which means they're not perfect, but they're always deterministic. When agents produce code, there's a level of

non-determinism there that we've never seen before as we've seen these evolutions of abstraction go along uh through our ecosystem. And that's the thing I think we're going to have to worry about a lot. Next is adding determinism into something that is When we talk about structural design in software architecture, we talk about this split between capabilities versus behavior. Behavior is your problem domain. It's the reason you're

writing a piece of software. I have a problem. I'm going to write some software to solve it. Behavior is what you're attacking there. But capabilities is what you call non-functional requirements or architecture characteristics. Those are all the ilities of your software. You have to worry about those capabilities as well when you start thinking about We have ways to build protections around behavior with unit tests, functional tests,

acceptance tests, etc. And we capabilities with architectural fitness functions. And congratulations, this is your new job Your new job because of the change of the level of abstraction is not to write the code inside that behavior box anymore. It is to supervise the creation of that code, but then to build deterministic guardrails around it so that you know it was produced correctly the first time, but maybe

more importantly that it continues to be produced correctly when you need to iterate on that code. Cuz anytime you let an agent change it, it might start hallucinating and do something wildly non-deterministic, and you have to watch out for that. This is what I was alluding to earlier that there really two phases of verification that you need now. One that is wired into the agent, either into

something like skills and clawed code, or at a root level context and a tool where the root level has higher priority of the things below it in that hierarchical context, but we need the ability to wire these foundational rules into our LLMs. The reason we need to do this, I mentioned this in the keynote, but it's worth bringing up here in case you didn't see that, because

this to me is one of the key things to understand about where we currently are in terms of LLM capabilities as compared to, for example, human developers. This is the Dreyfus model of knowledge acquisition, which was created for the nursing profession in the US back in the 20th century, and it basically defines five levels that people go through as they're learning some brand new thing that they've

never seen before. This includes nursing and programming, but also things like airline pilots. They've identified these for airline pilots. So, beginner or novice doesn't really understand how things work, but they can follow simple recipes, and so you can give them recipes and they can crank through recipes, but if one of them breaks, they don't know how to fix it. Advanced beginners have done a number dozens or

hundreds of recipes, and they have a limited ability to improvise. If something breaks, they can take some steps from an an other recipe and apply it and and sort of get it to work by hacking it a little bit. Competent understands how things work at least one abstraction level below the abstraction level you're working in and understands why things break when they break. Proficient understands everything top

to bottom, how they work, and probably builds recipes for beginners, advanced beginners, and experts are have been doing it so long they don't they can't even explain it anymore of how they make decisions because it's just basically muscle memory at this point. The reason I love this scale is because fundamentally the way LLMs work is they are perpetually advanced beginners. They are very, very good at finding

recipes to solve problems, but not reasoning through problems. The current research paper that just came out two weeks ago, you can fool virtually every LLM out there now with a word problem that says Bob picks up 12 mangoes, Suzy picks up five mangoes, three of them were smaller than the others, how many mangoes do they collectively have? All the LLMs see smaller and they subtract numbers even

though that's irrelevant to the actual word problem because they're not reasoning through it, they're pattern matching. That's what they are is really, really good pattern matches, and they're getting better and better all the time at finding recipes to apply to problems. And what's happening now are the companies are trying to wire in other aspects of AI, reasoning models and machine learning and neural networks, etc. to try

to get over this this barrier right here, but this barrier is going to be here for a while. But the reason this is important cuz I'm maintaining that your new job is to build guardrails to prevent LLMs from doing stuff that they shouldn't do. But the kind of guardrails that you build for humans, you have to be a lot more explicit for agents. And here's an example.

Let's say that you put some constraints on some agents that say, "I want you to generate code, must be within these components, must have a certain level of code quality, must have these kind of dependencies, and it must pass all these tests. Go." Well, it tries, and it can't get the Every time it tries to generate these components, the methods inside are so large that the code

complexity is too high, and so it tries again. And it tries again. One of the recipes it will eventually is one of the ways to make a unit test that's failing pass is just to replace the assertion with assert true, and it'll pass. Hey, we got the test to pass, let's move on to the next task. Humans won't do that, but that is a legitimate recipe for

making a unit test pass, and an LLM will eventually pick up if you stress them enough and put them under enough constraint. Those are the kinds of things that we have to look for is this sort of sneaky naive behavior by LLMs that don't know that it's wrong to do that because they don't understand right and wrong, they just understand recipes. So, this is part of the

reason why we are big advocates of this architecture definition language as pseudo code because what we want particularly within the context window for agents, which is a limited resource we want to be able to wire in these foundational rules in as little space as We really like pseudo code for that because it gives the LLM the least opportunities to hallucinate because you have the least number of

extra words in there, and it also takes up the least amount of a context window. So, when you look at things like system architecture and data flow from you define capabilities as foundational constraints for agents either wired in as skills or to root level context, build fitness functions for structure and governance and constraints, concrete fitness functions that run as part of continuous integration or deployment pipeline. This

gives you objective definitions for those important capabilities. This is the way that you explain these foundational architecture concepts in an unambiguous way. And the rest of this talk is going to be examples of what what that looks like. It uses the least context possible, so doesn't eat up attention span and it ensures uh quality guardrails. In terms of ensuring consistency and consistency comes from having objective definitions

for things and the ability to be able to test to see are those things true or not. So, using deterministic guardrails for non-deterministic code and non-deterministic code generation uh and as I mentioned before architecture as code as a testing is not framework. How can I get fast feedback on uh things that are happening in my The other interesting question that is seems to be churning around like

crazy in the uh the blogosphere now with agentic AI is what should the regeneration scope for agents be? So, okay, I'm going to let agents build code for me. How much? Should it be a single function or a component or a service or a system or several systems talking to one another? And the consensus seems to be that microservice is the right level for agentic code generation.

Uh I think because the micro term sounds small and that sounds appealing and so let's just say it's microservices. So, if we want to build deterministic guardrails, we can do domain level testing for behavior. But for capabilities we argue that the proper scope of agentic regeneration is this concept that we defined almost a decade ago called an architectural quantum. Uh an architectural quantum basically defines the desirable

characteristics of microservices, but it also applies to a lot of other things in software architecture. It is the the scope for a set of capabilities or architecture characteristics. This is why it's the perfect scope for agentic regeneration because when you regenerate code, you need to regenerate both the and the capabilities that behavior needs to exist within. What is the scope of those capabilities? It is this quantum

concept. And so this quantum idea gives you the right kind of encapsulation because it includes behavior and exactly the capabilities that this set of behaviors need. But this quantum idea also defines a lot of other useful things including how microservices can couple to other microservices within a distributed architecture. And this is what I was mini ranting about in my keynote yesterday when these new bubbles come along,

people act as if everything we've ever learned about software has been thrown out the window and we have to start over from scratch. And this is just not true. We've analyzed distributed architectures for many years now and understand exactly what it takes to make them operate and the things you have to watch out for. So, if you're going to use agents for your scope of code generation,

then you not only need to worry about the scope for its architecture characteristics, but you also need to deal with and constrain five different types of coupling. And these are the five. I'll give you brief examples of these. Static coupling is the dependencies, how things are wired together. And so, if two microservices share a component, they are statically coupled one another because if I change that shared

component, both of those microservices must change. Notice that if I'm just having agents build microservices for me, one of the strategies they will come up with at some point is to share this component because they need to pass information back and forth, but now I've created a static coupling point between those two microservices, which if I were building this as a human, I would not want to

have because now I'm violating one of the philosophies in microservices. Uh the other static uh coupling that is common in this world is the coupling between the code and the data in microservices because of data fidelity. There are a bunch of different fitness framework libraries to to check this. That's where all those tools come from. ArchUnit, NetArchTest, etc. Calm, I alluded to this earlier. Calm is another

language that describes architecture. This is created by the financial services industry. It's an open source open specification. They are defining in JSON a consistent way to address resources in the distributed architecture. And so that's under active development. That's another way of defining static dependencies in an architecture like this. Dynamic coupling has to do with how services call one another. So if your services end up calling one

another to do a workflow work and those calls are synchronous, it has negative impacts on things like responsiveness and scalability and elasticity. So you need to constrain your agents if they're communicating building code that communicates between services, you need to be asynchronous or build protections around synchronous communication. And for that kind of fitness functions, you need monitors or other things that can analyze runtime behavior. You can

also do forensic logging to learn about who's talking to what. Temporal coupling is really about startup dependencies and so this one's a fairly rare one. But this is if I'm filling up a cache for example on startup. So it is a static and dynamic dependency, but it's very short-lived because as soon as it starts up, it's finished. Contract coupling is a form of static coupling because if

two services pass information in a contract, they are now via that contract or maybe if that contract is a has metadata in it that ties them together. That's something else you have to watch out if you build if agents build services that pass information to other agents, you have to worry about what's in the contracts because you can inadvertently create high coupling when you do that. There

are a bunch of different ways to validate this. Consumer-driven contracts is the common way to do this in microservices, so you'd put consumer-driven contracts into your agentic code generation to make sure that it preserves the contracts between your communication. But then finally, the worst kind of is transactionality. And this is the mistake I see everybody making when they think, "Oh, well, I'll just have agents build these

little Lego microservices for me, and then to build real business systems, I'll just sort of glue all the Legos together and get them to do work." That is ignoring the ugly, awful realities of cross-service transactionality in microservices, which is possible but difficult and takes a lot of planning, and you can't just sort of vibe code that into existence. So, this goes back to what I was saying

before that we have good analytical tools to analyze things in software architecture whether they're built by humans or agents. Um, and we should utilize those things. And that's this idea of building guardrails. Let's talk about looking at what some of those guardrails would look And here's in the implementation world, I want to define domains within my ecosystem, and within those domains, I want to define components, and

then say assert that classes are only contained within components. Now, we originally designed this for humans, and this may seem overly pedantic for if you think of this as a testing But it's not a testing framework. It's a As the architect, I'm responsible for components and dependencies between components, and I don't want to create a bunch of dependency nightmares that's going to be hard to build future

code upon. Now, if somebody builds a new component in this ecosystem and it violates this rule that I've created here, that's not necessarily an error. It's a feedback opportunity. Oh, somebody created a new component here. Why? Is there a good reason for a new component there? Did I miss something? Or is there not a good reason for it and it might cause a problem? The point is

I want to know as soon as that new rogue component shows up, not 6 months later when I accidentally run across it. By creating an assertion like this, you guarantee that all the code that is created is created within the same component structure. And of course, this is even more important if you're letting agents do this because you need to constrain them because they will create balls

of mud if they're not constrained to do so. And of course, in the Java ecosystem in particular, what you're really doing here is creating directory structures and dependencies between things. And so, that's exactly what that ends up doing. We take that ADL and it's wired into the agent, but we can also take that same ADL and produce this code in the and wire this into continuous integration

to make sure that the LLM and I'm you've all had experience with this when you use one of these things, it sometimes just lies to you. Oh, yeah. We run all the tests. Everything is great. Okay, show me the outcome of those tests. Oh, you wanted to see the outcome of those tests. Let me run those tests for you and we'll see what the outcome is. It's

like, yo, so you were just lying to me before and so you got to you got to trust but verify for these things. Same is true of coupling. Not just the components themselves, but how dependencies exist between components. Because I don't want LLMs to create a bunch of coupling mess for me. And so I'm going to create some assertions here that say that there are no dependencies

on some of these components and allow dependencies on other ones. And of course, all that is is producing dependencies within my code structure. When I pass this to an LLM, it analyzes it, it figures it out, and they're in fact concrete fitness functions that I can wire into a continuous build that say these are the dependencies that should exist in my ecosystem. Again, we wire this into

the agentic code generation and it may iterate a few times before it can produce code that matches this, but then we also want to verify it as a concrete fitness function. You can also build constraints into an architecture like this, and the only one I'm going to show here is this database And this actually shows one of the advantages of using uh the ADL to state intent.

Cuz we're going to define these layers in this layered architecture, but then I'm going to say persistence layer is the only layer that contains database logic. Now, on our first iterations of using ADL to produce fitness functions, we were very specific here, but we realized there's actually a benefit to being more vague. Just stating your intent here, because when we produce this code in ArchUnit, it's smart

enough to pick up all the things in the Java world that let you connect to a database, all the concrete classes in the Java world that let you do that. When you generate the same code in the .NET world, it picks up the .NET interfaces that control data access. This is another benefit of this platform and technology agnostic ADL. Many architects supervise more than one platform or

technology stack. You have Java, you have .NET, you have TypeScript, JavaScript, you have Python, etc. ADL is platform and language agnostic and you can create concrete fitness functions in uh each of those platforms or tech stacks. What about engineering practices? I talked a little bit in my keynote about some code quality metrics. I'm going to talk about something else here. This is one of our little sample

projects that we have where we're using in our book called Monitor Me. It's a microservices system that's medical monitoring devices. Each of these things is completely independent of one another except uh the sleep status, which relies on heart rate and respiration, but all the others are completely independent and decoupled from one another. So, one of the inevitable things that comes up as an are decisions where both

options suck. But, they suck in different ways. And here's a classic example of that. Mono repo versus repo per service. Which is the correct answer? There is no correct answer because they both suck. They both have significant downsides, you got to choose one or the other. This happens to you all the time as an architect where you have to make a decision where you know there are

some bad things, bad trade-offs that go along with that decision, but we have to make a decision. None of them are perfect, and so you have to choose one or the other. This is a great example of an engineering practice that may in fact have an impact on your So, let's say that you've chosen a mono repo for good reasons. What's the thing that you have to

worry about in a mono repo? Cheating on dependencies. I'm trying to build microservices here, but I'm putting them in one repo, and it's an awfully big temptation to say, "Well, I really need this functionality, and it already exists in this other place, so I'll just do a little import, voilà, I have it." One of the projects I was working on recently was a small, agentically created system

that produced a very specific kind of medical form. It was actually a small little vertical market app, and for simplicity's sake, that several different collaborating agents that produced code for this thing, and for simplicity's sake, they were using a single repository to keep the code in, but the architect who was working on it said, "I really want to keep this as a single repo, but I want

to keep all the code decoupled, and the agents keep wanting to cheat on my runner repo. How can I prevent it from doing that?" Here's how you prevent it from doing We have to put on our architect's lenses and look at this. What does cheating in a mono repo really mean? It means importing something that you shouldn't be able to import. And so, if I define rules

in my architecture that say what you are allowed to import and what you're not allowed to import, then that keeps you from cheating on the mono repo. So, here it is for monitor me. Notice assert that sleep depends on heart rate of respiration has no dependency on anything else. The rest of them have no dependencies. And now I can generate code that in fact in the Java

world verifies that I have not accidentally imported something in a dependency that I should not have in my That's the code in the Java world. There's the same code in the .NET world. I think I've got it. The In our book we've got it in Python Classic example of how an engineering practice choice like a mono repo versus repo per service can have an interesting side effect.

And in our book we also show if you chose a repo per service, how do you make sure that you're not copy and pasting too much between the between the repos? Uh that's another thing that you can validate from an engineering practice standpoint. Let's talk next about data. The architects have decided to split the database into two domain databases for better fault tolerance, change control, and scalability.

Okay, but let's make sure we don't lose any trouble tickets and both domains have the same information. This is typically documented in a requirements or spreadsheet or something like that somewhere. But of course, we want to be able to document that in something like an ADR, but then also something executable like our ADL code. Tickets must be consistent between domains. Now, this is not one that we

can just hand to a uh a generative AI and say, "Build me a fitness function for this cuz there aren't any fitness functions for this. This is a runtime verification. This is not a static test of some kind." And so, we're going to have to produce some sort of code to do this, uh, some sort of custom, uh, architectural fitness function to do this. And here's sort

of what it would look like. So, I have this customer scope over here. I have the ticket scope over there. They each have separate databases. I can build a fitness function that runs as part of the service mesh that's running the monitoring and logging and naming service and all those sort of utilitarian things within my take a hash of all the ticket keys in the customer database,

the number of tickets on the queue, and then a hash of ticket keys over in the ticket database, and write a fitness function in the service mesh that says, "Every time the queue depth drops to zero, assert that those two hashes are equal to one another." I'm now validating data consistency between two domain databases within a if you're having agents build the code for the ticket processing

quantum and the customer quantum, you're going to want to know and verify that in fact data consistency was preserved every time you make a change to either one of those bits of code cuz it could be changing schemas, it could be changing code, et cetera. And so, this is that validation that even if I'm regenerating that code, this important capability in my architecture, data consistency, is in

fact preserved through uh this check. So, this works with agents build your code uh same as humans. So, okay, implementation data engineering practices, those are all seem like pretty measurable things, but what about teams and architecture? So, this is Team Topologies, a very influential book that defined these different kinds of teams. Streamline teams are trying to create features, enabling teams are working on um knowledge transfer and

uh uh things that are coming up that streamline team will need. Complicated subsystem teams handle specialization, and then platform teams handle things like um building platforms other sorts of validations. What you really care about from an architecture standpoint in your streamline teams is are they moving as quickly as possible because that's the goal of our streamline teams. And so, if you look at for example, monitor me,

each monitor is implemented by the team with a one-to-one mapping to services, and the enabling team is created is doing sensor feed research and development to see if new sensors need to be added to the mix here. So, how can we make sure that enabling teams aren't disrupting the stream teams? This is a good example of something that is in fact measurable, but you don't even may

not think of it as being one of the mantras that we talk about in our book everywhere is what data do I need, and where does it live? The data that I need here how often is the enabling team generating a merge for the stream aligned team? Well, I could validate that. This is an example of a GitHub action that logs merges between team A and B

if team A is the stream aligned team and team B is the enabling team. Now, I can quantify how often one team is merging into the other team and see how much potential disruption is happening between those teams. This is particularly true if you have a team that is some mix of humans and Again, quantifying what humans are doing seems a little bit overly controlling maybe from

an architecture standpoint, although mostly we're interested in this from a feedback standpoint, but when you start mixing humans and agents, you're going to want to start quantifying who's responsible for what, what backlogs are being created by one versus the other, and so these are ways to quantify that relationship between the architecture you're building and the entities that are building it either agents or humans. Let's talk a

second about integration and integration implications in architecture. And this goes back to that quantum concept that I was talking about before, the static coupling aspect of that quantum that I was talking about before, in fact, in integration architecture. How do I manage event brokers and how can I partition them for maximum reliability? Well, here's the scenario. I had this purchase book workflow where you place an order,

order placement generates a message which is picked up by payment, inventory, and notification. Uh payment picks up order fulfillment picks up payment and so this is sort of flowing through my architecture placing the orders for book. But as I mentioned before, one of the things that we look at when we analyze architectures like this as the static coupling for the architecture quantum. And the question we can

ask is how many quanta are represented by this picture if you think for a static coupling standpoint? Another way to ask that is how are these things talking to one another? They're talking to each other through a single broker. And the rule of thumb in architectures like this say that the topic or queue is typically owned by the sender, that is an architecture quantum, which means that

from an architecture quantum analysis standpoint, this is a single architecture quantum. Part of what this quantum thing analyzes is coupling and if that broker is down, nothing works in this architecture. So part of the reason for building a distributed architecture to get better availability and fault tolerance and yet I have zero availability and fault tolerance if that broker is down because I have a single architectural quantum.

This is the domain broker pattern that says by taking that quantum idea into account, let's build a broker Order placement and payment are sort of customer facing, we'll build a a broker for them. Uh inventory and warehouse is back office kind of stuff, build a domain for them, that's all the fulfillment and shipping and then notification is sort of plumbing and so now I've distributed my fragility

in my architecture across these domains so that if for example, order fulfillment, if that entire chunk of my architecture is down, I can still take orders, I can still update my inventory, my warehouse, etc. And so, this goes back to what I was talking about before. When you're thinking about architecture, you can't just think about the individual behavior inside these boxes. You have to think about how

they're coupled to other parts of your architecture and what implications that coupling has to other parts of your um particularly if you're doing any kind of code generation. Now, this is not a pure purely beneficial thing. There are trade-offs for doing this. The good side of this pattern is it preserves the quantum and it gives you better reliability because it distributes reliability across the distributed architecture. But,

if you're using commercial brokers, then it's going to add additional cost here and added complexity because now brokers are talking to one another, uh which can uh make things more confusing. But, now you can ask the question, who is my broker? What data do I need and where does it live? So, you can build a fitness function for this that says a container-level fitness function that abjures

observability for every one of these event processors and a service mesh that runs a regular check on communication extent. And when you find that you are extending that communication extent too far, start uh warning about this from a uh a fitness function standpoint. So, this is something that is uh validatable as well uh through fitness functions. The enterprise already has a role called enterprise architects that control

this intersection. In fact, there's a whole lot of aspects of the role of enterprise architect that applies here. But, I want to talk about one specific thing, which is around governance strategies and enterprise architecture. There are several of these. Governance strategies, of course, mandate and dictate the tools and platforms, technology choices, methodologies we use in the organization, processes, etc. And there are four common ones, two of

which I'm not going to bother talking about. Centralized and decentralized are the two categories. Prescriptive and classical alternatives, which are very old school. Mostly what we're seeing now and we'll see in the future are the decentralized ones, either distributed or durable interface. I want to talk about those two briefly. Let's talk about the decentralized model. Uh decisions or standards are delegated to individual business units with minimal

shared enterprise standards. And so the idea of the distributed standard is you have some core enterprise level standards that are mandated by enterprise architecture, some common ones that are crossed probably a domain, and then individual business units can have their own distinct standards for things within your ecosystem. And so here, you've got a a governing body, but they're only choosing alternatives. And now the standards can be

chosen They're they're only choosing things that need to be universally true, like logging and monitoring and things like that. And individual teams can pick the things that they want. The advantage of doing this is that you get the right tools for the job and business units feel like they have a lot of control. This is a lot more expensive, though, because now you're letting teams build the

things that they want and you may have duplication in But it's also easy to build fitness functions for this kind of behavior because you either have two patterns here that side car is a shared responsibility, or it's the ownership by from the infrastructure team, but easy to validate in either case. And in fact, typically what you see in these kind of ecosystems is that enterprise architecture owns

the core standards, teams own the common shared standards and solutions own the individual business unit standards. This is really common in the microservices world, but what we're seeing a move toward now is this durable interface strategy, which basically says, "I don't care what's behind your API. I literally don't care as long as your API is stable." This is sort of defensive against a genetically coded subsystems in

your ecosystem where there basically are no standards. All we are standardized on is how these things communicate with each As we see more and more agentic kind of code generation, we're going to see more and more of this. I don't really care what's in that business unit. I just care about what I can send to it and what I can get back. So, this mimics what ships

used to do before radios where they had flags. And so, this is the durable interface strategy. The downside of this, of course, is you get a lot of variability and duplication and cost in your organization, but if you have agents building stuff for you as quickly as possible, maybe that's not a bad thing at all. Uh you will need fitness functions around metadata that for the API

calls and consumer driven contracts to validate all these things, but this seems like the way that we will probably end up going for a lot of the agentic code from an enterprise architecture standpoint, hm is that me? Am I uh feeding back? From an enterprise architecture standpoint, I want to talk about one more thing, MCP. James is actually doing a talk or two here about MCP. MCP,

of course, is the integration glue between parts of your ecosystem. But this is hugely advantageous for enterprise architects as well. Cuz remember this validation data consistency code I was showing you I would really like to drive that from the enterprise architecture level, but I don't want to break that governance context. There's a lot of details I have to know to be able to write that fitness function,

and as an enterprise architect, I don't want to have to pierce that governance context and know what those details are because that creates a very brittle kind of fitness function. And that's where things like MCP come in. If you create an MCP server at the project level, it can expose tools to the enterprise architects like validate referential integrity, and it knows the details of how to do

that internally within that project scope. And now an it an agent could also call validate referential integrity as well at that project scope. And now inevitably when that changes and we add another database and need to evaluate referential integrity across all of them, I change it inside that governance context, but nothing else has to change. This is a great boon for roles like enterprise architecture and also

for things like software bill of materials. Cuz one of the things that we care a lot about now are dependencies and hallucinated dependencies. Now we can start providing software bill of materials as a data source or tool that you can call from an enterprise architecture standpoint and validate that you are in fact getting the stuff uh that you should have within your uh All right. So, let's

summarize all of this stuff. This is really an example of moving from qualitative analysis toward quantitative analysis. I showed you a bunch of examples yesterday of those star chart rating qualitative analysis, but this is actually making it executable by turning it into actual As I mentioned before, the real secret of agility and architecture is about building fast feedback, and that's what this architecture as code business is

about is building really fast feedback loops. So, lessons learned here don't use implementation details as a basis for fitness functions. Don't pierce things like bounded context. Don't be over-reliant on tools and frameworks. A lot of times you can build your own, but they're much simpler than you tend to think they are. Just because you have governance doesn't mean that bad intent won't break things, and so be

sure to uh understand um no amount of governance will stop bad actors from acting bad. So, the whole purpose of this is really fast feedback at the architectural level. It's not a testing framework. It's a feedback framework. And in fact, it's not meant to be completely comprehensive. So, if you look at pre-agile engineering and domain level testing, it was ad-hoc and arbitrary. And one of the ways

that we fixed that is by making it robust and If you look at domain level testing now, it's very good. But if you look at architectural testing for capabilities, it's sort of ad-hoc and spotty. We do not want this. Because it's too fragile and it breaks too much. What we want are protections around the load-bearing parts of our architecture. I want to know when important things change.

Mitigate inevitable negative feedbacks. Just the facts medium for conversations. And encourages think of architects of the world as a fully automatable code. That's it. Thanks very much for coming and hope you enjoyed it. >> [music] >> Mhm.