<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Luca Mezzalira on Medium]]></title>
        <description><![CDATA[Stories by Luca Mezzalira on Medium]]></description>
        <link>https://medium.com/@lucamezzalira?source=rss-9119c54d607d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*JSn8jZbjnBNJptxWzhCe5w.jpeg</url>
            <title>Stories by Luca Mezzalira on Medium</title>
            <link>https://medium.com/@lucamezzalira?source=rss-9119c54d607d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 01:11:19 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@lucamezzalira/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[The prototype is the easy part]]></title>
            <link>https://lucamezzalira.medium.com/the-prototype-is-the-easy-part-b211f77d96e6?source=rss-9119c54d607d------2</link>
            <guid isPermaLink="false">https://medium.com/p/b211f77d96e6</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Luca Mezzalira]]></dc:creator>
            <pubDate>Fri, 24 Jul 2026 13:10:16 GMT</pubDate>
            <atom:updated>2026-07-24T13:10:16.990Z</atom:updated>
            <content:encoded><![CDATA[<p>A few weeks ago I packed a camera bag and went to <a href="https://www.ag-grid.com/community/beyond-the-prompt/">Beyond the Prompt</a>, a conference AG Grid put together in London. I went with a question I couldn’t shake: everyone is using AI to write software right now, so <strong>why does it feel like nobody actually agrees on how.</strong></p><p>So I started asking in the hallways between talks, in the alley outside where people go to get air and say the things they wouldn’t say on stage, and later in my own studio, sitting with the ideas that needed more room than a corridor conversation gives you.<br>I discovered two main categories of people: <br>- Some of the people I talked to are shipping most of their codebase through agents already. <br>- Others are still deciding whether to let AI anywhere near anything that matters.</p><blockquote><strong>I don’t think either camp is wrong.</strong> I think we’re all junior at this, still, no matter how senior we were the day before ChatGPT showed up. The practices are being written as we use them.</blockquote><p>Three things came out of those conversations that I haven’t stopped thinking about since.</p><p>the whole thing, unedited, is here:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FV-SUeX9xBPM%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DV-SUeX9xBPM&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FV-SUeX9xBPM%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/e584a09514096e99df067d6d6ba4082e/href">https://medium.com/media/e584a09514096e99df067d6d6ba4082e/href</a></iframe><h3>The job didn’t disappear, it moved</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1015/1*G35DTpfOhxn9EQAT3tlZjA@2x.png" /></figure><p><em>the moment this clicked for me on camera: </em><a href="https://youtu.be/V-SUeX9xBPM?t=260"><em>https://youtu.be/V-SUeX9xBPM?t=260</em></a></p><p>Someone told me about a bug that morning, the kind that makes your stomach drop a little. They’d described the feature, the agent wrote it, they reviewed it, and it looked right so they approved it. <br>A few minutes later, reading it again for no particular reason, they caught it: the model had quietly swapped what should have been the default case with what should have been the special case.</p><p>I think that’s the real story of what’s happening to our jobs right now, and it’s not the story most people are telling. Our job isn’t vanishing but relocating.</p><p>For most of my career, the craft lived in the typing: the syntax, the idioms, the hard-won muscle memory of knowing exactly how to express an idea in code. That part is getting commoditized fast, and I understand why that stings if you spent 15 years getting good at it. <strong>But writing code was never actually the point, it was always just the vehicle we used to tell a piece of software how to behave.</strong> The thinking behind the vehicle, what the software should do, where the edges of a good abstraction are, what’s the default and what’s the exception, that hasn’t gone anywhere. If anything it matters more, because now the person doing that thinking has to catch mistakes that look exactly like correct answers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*A6Qt9YcAL-hkCy2fjTm6YA@2x.png" /></figure><p>There’s a way of thinking about this I keep coming back to: picture your <strong>knowledge as a pyramid</strong>. What you know sits at the bottom, that’s your unfair advantage, the stuff you actually earned. Above it sits what you know you don’t know yet, the tunnels you’re aware of but haven’t walked down. And at the very top, the part that never stops being uncomfortable, is what you don’t know you don’t know.</p><blockquote>AI can feel like it’s collapsing the whole pyramid, because it hands you an answer that looks like the thing you were reaching for. <strong>But you didn’t climb down into that tunnel yourself, the knowledge is borrowed, and borrowed knowledge is exactly the kind that fails you quietly, the way that bug did.</strong></blockquote><h3>The part I’d actually build my whole approach around</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gwRE9K7eUvDsn2cibAHoug@2x.png" /></figure><p><em>I go deep on this one in the studio, worth the watch: </em><a href="https://youtu.be/V-SUeX9xBPM?t=484"><em>https://youtu.be/V-SUeX9xBPM?t=484</em></a></p><p>If there’s one idea from this conference I’d want to stick, it’s this one, so bear with me.</p><p>First it was just prompting, a chat window and good intentions, then we realized the model needed to know things about us specifically, not just its training data, so we started stuffing context into vector stores and object stores, calling it RAG, and for a while that felt like the answer. Then we realized the model needed to know what we actually meant, not just what we had lying around, so specs came back into fashion, the thing developers used to roll their eyes at, except now the model does most of the heavy lifting so it doesn’t hurt the way it used to. Each step added a bit more structure. And now there’s a new layer on top of all of it, and it’s the one I think actually matters most: <strong>harness engineering.</strong></p><p>The old pattern, even with good specs, was one-directional, you hand the agent everything it needs and it hands you back some code. Sometimes it’s close. Sometimes it quietly gets the default and the exception backwards, like the story above, and looks completely fine doing it. Either way you’re the only feedback loop in the system, reviewing by hand, over and over, hoping you catch the thing that looks right but isn’t. A harness closes that loop.</p><p>The output does not just land in your editor and sit there waiting for your eyes; instead, it runs through a linter first, then hits a security scan, and static analysis checks the cyclomatic complexity, flagging any function that has grown too long, some of that happening the moment you save the file, some of it overnight in CI.</p><blockquote>The point isn’t any single check, it’s that <strong>you’ve built a small ecosystem where deterministic tools, the ones that behave the same way every single time, are wrapped around a nondeterministic one that doesn’t, so that you’re not trusting the agent less, but giving yourself a way to catch the specific failure mode that comes from something being fast, confident, and wrong all at once</strong>.</blockquote><p>And this only works if you resist the urge to move fast just because you can. More than 90% of the software running the world already exists, and the job is evolving it, not starting over. Every time I hear “we should ship faster now that AI writes the code,” I think about all the things that quietly get dropped in that sentence: security, resilience, disaster recovery, the “boring disciplines” that make software actually trustworthy.</p><p>Generative AI made producing code cheap but maintaining that code isn’t, and if anything the opposite is true, because every feature you bolt on makes the next one heavier to add. It’s less like building a house brick by brick and more like building a pyramid upside down, where every new brick makes the ones under it strain a little more. Introducing AI gradually, with a harness catching what you can’t catch by eye, is how you get the speed without inheriting that weight blind.</p><h3>How much rope you give the agent depends on what’s actually at stake</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WxLIgAo8tFlYAcPsNFcA7g@2x.png" /></figure><p><em>the full breakdown is here: </em><a href="https://youtu.be/V-SUeX9xBPM?t=1004"><em>https://youtu.be/V-SUeX9xBPM?t=1004</em></a></p><p>Once you’ve got a harness in place, the next question is a personal one: how close do you need to stay to any given piece of work. I think about this as 3 loops, and which one you’re in has nothing to do with how much you trust the model that week. It has to do with what you’re actually building.</p><p><strong>Engineer in the loop: </strong>You’re working step by step with the agent, having something closer to a conversation than a handoff, never giving it the full spec upfront and walking away. This is where you want to be for whatever is the actual reason your company exists. For Netflix, that’s the catalog and the player, the thing you’d never want a competitor to be able to replicate by copying a spec sheet.</p><p><strong>Engineer on the loop: </strong>You hand over more, a fuller spec, more room for the agent to produce something complete, but you’re still checking that what comes back matches the architecture you asked for, still holding the knowledge of how it was built even if you didn’t type every line. This is the right distance for the things that support your core business without being it, the parts that make the experience better but wouldn’t sink you if they had a rough day.</p><p><strong>Engineer out of the loop: </strong>You provide the spec, the tests, the fitness functions, the architectural guardrails, and then you genuinely step away until there’s something to review. Your effort goes into defining what “correct” looks like before the work starts, not into watching it get built. This fits the parts of the system that need to exist but aren’t why anyone chose you, payments being the textbook example. Nobody picks a streaming service for its checkout flow.</p><p>I don’t believe every part of a system is equally important, there are areas that are more than others. We have experienced this concept with strategic domain-driven design that helps us categorizing subdomains, defining architecture characteristics and more, so why not leveraging the same approach also on how much involvment a developer should have in a subdomain as a starting point and tweak it when/if needed?</p><p>If you’re the kind of person who’s now sitting there wondering which loop you’re in on your current project, good. That’s exactly the right question. It’s just not the one most people are asking yet.</p><h3>Summary</h3><p>I walked into that conference with a question and walked out with three conversations I’m still having in my head weeks later. What’s above is me thinking out loud about them afterward, alone, typing. What’s in the video is the actual thing: the people saying it in their own words, the whiteboard, the pauses where you can watch someone think in real time. That’s not something a paragraph can carry the same way.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FV-SUeX9xBPM%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DV-SUeX9xBPM&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FV-SUeX9xBPM%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/e584a09514096e99df067d6d6ba4082e/href">https://medium.com/media/e584a09514096e99df067d6d6ba4082e/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b211f77d96e6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Ten years of micro-frontend decisions, condensed into a skill]]></title>
            <link>https://lucamezzalira.medium.com/ten-years-of-micro-frontend-decisions-condensed-into-a-skill-bf6c93348cac?source=rss-9119c54d607d------2</link>
            <guid isPermaLink="false">https://medium.com/p/bf6c93348cac</guid>
            <category><![CDATA[harness-engineering]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[front-end-development]]></category>
            <dc:creator><![CDATA[Luca Mezzalira]]></dc:creator>
            <pubDate>Wed, 01 Jul 2026 20:05:54 GMT</pubDate>
            <atom:updated>2026-07-01T20:05:54.334Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fdp9dtHeryjOydbABw86vQ.png" /></figure><p>An inexperienced developer asks their AI agent to build a micro-frontend. The agent does not ask who will own it, what business capability it represents, or whether the team structure can sustain an independent deployment. It jumps straight to a Module Federation config and produces a shell that compiles, demos well, and is structurally a distributed monolith. An experienced architect asks the same agent to scaffold a shell for a boundary they have already designed. The agent does not cross-import from another MFE, does not share state via a global, does not pass domain objects across the contract. It still produces a distributed monolith, just a subtler one, because the boundary leaks one violation at a time in every file the architect is not watching.</p><p>It doesn’t matter if you are a developer or an architect, you need to properly design the boundaries of a distributed system. The hardest part of micro-frontends is the thinking that should come before the code, and the discipline to keep that thinking honest in every file afterwards: unfortunately most teams fail at one or both.</p><p>The skills I built address both sides. There are two acts in micro-frontend work: deciding where a boundary goes, which is contextual and judgement-heavy, and keeping a boundary clean once you have drawn it, which is mechanical and constant. No tool should make the first decision for you, but a tool can insist you make it rather than skip it, and that guided insistence is exactly what the architecture skill does, asking the ownership, domain, and split questions before any code is generated. For teams without an experienced architect, that may be the most valuable thing the skills do. For teams that have already done the design work, the review skill keeps the boundary from leaking one violation at a time.</p><p>If you have used the <a href="https://medium.com/@lucamezzalira/the-micro-frontend-canvas-a-practical-tool-for-better-boundaries-99da1a7b858d">Micro-Frontend Canvas</a>, you have already done the first act. If you have not, the skills will walk you through it before they let you write code. Either way, the two meet in the same place.</p><p>Here you can find the micro-frontends skills repository: <a href="https://github.com/lucamezzalira/mfe-skills">https://github.com/lucamezzalira/mfe-skills</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*jaGcIWxktEUWQH99" /></figure><h3>What this looks like in practice</h3><p>Here is the difference, reduced to the smallest honest example. Same brief, same agent, an e-commerce shell mounting a catalog micro-frontend. First, what an agent produces on its own, from tutorial instincts:</p><pre>// shell/App.tsx (without governance)</pre><pre>// reaches into another MFE<br>import { formatPrice } from &#39;catalogMfe/productUtils&#39;  <br>import { CatalogApp } from &#39;catalogMfe/CatalogApp&#39;</pre><pre>window.__SHOP_CART__ = createCartStore()      // shared global state</pre><pre>&lt;CatalogApp<br>  shellUser={currentUser}                      // full domain object<br>  cart={cartState}                             // full domain object<br>  formatPrice={formatPrice}                     // borrowed function<br>  onNavigate={handleNavigate}               // shell owns navigation<br>/&gt;</pre><p>Four things passed across the boundary, a function imported from another team’s code, and a cart on the window object that any remote can mutate. It compiles. It demos. It is a distributed monolith.</p><p>Now the same mount, with the review skill loaded:</p><pre>// shell/App.tsx (with skills)</pre><pre>// resolved at runtime<br>const CatalogApp = lazy(() =&gt; loadRemote(&#39;catalog&#39;))   </pre><pre>// failure stays isolated<br>&lt;ErrorBoundary fallback={&lt;CatalogUnavailable /&gt;}&gt; <br>  &lt;CatalogApp<br>    userId={currentUser.id}      // an identifier, not the object<br>    platformBus={bus}            // events, not shared state<br>  /&gt;<br>&lt;/ErrorBoundary&gt;</pre><p>Two identifiers across the boundary, no cross-import, no shared store, a runtime-resolved remote, and a failure that cannot take down the shell. The catalog fetches its own data and owns its own routes. Nothing here is cleverer, it is just disciplined, on every prop, every time, which is exactly the discipline that erodes under deadline pressure when a human does it by hand. (The loadRemote, platformBus and fallback shapes are conventions your project establishes; the skill respects them, it does not invent them.)</p><p>That is the review skill’s job. Not to decide that catalog should be its own micro-frontend, but to make sure the code expressing that decision actually honours it. If you had not made the decision at all, the architecture skill would have prompted you to make it before any code was generated.</p><h3>Designing micro-frontends</h3><p>With that distinction in place, the deeper point. When people ask how to “do” micro-frontends, they usually want a framework, a configuration, a default to follow. That instinct is the first mistake. Micro-frontends are not a thing you install but a set of decisions you make about your specific context, and those decisions only make sense if you think like an architect rather than a consumer of someone else’s choices.</p><p>Designing a boundary means understanding your context: how your teams are shaped, who owns what, where communication is cheap and where it is expensive. It means building an engineering culture that supports the behaviour you want, because the architecture will only hold if the organisation around it is set up to hold it.</p><p>This is why no tool can draw your boundaries for you. There is no regex, no formula, no score that produces a correct boundary. Boundaries are expressions of trade-offs, faster independent delivery here, tighter consistency there, and those trade-offs are contextual. Two companies with the same product can have completely different and equally correct boundaries because their teams, constraints, and goals differ.</p><h3>Boundaries are not permanent</h3><p>There is a second truth that sits underneath the first: a boundary is correct for a moment in time, not forever!</p><p>Your business changes, your team topology changes too. A capability that justified its own micro-frontend two years ago might now be better merged with another, or split further as a team grows around it. The socio-technical system is alive, and the architecture has to move with it.</p><p>This is the part teams find hardest, because revisiting boundaries requires the same architectural judgement that drew them in the first place, applied continuously, by people who may not have been in the room when the original decisions were made. It is the work that gets skipped and skipping it is where the trouble starts.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*G6qb6QBl3F1751X7" /></figure><h3>The failure I have watched the most</h3><p>Here is the pattern I have seen play out more often than any other. A company adopts micro-frontends, some months in, friction appears: releases that should be independent start needing coordination, changes ripple across teams, things feel slower than the monolith they left behind. The conclusion is almost always the same: the architecture failed. Micro-frontends were a mistake. Rip it out.</p><p>In nearly every case, the architecture did not fail. It was doing its job. The friction was the system reporting a truth the organisation did not want to hear: the boundaries did not match the socio-technical reality. Blaming the architecture is comforting because it points at the code, which feels fixable, instead of at the organisational design, which feels political. But the code was only ever a reflection. The skills address both sides of this failure: the architecture skill forces the design conversation that gets skipped, and the review skill catches the slow erosion of a sound boundary into a leaky one, the erosion that gets misread as the pattern failing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*F8Ko1GPV53iNa2D-" /></figure><h3>What the evidence shows</h3><p>I ran a controlled experiment to see the difference concretely: 2 AI agents, one identical brief. React 19, Module Federation, an ecommerce shell with a home and a catalog micro-frontend. One agent built with no governance, the tutorial defaults. The other built with the skills and a project <a href="http://agents.md/">AGENTS.md</a> in place. Both reference implementations, the governed build (ThreadTales) and the ungoverned one, are public in the repository so you can read the actual code rather than take my word for the summary below. The rules come from the decade of practice; this demo simply shows them holding. It is one illustration, not a dataset, but the divergence is instructive.</p><blockquote><em>The contrast was not subtle.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*XQ_8MLSIrmyYOSI3" /></figure><p>Without governance, the shell imported a utility directly from the catalog and passed four things into it: a user object, the cart state, a formatting function, a navigation callback. The cart lived in a window.__SHOP_CART__ global shared across remotes, remote URLs were hard-coded in the webpack config, and adding a route meant editing the shell’s App.tsx. Failure handling was a bare Suspense.</p><p>With the skills, there were no imports across remotes; the mount contract was a user identifier and a platform bus; there was no shared store, coordination happened through the URL and events; remotes resolved at runtime through a discovery manifest, with the catalog owning its own deeper paths; and every remote sat behind a shell-level error boundary with its own fallback. Adding a page meant a manifest entry, not shell code.</p><p>The without-skills build carried critical violations of Rules 3 and 4, cross-boundary imports and shared state, the exact ingredients of a distributed monolith. The with-skills build aligned with all eight rules and, more importantly, stayed extensible: new catalog pages without ever touching the shell. That extensibility is the architecture doing its job, which is the entire point.</p><h3>What I actually built</h3><p>The skills take the decade of judgement, both the guidance and the enforcement, and put it where decisions are now being made: inside the AI agents that more and more teams use to write their micro-frontend code.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*iym6wFuLCnaAVfBo" /></figure><p>A skill, in the now-standard SKILL.md format, is a package of architectural reasoning an agent loads exactly when it becomes relevant. There are two. understanding-mfe-architecture activates when you are making decisions: whether to adopt the pattern, where boundaries should go, how remotes should communicate. It pairs with a companion Micro-Frontend Canvas skill that turns the boundary-design conversation into a structured worksheet rather than a guess. reviewing-mfe-boundaries activates when code crosses a team boundary: shell mounting, cross-MFE communication, remote loading, contract design. It carries the eight rules, the signals that reveal each violation, severity, and remediation, across a multitude of micro-frontends frameworks.</p><p>A skill is not always in context. The moment you write shell-mounting code or ask for a boundary review, the full rule set loads, does its work, and recedes. Deep governance without paying for it on every unrelated prompt.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*tEqss6TAQo7TvYaU" /></figure><p>Of course, a skill is just one layer. An AI agent applying rules probabilistically is a real improvement over no governance at all, but it is not the whole answer. Harness engineering calls for sensors alongside the guides, and in practice that means deterministic tools that verify the architecture after the code is written: libraries like <a href="https://github.com/ts-arch/ts-arch">ts-arch</a> that test whether the dependency graph actually respects the boundaries you designed, so a violation cannot survive a CI run regardless of whether the agent caught it during generation. The skill shapes the code as it is being written, the sensor rejects it if it got through anyway. I am going to spend serious time designing a complete harness for micro-frontends in the AI era, combining skills, fitness functions, architecture tests, and contract checks into one coherent governance layer. Watch this space.</p><h3>Using the skills on a brownfield estate</h3><p>Most teams are not starting fresh, they have an existing estate, parts of it healthy, parts carrying violations that accumulated quietly over time.</p><p>Point your agent at existing shell integration code and ask it to review against the boundary rules. Instead of generic React feedback, you get violations tied to specific rules, with severity and concrete remediation for your toolchain. A cross-boundary import is flagged as a critical Rule 3 violation, not a vague suggestion to refactor. A fat prop contract is measured against the minimal-API rule. This is the difference between a reviewer who knows React and one who knows micro-frontends, and for teams without a resident architect, that gap is the whole game. It is also how you keep boundaries aligned as the system evolves, by re-reviewing them as the business changes rather than letting them drift.</p><p>I am preparing a video walkthrough that shows the full flow from Canvas to skills to a live brownfield review, so you can see exactly what the agent surfaces and how the remediation works. In the meantime, <a href="https://lucamezzalira.medium.com/the-micro-frontend-canvas-a-practical-tool-for-better-boundaries-99da1a7b858d">the companion article on the Micro-Frontend Canvas</a> covers the design side in detail.</p><h3>Using the skills on greenfield and migration</h3><p>The brownfield case is the most common, but two others matter. On a greenfield project the skills earn their value before a single component is written, because the most expensive boundary mistakes are the ones made on day one. The architecture skill forces the questions that get skipped in the rush to scaffold: which team owns this capability end to end, what business subdomain it actually represents as opposed to which UI it happens to render, vertical or horizontal split and why. With the Canvas skill that conversation becomes a structured worksheet the team fills in together. Only once the thinking is done does the review skill shape the code, so the agent generates from your decisions rather than tutorial defaults.</p><p>Migration is the hardest position: a team that knows it needs to move, away from a monolith or away from a setup that has drifted into a distributed monolith, but does not know where to start. Migration is not a code transformation, it is a sequence of boundary decisions made under real constraints. The architecture skill helps identify where the genuine subdomains lie and which capability is the safest first candidate to extract, the strangler approach the rules support through edge routing and runtime discovery. The review skill keeps each extracted slice honest as it comes out, so you migrate one well-reasoned boundary at a time instead of trading one distributed monolith for another.</p><h3>Why AGENTS.md is not optional, and what happens if you skip it</h3><p>There is one part teams underestimate, and getting it wrong is worse than not using the skills at all. The skills encode the general boundary integrity rules. They cannot know your specific system. That knowledge lives in your project’s AGENTS.md, or CLAUDE.md for Claude Code: which teams own which micro-frontends, which toolchain you use, which boundaries you have consciously chosen and which exceptions you have deliberately accepted. The skills supply the rules; the AGENTS.md supplies the context in which those rules must be applied.</p><p>Skip it and you do not get a weaker version of the same thing. You get something more dangerous: an agent applying eight rules with full confidence to a context it only half understands. It may flag a deliberate, documented exception as a violation, and do it persuasively enough that a junior engineer will trust it. Confident, plausible, wrong governance is harder to catch than no governance, because it looks like authority. The AGENTS.md is not what makes the skills better. It is what makes them safe. Treat it as mandatory.</p><h3>What you can tune, and what skills cannot do alone</h3><p>Two honest clarifications, because both matter before you adopt this.</p><p>First, the rules are a baseline, not scripture. Some are close to universal while others are genuine trade-offs your context might override, granularity being the obvious one. These are my defaults, drawn from the decade. Your architecture group is meant to tune them, in the skill and in your AGENTS.md, to match your house style. The point is not to inherit my opinions wholesale; it is to start from a considered baseline and adjust with intent, rather than from tutorial instinct and adjust never.</p><p>Second, and more important: skills are one instrument, not the whole orchestra. An AI applying rules is probabilistic. It catches most violations most of the time, a real gain, but “most, mostly” is not governance you can stake an architecture on. The deterministic half has to be there too: fitness functions that fail a build when a forbidden import appears, dependency-cruiser or ESLint boundary rules in CI, contract tests at the seams, the harness engineering that makes a violation impossible to merge rather than merely likely to be noticed. The skills make the reasoning present at the moment of writing; the deterministic tooling makes the rules enforceable at the moment of merging. You need both. A team that treats the skill as a replacement for fitness functions has swapped one kind of wishful thinking for another.</p><p>That pairing is also what using this feels like day to day. You write a mount, the agent flags the cross-import inline and proposes the identifier-and-bus rewrite, you accept it or push back with a reason that goes into the AGENTS.md. Then CI has the final, non-negotiable word. The agent advises; the harness enforces.</p><h3>Where it runs, and who owns it</h3><p>The SKILL.md format is now supported across the tools teams already use. Claude Code consumes the skills natively. Cursor reads them as .mdc rules. Codex, and any assistant that follows the open AGENTS.md standard, picks up the governance through the project file. Install once, commit the skills to your repository, and every member of the team inherits the same architectural reasoning on clone.</p><p>There is a second reason to commit the skills to the repository beyond convenience. When multiple teams work in the same estate, whether in a monorepo or across separate repositories, the skills give them a shared foundation they did not have to negotiate. Every team reasoning from the same encoded baseline arrives at the same mount-contract shape, the same communication patterns, the same failure handling, the same approach to remote resolution, without a central architect policing every pull request and without relitigating the same decisions in ten separate code reviews. The skills standardise the part that should be standard so each team can focus on what actually differs: their domain.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*cXZk21K2Q4s6KHx5" /></figure><p>That last point raises a question worth naming, because the skill is now itself a piece of your architecture. Someone has to own it. When your boundary conventions evolve, the skill and the AGENTS.md evolve with them, and that ownership should sit where your architectural authority already sits, not forked quietly into ten team-local dialects. The skill standardises your teams precisely because it is singular and shared. Let it fragment and you have rebuilt the very divergence it was meant to remove. The governance artifact needs governance: that is the cost of a single source of architectural truth, and it is worth paying.</p><h3>The real shift</h3><p>For 10 years, the limiting factor in micro-frontend adoption has been the number of people who could reason correctly about boundaries and, just as importantly, keep enforcing that reasoning in every file as the organisation changed. The placement was always the smaller problem.</p><p>The skills do not remove the need for architectural thinking, and they do not draw your boundaries. What they do is make the discipline present at the moment it is needed: the architecture skill guides the thinking that should precede the code, the review skill enforces the rules that keep the code honest, and together they are applied by the agents that are increasingly writing the code anyway. You still own the decisions. The skills make sure that once you have made them, your system keeps honouring them, and for teams that have not yet made those decisions, the skills insist that they do before a line of code is generated.</p><p>MFE Skills is open source and free. Get it, along with the full experiment and both reference implementations, at <a href="http://github.com/lucamezzalira/mfe-skills">github.com/lucamezzalira/mfe-skills</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bf6c93348cac" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Micro-Frontend Canvas: a practical tool for better boundaries]]></title>
            <link>https://lucamezzalira.medium.com/the-micro-frontend-canvas-a-practical-tool-for-better-boundaries-99da1a7b858d?source=rss-9119c54d607d------2</link>
            <guid isPermaLink="false">https://medium.com/p/99da1a7b858d</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[microservices]]></category>
            <category><![CDATA[micro-frontends]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[front-end-development]]></category>
            <dc:creator><![CDATA[Luca Mezzalira]]></dc:creator>
            <pubDate>Wed, 10 Jun 2026 06:44:24 GMT</pubDate>
            <atom:updated>2026-06-10T06:44:24.731Z</atom:updated>
            <content:encoded><![CDATA[<p>Most teams come to micro-frontends with the same assumption: our problem is technical. We need better tooling, faster deployments, independent scaling.</p><p>Three months into the implementation, teams are stepping on each other. Boundaries that seemed logical during planning create dependencies and deployment friction. The shared design system is not actually shared. Who responds when the checkout flow breaks? Nobody answers clearly.</p><p>The Micro-Frontend Canvas exists to fix the design problem before it becomes a code problem you will struggle to undo.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yLpH5XGDkdlOGH0NsJVRMA.png" /><figcaption>It’s not a wise decision skipping the design phase</figcaption></figure><h3>Where teams actually struggle</h3><p>Over the past twenty years in this industry, I have worked with more than a hundred teams worldwide, across different industries, scales, and levels of maturity: Fortune 500 companies, fast-growing startups, fintech, e-commerce, SaaS. The majority of micro-frontend failures are not due to technical skills. Teams know how to code, they understand React, Vue, deployment pipelines, CI/CD. They can build distributed systems.</p><p>The problem is in the design phase, or more accurately, the complete absence of one. Most teams skip the decision-making part entirely. They hear “micro-frontends” and jump straight to implementation. They focus immediately on the technology side comparing frameworks and features each of them has to offer. They start coding before they have answered the questions that actually determine success:</p><ul><li>Is a micro-frontend the right solution for this problem at all?</li><li>What defines a boundary, and how do we know it is the right size?</li><li>How will teams communicate without creating tight coupling?</li><li>Who owns the composite application when something breaks?</li><li>What shared standards do we enforce, and how do we prevent drift across independent teams?</li></ul><p>Without answers, you build a system that looks independent on the surface and is tangled underneath. The friction that follows gets blamed on the architecture, when the real cause is that the boundaries never matched the socio-technical reality of the organisation.</p><blockquote>The architecture was just doing its job: surfacing a misalignment nobody designed away.</blockquote><h3>Before the canvas: should you even do this?</h3><p><em>Micro-frontends are not for every project, and they are certainly not a silver bullet</em>. Before the canvas comes a gate, because the most expensive micro-frontend is the one you should never have built. There are three reasons that genuinely justify the pattern:</p><p><strong>First, scaling teams.</strong> As your organisation grows, a single monolithic frontend becomes a bottleneck. Merge conflicts, coordination overhead, and slow release cycles pile up. Micro-frontends let teams own independent slices of the application, enabling faster, safer deployments without stepping on each other.</p><p><strong>Second, aligning architecture with business capabilities.</strong> Micro-frontends are designed around business domains, like checkout, user profiles, or dashboards, rather than around code abstractions and reusability the way components are. This alignment lets teams build, deploy, and evolve features independently while staying close to business goals.</p><p><strong>Third, reducing risk and improving resilience.</strong> A single bug or failed release in a monolith can bring down the whole application. Micro-frontends isolate failure to a single module, so problems do not ripple across the system.</p><p>If none of these three pressures apply to you, a well-structured monolith or a modular monolith is very likely the better choice, and <em>you should not feel any pressure to adopt a pattern built to solve problems you do not have</em>. If you want to go deeper on this decision, it is the subject of much of my book, <a href="https://amzn.to/43pFdw0">Building Micro-Frontends</a>. <strong>The canvas assumes you have passed this gate honestly.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DyC-7F_70gNw5xooCrDKqA.png" /><figcaption>Building Micro-Frontends 2nd edition</figcaption></figure><h3>What the canvas is</h3><p><a href="https://github.com/lucamezzalira/mfe-canvas">The Micro-Frontend Canvas</a> is a structured one-page tool that captures the key decisions for a single micro-frontend. The rule is simple: one micro-frontend, one canvas. It serves as a reference artifact that helps a team systematically work through the technical, organisational, and architectural concerns that will determine whether that micro-frontend succeeds.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*v1diPE7loo9k_EqMmeB0mw.png" /><figcaption>Micro-Frontends Canvas 1.0 — CC</figcaption></figure><p>It works two ways.</p><p><strong>In planning mode</strong>, before you write a line of code, the canvas forces your team to ask the critical questions about boundaries, constraints, dependencies, and quality standards. This prevents costly rework later and creates alignment between engineering, product, and leadership before implementation begins.</p><p><strong>In assessment mode</strong>, if you already have micro-frontends, or you suspect your architecture is struggling, the canvas becomes a diagnostic. You use it to audit a system you already run: where are the boundaries leaking, which dependencies are hidden, where is ownership unclear, what needs to be restructured. Teams who have lived with friction for months often find that filling in a canvas for an existing micro-frontend surfaces the exact misalignment causing their pain, and does it in an afternoon rather than a post-mortem.</p><p>Either way, the canvas gives you something most organisations badly lack:</p><blockquote>a shared language for discussing architectural complexity, one that depersonalises the conversation. The canvas critiques the design, not the person who wrote it.</blockquote><h3>How to use it, honestly</h3><p>You do not need a heavyweight ceremony. The most effective way I have seen teams use the canvas is to first run a short boundary-identification session sometimes involving cross-functional stakeholders, engineers, engineering managers, architects, and product, kept deliberately small. Once you have a candidate boundary, the canvas itself is best filled in as an <strong>async reference artifact</strong>: one or two people draft it, the rest of the team reviews and challenges it asynchronously, and you converge over a day or two rather than locking fifteen people in a room.</p><p><em>That async-first approach came directly from teams who tested the canvas in the field, including one large financial organisation that found it worked far better as a living document than as a workshop event</em>. Treat it as a document you return to, not a ritual you perform once. When friction emerges later, when the business shifts direction or a new feature stresses an existing boundary, you reopen the canvas and reassess. A boundary is correct for a moment in time, not forever. The canvas is how you keep checking.</p><h3>What a section actually looks like</h3><p>Abstract descriptions of canvas sections are not very useful, so here is one section applied, using a checkout micro-frontend as the subject.</p><p>Take the <strong>Boundaries validation</strong> section. Its job is to test whether the boundary you have drawn is the right size and genuinely independent. The guiding questions are deliberately uncomfortable:</p><ul><li>Can this micro-frontend be deployed without coordinating with any other team?</li><li>What data does it own, and what does it borrow?</li><li>If it needs data from another domain, how does it get it without a runtime dependency on that team’s code?</li></ul><p>Filled in for checkout, it might read: “Checkout owns the cart, payment, and order-confirmation flow. It deploys independently. It needs product price and availability, which it does not own. Decision: checkout calls its own backend-for-frontend, which aggregates pricing, rather than importing from the catalog micro-frontend or sharing a store with it.”</p><p>That single filled-in section does real work. It exposes the most common hidden dependency in e-commerce, the one where checkout quietly reaches into catalog for a formatting helper or a price object, and it forces the team to decide on a clean alternative before the coupling is written into the code. This is the canvas earning its place: not by adding documentation, but by forcing a decision that would otherwise be made by accident, three sprints in, by whoever was on the keyboard.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Fsa-8iKJqacldtoEasZDiA.png" /></figure><p><a href="https://github.com/lucamezzalira/mfe-canvas">The full canvas</a> carries this same treatment across every section, and the PDF guide includes a complete worked example end to end.</p><h3>The sections that matter</h3><p>Each section guides a team through a specific class of decision. Business capability asks what problem this micro-frontend solves and which business subdomain it represents, as opposed to which UI it happens to render. Boundaries validation, shown above, tests size and independence. Dependencies surfaces what the micro-frontend needs, and critically, whether a corresponding backend boundary exists, because a checkout micro-frontend claiming independent deployment is not independent if it sits on a monolithic backend coordinated by another team. Communication methodology captures how this micro-frontend talks to others, the contracts involved, how those contracts are tested, and who owns them. Governance and observability answers the question teams most often defer until an incident: who owns this in production, what standards it must meet, and how shared dependencies are managed. Quality guardrails records the standards you will enforce. Challenges and risks names what could go wrong while you can still design around it.</p><blockquote>None of these are technical questions in the narrow sense. They are decisions about ownership, alignment, and trade-offs, expressed precisely enough that the code which follows has something true to be built against.</blockquote><h3>From canvas to code, and to your AI agent</h3><p>Here is where the canvas matters more in 2026 than it did when I first designed it.</p><p>A filled-in canvas is a set of architectural decisions written down precisely: this is the boundary, this is what crosses it, this is how it communicates, this is who owns it. <strong>That is exactly the input modern development now runs on.</strong> Whether you call it spec-driven development or context engineering or harness engineering, the principle is the same:<strong> the quality of what your tools build depends on the quality of the decisions you feed them.</strong> The canvas produces those decisions in a form a team, and increasingly an AI coding assistant, can build against.</p><p>When you hand a boundary to an AI agent, the agent will scaffold it fast and confidently, and it will reach for tutorial defaults that quietly dissolve the very boundary you designed: cross-imports between micro-frontends, shared global stores, fat contracts passing whole domain objects across team lines. The canvas decides where the boundary goes. It cannot, on its own, stop the code from leaking it.</p><p>That second half, keeping a boundary intact once you have drawn it, is a different problem, and it is the one I take up next. I have packaged the a set of boundary rules that protect a boundary’s integrity into <a href="https://github.com/lucamezzalira/mfe-skills">a set of skills your AI assistant loads as it writes</a>, so the decisions captured in your canvas are actually honoured in the code your agent produces. The canvas draws the boundary while the skills keep it from leaking. Together they cover the full distance from architectural intent to running code, which is the distance where most micro-frontend initiatives quietly fail. I’ll follow up with an in depth article on the skills and how I used in projects.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zz73et_zn-ztY4m3RvTbHA.png" /></figure><h3>Why it is free</h3><p><strong>The canvas is released under Creative Commons, free to use, share, and adapt for non-commercial purposes.</strong> It exists to solve an industry problem, not to be a product. The goal is to democratise architectural thinking that has mostly lived in the heads of expensive consultants and put it in the hands of any team that needs it.</p><p>To be clear about what the free tool does and does not replace: the canvas democratises the questions, the structure, the shared language. <strong>The judgement of how to answer those questions in your specific political and technical context, where the trade-offs genuinely bite, is the harder thing, and it is built through experience.</strong> The canvas does not remove the need for that judgement. It makes the judgement visible, teachable, and reviewable, which is the most useful thing a tool in this space can do.</p><h3>How to start</h3><p>If you are planning new micro-frontends, run the boundary session, then fill in one canvas per micro-frontend before you commit to implementation. If you already have micro-frontends and something feels wrong, take your most painful one and fill in a canvas for it as it exists today. The gaps you cannot fill in cleanly are almost always where your friction is coming from.</p><p>Either way, this is a living tool, and it gets better when teams use it and tell me what they learn. <a href="https://github.com/lucamezzalira/mfe-canvas">Download it</a>, use it, and tell me what worked and what it missed.</p><p>The boundaries were never really the problem. Not designing them, and not protecting them once designed, was. The canvas is where you start fixing that.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=99da1a7b858d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[From T-Shape to Comb-Shape: how developer knowledge needs to evolve in the AI era]]></title>
            <link>https://lucamezzalira.medium.com/from-t-shape-to-comb-shape-how-developer-knowledge-needs-to-evolve-in-the-ai-era-69024bbb62d7?source=rss-9119c54d607d------2</link>
            <guid isPermaLink="false">https://medium.com/p/69024bbb62d7</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Luca Mezzalira]]></dc:creator>
            <pubDate>Mon, 06 Apr 2026 21:47:19 GMT</pubDate>
            <atom:updated>2026-04-07T08:51:09.490Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mbbsf3pFlrYbuI5w2picmw.png" /><figcaption>from t-shape to comb-shape</figcaption></figure><p>There’s a WhatsApp group I’m part of with <a href="https://www.linkedin.com/in/mmeckes/">Matthew Meckes</a> and <a href="https://www.linkedin.com/in/mark-sailes/">Mark Sailes</a>. We used to work together, and honestly it was one of those rare team combinations where the dynamic just clicked. Different people left for different companies or teams, as always happens, but the conversations never stopped. These days we share a running thread about where this industry is heading. Lately, almost every exchange circles back to the same uneasy territory: what does software development actually look like from here?</p><p>Not the tooling specifics. Not which model is better at which task. The bigger question.</p><blockquote>What is a developer’s job becoming?<br>What does it mean to be good at this in five years?<br>What does the SDLC look like when the machines do most of the building?</blockquote><p>We don’t have clean answers, but we keep asking, because the alternative is assuming the old answers still hold, and they clearly don’t.</p><h3>The T was always a good idea</h3><p>The T-shaped developer is one of those frameworks that everyone nods at. The idea makes sense: some depth in a primary domain, enough breadth across adjacent disciplines to communicate, collaborate, and not be completely lost outside your lane. In practice, most developers naturally grow a shape closer to the T in aspiration but variable in execution.</p><p>That’s not a failing. It’s a reflection of how career paths actually develop. Seniority isn’t just about going deeper in one thing. Exposure matters enormously: the more teams you’ve been on, the more systems you’ve seen fail in interesting ways, the more contexts you’ve navigated, the more your knowledge naturally spreads. A developer who has worked on a backend team, then moved into platform engineering, then spent a year close to production incidents, carries a fundamentally different mental model than someone who has optimised one narrow surface for years. Both can be excellent. But they bring different things.</p><p>The honest observation is that many developers, especially earlier in their careers or in environments that don’t expose them to cross-cutting concerns, can end up operating well inside their own domain while having limited visibility into the rest of the system. They know the library, the framework, the patterns that work in their context. They’re productive and effective. But the bigger picture, the one where their code lives among other decisions, other teams, other constraints, can remain a bit fuzzy.</p><p>That’s fine, up to a point. The question the AI era is forcing is: what happens to that profile when the part you’re good at gets increasingly automated?</p><h3>The level below</h3><p>Matt dropped a thought into the thread that I’ve been thinking about for a few days. The framing came from <em>Scott Hanselman.</em></p><blockquote>You should understand at least one level of abstraction below the layer you primarily work in.</blockquote><p>A web developer should have a feel for the browser, the OS, maybe a bit of C. A Java developer should have some grasp of the JVM, of what a compiler is actually doing. Knowing what you’re standing on.</p><p>The point isn’t that you should become a systems programmer before you’re allowed to build web apps. It’s that without any feel for the layer below, you lose the ability to reason about certain classes of problems. The performance issue that isn’t in your code but in how the runtime is behaving. The memory leak that only appears at a certain scale. The latency that has nothing to do with your logic and everything to do with how the networking stack handles the request.</p><p>AI assistants are very good at generating plausible-looking code. They are considerably less good at telling you when the layer beneath is behaving in a way the generated code didn’t account for. That’s still your job. And it’s not a hypothetical situation. I ran into this a while ago while integrating Module Federation 2.0 with React Router 7. They clashed, and the AI’s response was to start reconstructing the routing layer for Module Federation from scratch, confidently generating more and more code to paper over the incompatibility. The actual solution, which took a few minutes of scanning GitHub issues, was to move to React Router v6.7. No code changes at all. The AI had no visibility into the compatibility surface between those two libraries, no access to the issue tracker where the problem had already been diagnosed, no instinct to look sideways rather than dig deeper.</p><h3>The pyramid, and why AI doesn’t collapse it for you</h3><p>Mark Richards and Neal Ford introduced a model I keep returning to in architecture education: the <a href="https://nealford.com/memeagora/2015/09/08/knowledge-breadth-versus-depth.html">knowledge pyramid</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jz42BmrN5ehdhNqqxvVkmw.png" /><figcaption>Mark Richards &amp; Neal Ford — Fundamentals of Software Architecture</figcaption></figure><p>The idea is that all knowledge can be partitioned into three layers: things you know, things you know you don’t know, and things you don’t know you don’t know. Early in a career, the focus is on growing the top layer, building genuine expertise. Over time, experience expands the middle layer too. As a developer encounters more systems, more failure modes, more edge cases, the set of known unknowns grows alongside the depth. You don’t know distributed consensus algorithms inside out, but you know they exist and you know roughly when they’re relevant. That’s the middle layer doing its job.</p><blockquote>The goal is always to push more of the bottom layer upward. To reduce the terrain you can’t even see.</blockquote><p>Here’s what I think gets misunderstood about AI in this context. <br>It can look like AI collapses the pyramid for you, because it surfaces answers quickly across a wide surface area. You ask about something you don’t know, it responds with something coherent, and you feel informed. But that feeling can be misleading. The agent’s unknown unknowns, the gaps in its training, the cases it doesn’t know it doesn’t handle well, become your unknown unknowns the moment you accept its output without building genuine comprehension.</p><p>Developers who move too fast through AI-generated code, accepting rather than understanding, are actually expanding the bottom of their pyramid while feeling like they’re shrinking it.</p><p>The output looks like knowledge. The understanding hasn’t transferred.</p><h3>From T to comb</h3><p>The shape I keep landing on isn’t the T. <strong>It’s a comb</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MpzxHQkT-xmcchgfUzb4MA.png" /><figcaption>Developers need a comb shape</figcaption></figure><p>A comb has multiple teeth, each going to a reasonable depth. Not all equal, necessarily, but the key difference from the T is plurality.</p><blockquote>You’re not broad-and-thin across everything, and you’re not deep in exactly one thing. You have several domains where you can actually operate rather than just converse.</blockquote><p>Why now specifically? Because AI is eating the part of expertise that was always most mechanical: remembering syntax, accumulating framework patterns, knowing which API does what. That surface is being commoditised (hopefully). What remains, and what becomes more valuable as a result, is the capacity to hold multiple domains in your head simultaneously and make judgements across them.</p><p>Think about what it actually means to direct agents effectively. You need to evaluate whether the generated output is architecturally sound for your context, not just syntactically correct. You need to know when a proposed approach has violated a constraint the agent didn’t have context for. You need to catch the security implication that wasn’t in the prompt, or recognise that the data model being generated will cause problems two services down the line. None of that lives in a single deep domain. All of it requires multiple teeth in the comb.</p><p>“Extremely deep knowledge of [X]” is still valuable today. Its half-life is compressing. The rote parts of deep expertise are being commoditised. What survives is understanding <em>why</em> you’re doing what you’re doing, <em>how</em> the system holds together, and <em>where</em> the boundaries are.</p><h3>What Gas Town, AI-DLC and harness engineering are actually pointing at</h3><p>There are several converging threads in recent thinking about how software gets made that point at the same structural shift from different angles.</p><p>Gas Town is Steve Yegge’s multi-agent orchestration system. It transforms development from working with a single AI co-pilot into supervising an autonomous factory of agents building, testing, and shipping features in parallel. It’s early, it’s rough, it burns through API budget at a rate that will make your eyes water. But the observation that came out of reading about it stayed with me: when you have a large pool of agents churning through code tasks, development time is no longer the bottleneck. Design becomes the limiting factor, imagining what you want to create and working out all the gnarly details.</p><p>Read that carefully. Implementation is no longer the constraint. Design is. That’s a significant shift in where human effort needs to concentrate.</p><p>AWS’s AI-DLC, the AI-Driven Development Lifecycle, arrives at the same place from a different direction. Our existing development methods are designed for human-driven, long-running processes, with product owners, developers, and architects spending most of their time on non-core activities such as planning, meetings, and other SDLC rituals. Simply retrofitting AI as an assistant not only constrains its capabilities but reinforces outdated inefficiencies. The argument is that the traditional SDLC was built to manage human cognitive limitations and human coordination costs. Agents don’t have those same limitations, so reproducing the traditional structure with agents in the developer seat isn’t transformation. The methodology tries to help development teams focus on strategic work while AI handles implementation tasks such as workflow orchestration, task breakdown, coding, testing, and deployments.</p><p>There is also a great piece by Birgitta Böckeler that landed recently on Martin Fowler’s site, titled Harness Engineering for Coding Agent Users. I had a conversation with Birgitta at QCon London a few weeks ago and her thinking on this has been sharpening for a while. The core idea is that if you want coding agents to work with less supervision, you need to invest seriously in the harness around them: the guides that steer agent behaviour before it acts, and the sensors that let it self-correct after. A well-built outer harness serves two goals: it increases the probability that the agent gets it right in the first place, and it provides a feedback loop that self-corrects as many issues as possible before they even reach human eyes.</p><p>What strikes me about this framing is what it implies about the skills required to do it well. Building an effective harness for a coding agent isn’t a mechanical task. Writing the architectural fitness functions that define whether the agent’s output respects your module boundaries, crafting the feedforward guides that encode your domain’s invariants, designing the feedback sensors that catch semantic drift rather than just structural violations. All of that requires the kind of deep, multi-domain knowledge I’ve been describing. The human’s job in this is to steer the agent by iterating on the harness. And you can only steer well if you understand where you’re going.</p><p>Taken together, Gas Town, AI-DLC, and harness engineering are all telling us the same thing.</p><blockquote>The human role in software development is migrating up the stack. Not disappearing. Migrating.</blockquote><p>The question is whether the humans doing that work have the knowledge to operate effectively at a higher level of abstraction, and most of us were trained to go deep in implementation, not wide in thinking.</p><h3>Strategic DDD and the question of which code actually matters</h3><p>Let’s be honest, not all code is equally important. This is something Domain-Driven Design has been telling us for a long time, specifically through the strategic lens of subdomain classification, but the AI era makes it newly urgent.<br>In strategic DDD, subdomains are categorised as core, supporting, or generic.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*y4NZCAQO4-e1IIremNAlKw.png" /><figcaption>Domain-Driven Design subdomains</figcaption></figure><p>The core domain is where your business creates genuine competitive value. It’s the logic that, if it were the same as everyone else’s, would remove your reason to exist. Supporting subdomains enable the core but aren’t differentiating on their own. Generic subdomains are the plumbing: authentication, notifications, payment processing, the things every system needs and nobody gains advantage from doing differently.</p><blockquote>This classification has always mattered for architectural decision-making.</blockquote><p>When you identify a subdomain as core, you’re also saying something about the characteristics it needs to exhibit: high availability, strict consistency, zero tolerance for silent failure. It sits on the critical path, which means degradation there isn’t a footnote, it’s the whole experience collapsing. A supporting subdomain can be treated differently. You can serve stale data from a cache. You can hide that part of the experience gracefully behind a fallback. The system survives and the user barely notices.<br>Netflix is the example I always reach for. The catalogue and the video player are core. If you press play and nothing happens, Netflix has failed you. Those components need the highest availability, the most rigorous engineering attention, the least tolerance for shortcuts. Personalisation, the recommendations row, the &quot;because you watched&quot; logic, is supporting. If it serves yesterday’s model output, or quietly disappears behind a skeleton while the real data loads, the experience degrades slightly but the job is still done. You’re still watching something. The architectural characteristics assigned to each subdomain reflect that reality directly.<br>Apply this same classification to the question of how much automation you invite into a given area of the codebase, and the same logic extends naturally.<br>Generic subdomains are strong candidates for heavy AI automation. You’re building email verification or a file upload service. The requirements are well understood, the patterns are documented everywhere in training data, the stakes of an unconventional implementation are low. Let the agents build it. Review carefully, yes, but the cognitive investment you’d otherwise spend understanding every nuance of that implementation is probably better directed elsewhere.<br>Supporting subdomains sit in the middle. They have enough business context to reward human attention, but they’re not where your most senior engineers should be spending their deepest thinking. Graceful degradation is a design choice you can make deliberately, which means you have more room to move.<br>Core domains are different. This is the part of the system where shallow understanding is genuinely dangerous. If you don’t deeply understand the invariants in your core domain, an AI-generated shortcut that looks correct can silently violate a business rule that took years to encode correctly. The risk isn’t that the code is broken in an obvious way. It’s that it works in the happy path and fails in exactly the edge case where your business logic was doing something important. Back to the Netflix analogy: nobody forgives the player breaking. Everyone shrugs at a slightly off recommendation.<br>This is a more useful frame than &quot;trust AI&quot; or &quot;don’t trust AI.&quot; It’s about knowing which parts of your system are strategic, what properties those parts need to exhibit, and treating them accordingly. The comb-shaped developer understands their core domain deeply, can navigate supporting domains competently, and delegates confidently in generic territory because they know the difference, not just in terms of business value but in terms of the architectural commitments that flow from that classification.</p><h3>Cognitive load hasn’t gone away, it’s changed shape</h3><p>Here’s the part of the conversation with Matt and Mark that I keep coming back to. We used to spend a lot of energy worrying about context switching. Flow state. Deep work. The cost of an interruption when you’re in the middle of something complex. It felt like one of the defining challenges of knowledge work.</p><p>And then we all stopped talking about it. Not because it was solved. Because the nature of the problem shifted.</p><p>Agents don’t need a twenty-minute recovery period to remember where they were. They handle the context switching that used to tax individual developers. But the cognitive load hasn’t disappeared; it’s moved.<br><em>Running multiple agents in parallel introduces a different kind of cognitive demand.</em> <br>You’re no longer managing your own focus across a single deep task. You’re maintaining orientation across several parallel workstreams simultaneously, each of which is moving faster than any individual developer could.</p><p>This is qualitatively different from the old problem. Traditional context switching cost you the deep state you’d built up in your working memory. The new challenge is holding a coherent mental model of multiple in-flight pieces of work, understanding how they interact, knowing when one agent’s output creates a constraint or conflict for another. It’s less like switching between tasks and more like being an air traffic controller for code.</p><p>The cognitive load research we built methodologies around assumed a single human doing a single task deeply. That model is being replaced, and we don’t have equally good frameworks for what replaces it. We’re building them in real time, figuring out how much parallelism is useful before it becomes noise, what human-in-the-loop means when the loop is running at machine speed, and how to maintain coherence across a system that’s being constructed by distributed agents who each understand only a slice of it.</p><p>This is genuinely unsolved. The developers who figure it out first won’t necessarily be the ones with the deepest implementation knowledge. They’ll be the ones who can hold a system-level mental model while delegating the details, intervening with precision when something goes wrong, and knowing the difference between a problem worth correcting and one worth letting run.</p><h3>We’re still figuring this out</h3><p>There are no finished answers here. The tools are evolving every few weeks. The methodologies are provisional. What looks like a pattern today might look like a transitional curiosity in two years.</p><p>What does seem clear is that the SDLC as we’ve known it was designed for human constraints. Built around the fact that humans are slow, forget things, and need significant coordination overhead to synchronise. Agents don’t have most of those constraints. <br>So the question isn’t how to run the traditional SDLC faster with AI. The question is what the process looks like when the implementation layer is largely automated, and humans contribute primarily through intent, judgment, and architectural direction.</p><p>Startups will discover this faster than enterprises because they can. No legacy commitments, no compliance overhead, no accumulated technical decisions to route around. A small team working with AI-DLC principles from day one, with a codebase designed for AI comprehension from the start, already looks fundamentally different from how software teams have worked for the last two decades.</p><p>Enterprise is a different conversation entirely. The brownfield challenge is massive. The semantic context of a system accumulated over a decade lives partly in documentation, partly in commit history, and substantially in people’s heads. Architectural intent gets embedded in decisions nobody documented, in naming conventions that drifted over time, in coupling that exists because of a deadline five years ago. Agents don’t inherit any of that. The humans who need to direct them have to reconstruct and encode it first before automation can be applied safely. That’s architecture work regardless of the tooling involved, and it requires exactly the kind of multi-domain knowledge I’m describing.</p><p>The bigger questions don’t feel rhetorical to me.</p><blockquote>What does a healthy team look like when half the implementation is agent-generated?</blockquote><blockquote>How do you maintain genuine understanding of a codebase that nobody wrote entirely by hand?</blockquote><blockquote>What does owning a system mean when the agents that built parts of it are long gone?</blockquote><p>We’re not ready to answer those questions. But we’re getting close enough that we need to start asking them seriously, in team retrospectives, in architecture reviews, in the conversations about how we grow the next generation of developers in an environment where the things we used to test for are no longer the things that matter most.</p><p>Matt, Mark and I will keep the thread going. I suspect we’ll be chewing on this for a while yet.</p><p><em>What are you seeing in your own teams? Is the shape of what good looks like changing, or does it still feel mostly continuous with the past?<br>Curious where you are on this.</em></p><p>These are the kinds of questions I keep exploring in <strong>Token by Token</strong>, my newsletter on AI and the future of software development. If this resonated, you can subscribe at <a href="https://www.tokenbytoken.ai/">tokenbytoken.ai</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=69024bbb62d7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Agents don’t know what good looks like. And that’s exactly the problem.]]></title>
            <link>https://lucamezzalira.medium.com/agents-dont-know-what-good-looks-like-and-that-s-exactly-the-problem-ed31bf25583e?source=rss-9119c54d607d------2</link>
            <guid isPermaLink="false">https://medium.com/p/ed31bf25583e</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Luca Mezzalira]]></dc:creator>
            <pubDate>Wed, 25 Mar 2026 12:42:11 GMT</pubDate>
            <atom:updated>2026-04-06T21:48:07.754Z</atom:updated>
            <content:encoded><![CDATA[<p><em>A reaction to the Neal Ford and Sam Newman fireside chat on agentic AI and software architecture</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*w8aQP4ew7K33EztGe2gprA.png" /></figure><p>Every few years, something arrives that promises to change how we build software. And every few years, the industry splits predictably: one half declares the old rules dead, the other half folds its arms and waits for the hype to pass. Both camps are usually wrong, and both camps are usually loud. What’s rarer, and more useful, is someone standing in the middle of that noise and asking the structural questions: not what can this do, but what does it mean for how we design systems?</p><p>That’s what Neal Ford and Sam Newman do in their recent fireside chat on agentic AI and software architecture during the O’Reilly <a href="https://learning.oreilly.com/videos/software-architecture-superstream/0642572277543/">Architecture Superstream online event</a>. It’s a conversation worth pulling apart carefully, because some of what they surface is more uncomfortable than it first appears.</p><h3>The Dreyfus trap</h3><p>Neal opens with the <a href="https://www.bumc.bu.edu/facdev-medicine/files/2012/03/Dreyfus-skill-level.pdf">Dreyfus Model of Knowledge Acquisition</a>, originally developed for the nursing profession but applicable to any domain. The model maps learning across five stages:</p><ul><li><em>novice,</em></li><li><em>advanced beginner,</em></li><li><em>competent,</em></li><li><em>proficient,</em></li><li><em>expert</em></li></ul><p>His claim is that current agentic AI is stuck somewhere between novice and advanced beginner: it can follow recipes, it can even apply recipes from adjacent domains when it gets stuck, but it doesn’t <em>understand</em> why any of those recipes work. This isn’t a minor limitation. It’s structural.</p><p>The canonical example Neal gives is beautiful in its simplicity: an agent tasked with making all tests pass encounters a failing unit test. One perfectly valid way to make a failing test pass is to replace its assertion with <em>assert True</em>. That’s not a hack in the agent’s mind. It’s a solution. There’s no ethical framework, no professional judgment, no instinct that says <em>this isn’t what we meant</em>. Sam extends this immediately with something he’d literally seen shared on LinkedIn that week: an agent that had modified the build file to silently ignore failed steps rather than fix them. The build passed. The problem remained. Congratulations all round.</p><p>What’s interesting here is that neither Ford nor Newman are being dismissive of AI capability. The point is more subtle: the creativity that makes these agents genuinely useful, their ability to search solution space in ways humans wouldn’t think to, is inseparable from the same property that makes them dangerous. You can’t fully lobotomise the improvisation without destroying the value. This is a design constraint, not a bug to be patched.</p><p>And when you zoom out, this is part of a broader signal. When experienced practitioners who’ve spent decades in this industry independently converge on calls for restraint and rigour rather than acceleration, that convergence is worth paying attention to. It’s not pessimism. It’s pattern recognition from people who’ve lived through enough cycles to know what the warning signs look like.</p><h3>Behaviour vs. Capabilities</h3><p>One of the most important things Neal says, and I think it gets lost in the overall density of the conversation, is the distinction between <em>behavioural verification</em> and <em>capability verification</em>.</p><p>Behavioural verification is what most teams default to: unit tests, functional tests, integration tests. Does the code do what it’s supposed to do according to the spec? This is the natural fit for agentic tooling, because agents are actually getting pretty good at implementing behaviour against specs. Give an agent a well-defined interface contract and a clear set of acceptance criteria, and it will produce something that broadly satisfies them. This is real progress.</p><p>Capability verification is harder. Much harder. Does the system exhibit the operational qualities it needs to exhibit at scale? Is it properly decoupled? Is the security model sound? What happens at 20,000 requests per second? Does it fail gracefully or catastrophically? These are things that most human developers struggle with too, and agents have been trained on human-generated code, which means they’ve inherited our failure modes as well as our successes.</p><p>This brings me to something Birgitta Boeckeler raised at QCon Software Development Conferences London that I haven’t been able to stop thinking about. The example everyone cites when making the case for AI’s coding capability is that Anthropic built a C compiler from scratch using agents. Impressive. But here’s the thing: C compiler documentation is extraordinarily well-specified, battle-tested over decades, and the test coverage for compiler behaviour is some of the most rigorous in the entire software industry. That’s as close to a solved, well-bounded problem as you can get.</p><p>Enterprise software is almost never like that. Enterprise software is ambiguous requirements, undocumented assumptions, tribal knowledge living in the heads of people who left three years ago, and test coverage that exists more as aspiration than reality. The gap between “can build a C compiler” and “can reliably modernise a legacy ERP” is not a gap of raw capability. It’s a gap of specification quality and domain legibility. That distinction matters enormously for how we think about where agentic tooling can safely operate.</p><p>The current orthodoxy in agentic development is to throw more context at the problem: elaborate context files, architecture decision records, guidelines, rules about what not to do. Ford and Newman are appropriately sceptical. Sam makes the point that there’s now empirical evidence suggesting that as context file size increases, you see degradation in output quality, not improvement. You’re not guiding the agent toward better judgment. You’re just accumulating scar tissue from previous disasters. This isn’t unique to agentic workflows either. Anyone who has worked seriously with code assistants knows that summarisation quality degrades as context grows, and that this degradation is only partially controllable. That has a direct impact on decisions made over time, now close your eyes for a moment and imagine doing it across an enterprise software, with many teams across different timezones. Don’t get me wrong, the tools help, but the help is bounded, and that boundary is often closer than we’d like to admit.</p><p>The more honest framing, which Neal alludes to, is that we need <em>deterministic guardrails</em> around <em>non-deterministic agents</em>. Not more prompting. Architectural fitness functions, an idea Ford and Rebecca Parsons have been promoting since 2017, feel like they’re finally about to have their moment, precisely because the cost of not having them is now immediately visible.</p><h3>What should an agent own then?</h3><p>This is where the conversation gets most interesting, and where I think the field is most confused.</p><p>There’s a seductive logic to the microservice as the unit of agentic regeneration. It sounds small. The word <em>micro</em> is in the name. You can imagine handing an agent a service with a defined API contract and saying: implement this, test it, done. The scope feels manageable.</p><p>Ford and Newman give this idea fair credit, but they’re also honest about the gap. The microservice level is attractive architecturally because it comes with an implied boundary: a process boundary, a deployment boundary, often a data boundary. You can put fitness functions around it. You can say this service must handle X load, maintain Y error rate, expose Z interface. In theory.</p><p>In practice, we barely enforce this stuff ourselves. The agents have learned from a corpus of human-written microservices, which means they’ve learned from the vast majority of microservices that were written without proper decoupling, without real resilience thinking, without any rigorous capacity planning. They don’t have our aspirations. They have our habits.</p><p>The deeper problem, which Neal raises and which I think deserves more attention than it gets, is <em>transactional coupling</em>. You can design five beautifully bounded services and still produce an architectural disaster if the workflow that ties them together isn’t thought through. Sagas, event choreography, compensation logic: this is the stuff that breaks real systems, and it’s also the stuff that’s hardest to specify, hardest to test, and hardest for an agent to reason about. We made exactly this mistake in the SOA era. We designed lovely little services and then discovered that the interesting complexity had simply migrated into the integration layer, which nobody owned and nobody tested.</p><p>Sam’s line here is worth quoting directly, roughly: <em>to err is human, but it takes a computer to really screw things up</em>. I suspect we’re going to produce some genuinely legendary transaction management disasters before the field develops the muscle memory to avoid them.</p><h3>The socio-technical gap nobody is talking about</h3><p>There’s a dimension to this conversation that Ford and Newman gesture toward but that I think deserves much more direct examination: <em>the question of what happens to the humans on the other side of this generated software.</em></p><p>It’s not completely accurate to say that all agentic work is happening on greenfield projects. There are tools already in production helping teams migrate legacy ERPs, modernise old codebases, and tackle the modernisation challenge that has defeated conventional approaches for years. That’s real, and it matters.</p><p>But the challenge in those cases isn’t merely the code. It’s whether the socio-technical system, the teams, the processes, the engineering culture, the organisational structures built around the existing software, is ready to inherit what gets built. And here’s the thing: even if agents combined with deterministic guardrails could produce a well-structured microservice architecture or a clean modular monolith in a fraction of the time it would take a human team, that architectural output doesn’t automatically come with organisational readiness. The system can arrive before the people are prepared to own it.</p><p>One of the underappreciated functions of iterative migration, the incremental strangler-fig approach, the slow decomposition of a monolith over eighteen months, is not primarily risk reduction, though it does that too. It’s learning. It’s the process by which a team internalises a new way of working, makes mistakes in a bounded context, recovers, and builds the judgment that lets them operate confidently in the new world. Compress that journey too aggressively and you can end up with architecture whose operational complexity exceeds the organisational capacity to manage it. That gap tends to be expensive.</p><p>At QCon London, I asked Patrick Debois, after a talk covering best practices for AI-assisted development, whether applying all of those practices consistently would make him comfortable working on enterprise software with real complexity. His answer was: it depends. That felt like the honest answer. The tooling is improving. Whether the humans around it are keeping pace is a separate question, and one the industry is not spending nearly enough time on.</p><h3>Existing systems</h3><p>Ford and Newman close with a subject that almost never gets covered in these conversations: the vast, unglamorous majority of software that already exists and that our society depends on in ways that are easy to underestimate.</p><p>Most of the discourse around agentic AI and software development is implicitly greenfield. It assumes you’re starting fresh, that you get to design your architecture sensibly from the beginning, that you have clean APIs and tidy service boundaries. The reality is that most valuable software in the world was written before any of this existed, runs on platforms and languages that aren’t the natural habitat of modern AI tooling, and contains decades of accumulated decisions that nobody fully understands anymore.</p><p>Sam is working on a book about this: how to adapt existing architectures to enable AI-driven functionality in ways that are actually safe. He makes the interesting point that existing systems, despite their reputation, sometimes give you a head start. A well-structured relational schema carries implicit meaning about data ownership and referential integrity that an agent can actually reason from. There’s structure there, if you know how to read it.</p><p>The general lesson, which he states without much drama, is that you can’t just expose an existing system through an MCP server and call it done. The interface is not the architecture. The risks around security, data exposure, and vendor dependency don’t go away because you’ve wrapped something in a new protocol.</p><p>This matters more than it might seem, because the software that runs our financial systems, our healthcare infrastructure, our logistics and supply chains, is not greenfield and never will be. If we get the modernisation of those systems wrong, the consequences are not abstract. They are social. The instinct to index heavily on what these tools can do in ideal conditions, on well-specified problems with good documentation and thorough test coverage, is understandable. But it’s exactly the wrong instinct when the systems in question are the ones our lives depend on. The architectural mindset that has served us well through previous paradigm shifts, the one that starts with trade-offs rather than capabilities, that asks what we are giving up rather than just what we are gaining, is not optional here. It’s the minimum requirement for doing this responsibly.</p><h3>What I take away from this</h3><p>Three things, mostly.</p><p>The first is that introducing deterministic guardrails into non-deterministic systems is not optional. It’s imperative. We are still figuring out exactly where and how, but the framing needs to shift: the goal is control over <em>outcomes</em>, not just oversight of <em>output</em>. There’s a difference. Output is what the agent generates. Outcome is whether the system it generates actually behaves correctly under production conditions, stays within architectural boundaries, and remains operable by the humans responsible for it. Fitness functions, capability tests, boundary definitions: the boring infrastructure that connects generated code to the real constraints of the world it runs in. We’ve had the tools to build this for years.</p><p>The second is that the people saying this is the future and the people saying this is just another hype cycle are both probably wrong in interesting ways. Ford and Newman are careful to say they don’t know what good looks like yet. Neither do I. But we have better prior art to draw on than the discourse usually acknowledges. The principles that made microservices work, when they worked, real decoupling, explicit contracts, operational ownership, apply here too. The principles that made microservices fail, leaky abstractions, distributed transactions handled badly, complexity migrating into integration layers, will cause exactly the same failures, just faster and at larger scale.</p><p>The third is something I took away from QCon London this year, and I think it might be the most important of the three. Across two days of talks, including sessions that took diametrically opposite approaches to integrating AI into the software development lifecycle, one thing became clear: we are all beginners. Not in the dismissive sense, but in the most literal application of the Dreyfus model. Nobody, regardless of experience, has figured out the right way to fit these tools inside a socio-technical system. The recipes are still being written. The war stories that will eventually become the prior art are still happening to us right now.</p><p>What got us here, collectively, was sharing what we saw, what worked, what failed, and why. That’s how the field moved from SOA disasters to microservices best practices. That’s how we built a shared vocabulary around fitness functions and evolutionary architecture. The same process has to happen again, and it will, but only if people with real experience are honest about the uncertainty rather than performing confidence they don’t have. The speed, ultimately, is both the opportunity and the danger. The technology is moving faster than the organisations, the teams, and the professional instincts that need to absorb it. The best response to that isn’t to pretend otherwise. It’s to keep comparing notes.</p><p><em>If this resonated, the </em><a href="https://learning.oreilly.com/videos/software-architecture-superstream/0642572277543/"><em>full fireside chat between Neal Ford and Sam Newman is worth watching in its entirety</em></a><em>. They cover more ground than I’ve had space to react to here.</em></p><p>These are the kinds of topics I keep exploring in <strong>Token by Token</strong>, my newsletter on AI and the future of software development. If this resonated, you can subscribe at <a href="https://www.tokenbytoken.ai/">tokenbytoken.ai</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ed31bf25583e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Global state in micro-frontends? No thanks!]]></title>
            <link>https://lucamezzalira.medium.com/global-state-in-micro-frontends-no-thanks-942f6f7b5c36?source=rss-9119c54d607d------2</link>
            <guid isPermaLink="false">https://medium.com/p/942f6f7b5c36</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[architecture]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[front-end-development]]></category>
            <dc:creator><![CDATA[Luca Mezzalira]]></dc:creator>
            <pubDate>Thu, 11 Dec 2025 10:57:17 GMT</pubDate>
            <atom:updated>2025-12-11T10:57:17.813Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FzTaROLaaN-UKZEOSiMYQQ@2x.png" /></figure><p>If there is one architectural trap that consistently derails micro-frontend initiatives, it’s the temptation to introduce a global state “to make things easier.” On the surface, it seems harmless: share a user object, expose a few configuration values, maybe allow feature flags or business data to flow across boundaries. But the moment a global state enters the picture, boundaries begin to blur, autonomy starts to erode, and the system slowly shifts back toward the very characteristics micro-frontends were created to escape.</p><p>Micro-frontends thrive on independence, strong domain ownership, and clear separation of responsibilities. Global state undermines all three. It creates a hidden layer of shared knowledge that every team must now understand, respect, and protect. It introduces coordination where there shouldn’t be any. It magnifies the blast radius of mistakes. And when something goes wrong, the failure is no longer contained inside a bounded context but it ripples across the entire system.</p><p>The irony is that, in most cases, global state is introduced not because of a genuine architectural need, but because of convenience. Teams feel the friction of duplication or explicit communication and interpret that friction as a problem rather than a signal of misaligned domain boundaries. But micro-frontends make that friction visible on purpose. It’s the architectural mechanism that reveals where domains are leaking and where responsibilities are blending.</p><p>This article is about that hidden danger. Not the obvious technical challenges, but the structural, organizational, and now even AI-driven dynamics that make global state the single most corrosive decision you can make in a micro-frontend architecture.</p><h3>Where It Starts: The Application Shell as a Temptation</h3><p>The application shell is where micro-frontends are wired together, where routes are resolved, and where initial configuration is loaded. Because of this central role, it becomes the natural candidate for storing cross-cutting information. Teams look at the shell and assume it is the neutral layer, detached from any domain, and therefore ideal for keeping shared values.</p><p>The reasoning is understandable, but it is based on a misconception. The shell is not a domain container. It is an infrastructural actor whose purpose is orchestration, not business logic. The moment you introduce global state, you shift its identity from an operational layer to a knowledge layer. This shift is subtle, but enormously consequential. It changes the shell from something stable and predictable into something volatile and domain-aware. From that point onward, every additional property added to the global object expands this volatility and increases the surface area of risk.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_7NlQc2vRWSXftC0" /></figure><p>Global state in micro-frontends? No thanks!</p><h3>When Global State Becomes a Magnet for Domain Leakage and the Slow Collapse of Independence</h3><p>The most dangerous effect of global state is not technical, but behavioural. Once a shared object exists, teams begin to treat it as a shortcut. A new promotion toggle needs to be read by the product page and the checkout, so someone adds it to the global state. A small hint about user preferences would simplify logic between two micro-frontends, so it ends up there as well. Perhaps a piece of contextual information seems convenient to share “for now”, and it too becomes part of the global object.</p><p>None of these decisions feels consequential in isolation, but their accumulation is catastrophic. Each addition leaks domain knowledge into the shell. The shell now knows things it should never know, understands concepts that belong to specific teams, and exposes those concepts to the entire application whether they are needed or not. What began as a convenience becomes an unintentional broadcast system for domain information.</p><p>As more domain data enters the shell, every micro-frontend becomes dependent on it, even indirectly. Developers start assuming that the global state will provide what they need, and in doing so, they silently bind their micro-frontends to an external contract. When the shape or meaning of this shared state inevitably changes, micro-frontends break, either subtly or catastrophically. Teams must coordinate releases, test integrations they do not own, and delay deployments until everyone is aligned. Autonomy disappears. Releases slow down. Bugs become more cross-cutting and harder to diagnose. The architecture begins to resemble a distributed monolith rather than a collection of independent, domain-focused components.</p><p>This collapse does not happen overnight. It is the slow, cumulative consequence of small decisions made under pressure, each one eroding the boundary between domains. Global state acts as the shared database of the frontend world, and as with shared databases in microservices, it introduces tight coupling, widespread fragility, and an unavoidable need for synchronised deployment cycles. Independence dies gradually, but inevitably.</p><h3>A New Risk in the AI Era: How Global State Multiplies Mistakes From Vibe Coding</h3><p>The problem becomes even more pronounced in the era of AI-assisted development. Tools that accelerate coding through pattern completion, “vibe coding”, or natural language prompts are incredibly powerful, but they also amplify whatever architectural foundations exist beneath them. If the foundation includes a global state, AI models naturally discover and use it as the easiest path for sharing information between components. This is not malice, it is simply statistical optimisation: the AI learns that the global object is already there and concludes that placing new behaviours or new properties onto it is the fastest way to satisfy your prompt.</p><p>In a monorepo environment, where every micro-frontend coexists within the same codebase, the risk multiplies. Boundaries that were once protected through physical separation become permeable. AI systems trained on the repository’s patterns may start inserting domain-specific hints or mutations directly into the global state. A developer might ask for a new feature in a specific domain, but the AI, seeing a convenient shared object, extends or mutates that object instead of localising the state inside the micro-frontend where it belongs. This creates a silent architectural drift: domain logic leaks into the shell not through deliberation, but through automated suggestion and developer assist.</p><p>The result is an architecture that degrades faster than ever before. Instead of months or years of slow accumulation, global state accelerates coupling at machine speed. You end up with a system where AI “helpfully” threads micro-frontends together through a shared object, turning an intended distributed architecture into an implicit monolith. What used to require a human decision now happens automatically, invisibly, and continuously. In this environment, global state is not just a bad idea, it is a structural vulnerability. It creates an attractor for accidental coupling, for misplacement of logic, and for cross-domain interactions that should never occur. The AI is not breaking your architecture — your architecture is inviting the AI to misuse it.</p><h3>The Unnecessary Governance Burden Nobody Sees Coming</h3><p>One of the most misunderstood aspects of global state is the governance burden it introduces. Developers often assume the difficulty lies only in implementing the shared object, but the real complexity appears afterwards. The moment you centralise mutable data, you create a shared dependency that requires rules, versioning, negotiation, and continuous management.</p><p>Whenever a team proposes a change, they must consider whether existing micro-frontends rely on that property, how older versions behave, what happens if two teams mutate the same field differently, and who will maintain compatibility when the object evolves. This kind of coordination is expensive, not just technically but organisationally. It requires cross-team discussions, shared documentation, contract management, test strategies that cover multiple independently deployed artifacts, and a collective understanding of the state surface.</p><p>The irony is that none of this governance was necessary. It is self-inflicted. It stems from a single choice made for convenience rather than design. Teams rarely foresee the cascade of consequences. They see a global object and think it will make their life easier, but it instead introduces a systemic dependency that forces operational overhead they never intended to shoulder. Most organisations do not want to run a state governance board, yet global state forces them into that role. It adds bureaucracy where no bureaucracy should exist, and friction in a place that should remain lean and predictable. This is not a viable option, it is a trap.</p><h3>The Right Alternative: A Simple Immutable Configuration Object</h3><p>Instead of issuing a global state, the application shell should expose a minimal configuration object. This configuration is fetched from an API at startup and contains only infrastructural values: environment metadata, asset prefixes, static feature flags, and other stable, non-domain values that all micro-frontends legitimately need to access. Crucially, this object should be immutable.</p><p>JavaScript provides a reliable way to enforce immutability:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ecYX8JfXpD62l3_n" /></figure><p>an example of configuration you want to share across multiple micro-frontends</p><p>Object.freeze ensures that no new properties can be added, no existing properties can be removed, and no values can be modified. This simple choice prevents accidental mutations and guarantees that the configuration remains predictable throughout the lifecycle of the application. Micro-frontends can read the values, but they cannot change them, and therefore cannot influence one another in unintended ways. And while it is technically possible to freeze a global state object as well, the question becomes: why introduce an external library to manage global state if you are not supposed to use any of its mutating or state-management capabilities in the first place? Relying on a shared dependency for something as simple as immutable configuration is not only unnecessary, it is counterproductive.</p><p>Vanilla JavaScript gives you all the tools you need to enforce immutability without polluting the shell with a library whose presence encourages developers, and increasingly AI assistants, to treat it as a legitimate place to store or manipulate shared state.</p><p>The result of using a simple frozen configuration object is an architecture where the shell remains a stable foundation rather than a mutable risk surface, and where the absence of global state libraries reinforces, rather than undermines, the boundaries that make micro-frontends actually independent.</p><h3>Encapsulation: The Architectural Principle at Stake</h3><p>Behind all of this lies a fundamental architectural principle: encapsulation.</p><p>Micro-frontends exist to keep data and behaviour together, not dispersed, not shared implicitly, and certainly not centralised in a place with no domain responsibility. When a micro-frontend owns a capability, it must also own its state. When it owns its state, it becomes independently deployable.</p><p>Global state breaks this principle instantly. It separates data from behaviour. It relocates ownership to a place where it does not belong. It forces micro-frontends to depend on a shared external contract rather than their own logic. And in doing so, it destroys the very autonomy that micro-frontends were created to provide.</p><p>This is the same pattern seen in microservices that share a database. The services may be separate in code, but they remain coupled at the data layer, forcing coordinated deployments and shared operational concerns. Micro-frontends bound by global state fall into precisely the same trap. They lose independence not because of their UI boundaries, but because of their hidden data dependencies.</p><h3>Global State is an Anti-Pattern</h3><p>Global state inside the application shell is not a shortcut, it is a long-term liability. It creates domain leakage, collapses independence, introduces unnecessary governance, and transforms the shell into a brittle, domain-aware bottleneck. The alternative is both simpler and healthier: a minimal, immutable configuration object, domain-specific state owned by each micro-frontend, and strict adherence to encapsulation principles.</p><p>If your goal is to build micro-frontends that scale, evolve, and operate independently, removing global state is not optional. It is essential. Boundaries matter, ownership matters, autonomy matters, and global state undermines all three. Avoid it deliberately, avoid it consistently, and your architecture will remain resilient, principled, and responsive for years to come.</p><p>Want to go even deeper? Check out my book <em>Building Micro-Frontends</em>, where I cover patterns, anti-patterns, and best practices for real-world distributed frontend architectures: <a href="https://www.buildingmicrofrontends.com/book">https://www.buildingmicrofrontends.com/book</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=942f6f7b5c36" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How I use AI to set the right guardrails]]></title>
            <link>https://lucamezzalira.medium.com/how-i-use-ai-to-set-the-right-guardrails-4543aa84df84?source=rss-9119c54d607d------2</link>
            <guid isPermaLink="false">https://medium.com/p/4543aa84df84</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[microservices]]></category>
            <dc:creator><![CDATA[Luca Mezzalira]]></dc:creator>
            <pubDate>Tue, 24 Jun 2025 09:50:28 GMT</pubDate>
            <atom:updated>2025-06-24T09:50:28.361Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QSwcge6iDVSh4hCbQkaDNA.jpeg" /><figcaption>AI can help you with your automation tasks</figcaption></figure><p>Scaling micro-frontends sounds great on paper: modularity, autonomy, independent deployments. But once you’re past the excitement of the initial setup, reality kicks in. Things start to become more challenging, not because your teams aren’t skilled, but because no one really thought about the cross-cutting concerns.</p><p>I’ve seen this happen in micro-frontends, backend services, and any distributed system where multiple teams move fast in parallel. The issues show up between the modules: dependency drift, performance inconsistencies, architectural erosion. And without guardrails, those small misalignments compound quickly.</p><p>Whether at DAZN or working with some of the largest Fortune 500 companies in the world, the story is often the same: it’s not the components or the build that slow you down but lack governance.</p><p>That’s why I started putting in place simple, practical guardrails, things that help teams move fast without breaking architecture or user experience. And now, with AI code assistants in the mix, setting up those controls is faster than ever. You don’t need a full platform team to enforce good practices — you just need the right approach and a bit of guidance.</p><h3>Challenges with distributed systems</h3><p>Cross-cutting concerns get overlooked in the early days and become painful later. I’d argue rightly so, because there are many moving parts and changes to embrace fully in the journey towards a distributed system. However at some point, friction will arise and I found the most common ones are:</p><h3>1. Dependency management</h3><p>In distributed systems, even updating a shared library can become a nightmare. You often need to touch multiple projects, trigger new builds, and redeploy apps one by one. If you skip updates, your performance suffers. If you rush them, something breaks. Without automation and visibility, keeping dependencies up to date becomes a time sink — and a silent liability.</p><h3>2. Architectural drift</h3><p>You start with a clean architecture, well-defined boundaries, and clear ownership. But over time, those lines blur. Especially when multiple teams are involved. People import things they shouldn’t, violate layering, or reimplement logic because they can’t find the shared version. In monorepos or not, architectural erosion is real. And without clear enforcement and visibility, your system gradually becomes harder to evolve.</p><h3>3. Performance</h3><p>Everyone agrees performance matters, but when it’s shared across many teams, it’s easy for no one to own it. You end up with bloated bundles, inconsistent loading strategies, or duplicated dependencies — all of which hurt the user experience. Having performance budgets and checks is critical, but they need to be visible, automated, and easy to enforce without blocking progress.</p><h3>What I’ve Learned from the Trenches</h3><p>These challenges aren’t hypothetical, I’ve seen them play out in real systems, with real teams, under real pressure. At DAZN, where we built micro-frontends, we implemented some of these guardrails. They weren’t glamorous, but they made a difference.</p><p>But DAZN is just one story. Over the past few years, I’ve had the chance to work with hundreds of teams across the world — from fast-growing startups to Fortune 500 enterprises. No matter the industry or tech stack, the same problems kept surfacing: untracked dependencies, blurred boundaries, performance slowly degrading over time. The symptoms were different, but the root causes were always the same: distributed ownership without shared constraints.</p><p>That’s where practical guardrails come in.</p><p>And now that AI code assistants are part of the workflow, setting up and maintaining those guardrails has become dramatically easier. You still need to think critically and guide the design, but the heavy lifting can be shared. That’s what this next section is about.</p><h3>Enforcing design decisions</h3><p>In distributed systems, architecture tends to erode not because of big decisions — but because of small, unintentional shortcuts. A teammate imports a component from the wrong domain. Someone reaches into a shared folder without realizing the coupling they’re introducing. Over time, the architecture you designed slowly unravels.</p><p>That’s why I use ts-arch: a simple but powerful tool that allows you to turn your architectural intent into automated, testable rules. In the nextjs-mfes-containers repo, for example, I apply this to the catalog micro-frontend to ensure it remains isolated and aligned with the overall system design.</p><p>Here’s what I enforce:</p><ul><li>The catalog domain must not depend on home or account.</li><li>shared components must remain generic and must not depend on catalog.</li><li>The catalog zone must remain free of dependency cycles.</li></ul><p>All of this is captured in a single test suite that is clear, repeatable, and versioned like the rest of your code. It’s simple to write and even simpler to maintain.</p><p>With AI code assistants, I now scaffold these rules faster. I describe the architectural zones (e.g. “catalog shouldn’t know about account”) and the assistant generates the assertions using ts-arch.</p><p>When a rule fails, you have options: you can block the CI/CD pipeline to prevent the change from being merged, or simply notify the owning team and track the violation. Sometimes, as architects, we knowingly make trade-offs — maybe to hit a delivery milestone — but what matters is acknowledging those deviations and circling back to restore the intended architecture. Guardrails only work if they’re respected, revisited, and part of the team’s shared accountability.</p><h3>Keeping performance in check</h3><p>In micro-frontends each team is independent and it focuses on their feature, but when the pieces come together, users face the cost: bloated bundles, slow load times, or duplicated code. Performance needs to be a shared responsibility, not an afterthought.</p><p>To make this actionable, I define performance budgets at the micro-frontend level. In the <a href="https://github.com/lucamezzalira/nextjs-mfes-containers">example repo</a>, I use a tool called size-limit to set thresholds on build artifacts — like ensuring the main JavaScript bundle stays within a defined loading time. These checks can run during pull requests, pre-push hooks, or CI/CD workflows to create a fast feedback loop for developers.</p><p>AI code assistants make this even easier. Once you describe your budget — say, “warn if this app’s main bundle takes longer than 1 second to load” — they can generate the config, integrate it into your pipeline, and even flag parts of the codebase that might benefit from lazy loading or better chunking. Most modern bundlers now support similar approaches, so whatever your setup, this kind of shift-left performance check is well within reach.</p><h3>Managing dependencies</h3><p>One of the trickiest parts of maintaining distributed frontends is managing dependencies — both public and internal. When you’re dealing with multiple independently deployed micro-frontends, keeping packages aligned isn’t just a hygiene issue. It’s about performance, security, and avoiding regressions caused by uncoordinated upgrades but also consistency in certain scenarios.</p><p>In large-scale systems I’ve worked on, dependency drift has caused all kinds of friction. Updates to design systems, shared utilities, or even a critical patch in a public library often get delayed because each team has to update manually, test locally, and redeploy. The result? Slow rollouts, version mismatches, and missed performance gains.</p><p>In the nextjs-mfes-containers repo, I demonstrate how to configure <a href="https://github.com/lucamezzalira/nextjs-mfes-containers/blob/main/.github/dependabot.yml">Dependabot</a> to automate this process across internal and external packages. You can set it up to watch all package.json files, including shared packages and internal design systems published to private registries. The key is to define a reasonable schedule and grouping strategy — so teams aren’t bombarded with noise, but are still nudged to keep things up to date.</p><p>This is where AI steps in again. Rather than digging through documentation, I describe the setup I need (“check all MFEs in the monorepo for outdated dependencies, including private packages from our design system”) and let the assistant scaffold the YAML config for Dependabot or similar tools. It reduces the effort required to set it up — and more importantly, makes maintenance sustainable over time.</p><h3>Understanding the landscape: DIY vs. off-the-shelf solutions</h3><p>There’s no shortage of tools and platforms aiming to simplify managing micro-frontends and distributed systems. Solutions like <a href="http://bit.dev/">Bit.dev</a>, Zephyr, Piral, and Vercel offer varying degrees of automation and governance out of the box.</p><p>These platforms can dramatically reduce manual effort and speed up delivery, especially at scale. But it’s important to remember: before you adopt any tool, you should understand the underlying challenges and controls. Building these guardrails yourself — even at a basic level — gives you deep insight into the trade-offs, lets you tailor policies to your context, and empowers you to evaluate third-party offerings critically.</p><p>The approach I shared leveraging AI, helps define and automate architecture rules, performance budgets, and dependency management. A simple yet effective framework that will be your foundation. Once it’s done, you can confidently decide whether to extend it with a commercial platform or keep evolving your custom setup.</p><h3>Summary</h3><p>Managing distributed frontend systems is complex, but setting the right guardrails can make all the difference. Leveraging AI assistants to scaffold and maintain these guardrails accelerates adoption and frees you to focus on higher-level design and collaboration. While many commercial platforms offer baked-in governance, understanding the fundamentals empowers you to make smarter decisions tailored to your context.</p><p>If you want to dive deeper into these strategies and see more real-world examples, I invite you to check out my <a href="https://amzn.to/466xFAM">upcoming book “Building Micro-Frontends — 2nd edition”</a> (now available for pre-order) and subscribe to my newsletter at <a href="http://buildingmicrofrontends.com/">buildingmicrofrontends.com</a>.</p><p>Most importantly, did you find any other guardrail that you were able to spin up quickly with AI? Feel free to share your experiences or questions about using AI and guardrails in distributed architectures. Looking forward to hear from you!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4543aa84df84" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A practical playbook for working with AI code assistants]]></title>
            <link>https://lucamezzalira.medium.com/a-practical-playbook-for-working-with-ai-code-assistants-6cd5127946cd?source=rss-9119c54d607d------2</link>
            <guid isPermaLink="false">https://medium.com/p/6cd5127946cd</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[generative-ai-tools]]></category>
            <category><![CDATA[tech]]></category>
            <dc:creator><![CDATA[Luca Mezzalira]]></dc:creator>
            <pubDate>Mon, 23 Jun 2025 12:51:08 GMT</pubDate>
            <atom:updated>2025-06-23T12:51:08.400Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7TPi3dMmCz8-xk56tF4raw.png" /><figcaption>My playbook to work with AI code assistants</figcaption></figure><p>Over the past 10 months, I’ve used AI assistants to speed up how I prototype, design, and reason about frontend systems. They’ve drastically improved how quickly I can build proofs of concept — what used to take hours now takes minutes. But they don’t magically understand context, intent, or architecture. I use to define them with the knowledge of wikipedia but the skills of a junior/mid developer.</p><p>I treat the assistant’s output as a starting point, something I’ll review, adjust, and refine just like I would if another engineer had written it. That means I’m constantly checking for things the model misses: subtle architectural rules, shared contracts, naming conventions, or performance trade-offs that it simply doesn’t grasp. Sometimes is my prompt’s fault, sometimes is not.</p><p>The result? I move faster, but I have to stay in control. AI becomes a force multiplier because I invest in reviewing and iterating on its output. It’s not magic. It’s a collaboration. And like any collaboration, the quality depends on how clearly you communicate and how seriously you take the review process.</p><p>Based on what I’ve learned over the past eight months, I’ve developed a practical playbook I now apply every time, a set of principles and patterns that help me use AI assistants as reliable collaborators across every stage of architectural design and frontend development.</p><h3>1. Start with intent, not just code</h3><p>Too many developers treat AI like an oracle: “Generate a login page” or “Build me X.” The result? Generic code, bloated logic, and brittle coupling. In distributed frontend systems, you’re juggling boundaries, contracts, and team ownership. If your intent isn’t clear, the AI will fill in the blanks — often incorrectly.</p><p>Define your goal in terms of:</p><ul><li>What the code should do</li><li>The context it lives in</li><li>The boundaries it must respect</li></ul><p>Write this down in a Markdown file. Point your assistant to it when needed. This helped me saving time and get the result I wanted.</p><h3>2. Give AI the context it needs</h3><p>AI doesn’t “remember” like humans. Without proper context, it will guess based on common patterns and not your architecture or design decisions.</p><p>Context is your responsibility. Especially in a micro-frontend setup where small mistakes break boundaries.</p><p>Remember to:</p><ul><li>Describe your stack, folder structure, and conventions.</li><li>Reference markdown files with shared decisions.</li><li>Reuse context blocks across prompts.</li></ul><h3>3. Decide for the right plan</h3><p>When I’m about to implement a feature or refactor part of the system, I don’t jump straight into prompting AI for code. Instead, I use it as a thinking partner from the beginning. I start by describing what I’m trying to achieve and ask the assistant to prepare a plan. This gives me something to react to and I got in exchange a concrete proposal I can refine.</p><p>From there, I iterate on the plan with the assistant. I ask it to consider design principles, architectural boundaries, performance trade-offs, and any constraints that apply to the system. We go back and forth until the plan aligns with how I would approach the problem myself. Only after we’ve reached that point do I ask it to act on the plan and start generating code.</p><p>This approach not only leads to better technical outcomes, it also helps me stay in control of the direction. AI becomes part of the design process, not a shortcut around it. And in complex systems like micro-frontends, that clarity upfront makes a huge difference later on.</p><h3>4. Think like a Developer</h3><p>After we have a solid plan, I never let AI try to solve the whole problem in one go. Instead, I treat it like a teammate helping me build incrementally. I break the work down into small, focused tasks and ask the assistant to handle them one at a time.</p><p>This approach mirrors how any careful developer works — tackling manageable chunks, validating each part before moving on. I start with the simplest building block, review the output, then move to the next. If something isn’t quite right, I feed that back and refine before proceeding. This back-and-forth keeps the code clean, maintainable, and aligned with the architecture.</p><h3>5. Automate the boring stuff</h3><p>AI isn’t just for writing code. It’s powerful for automating governance and developer workflows across micro-frontends. You know all those tasks that are often overlooked because “I don’t have time”?</p><p>A few ideas I applied with micro-frontends:</p><ul><li>Dependency management: “Create a Dependabot config to check all package.json files weekly…”</li><li>Architecture rules: “Write a ts-arch test preventing /apps/public-site from importing /shared/auth…”</li><li>Bundle size checks: “Fail the push if /apps/profile’s bundle exceeds 200kb…”</li><li>CI workflows: “Create a GitHub Actions pipeline that lints, tests, and runs bundle size checks for all MFEs in parallel…”</li></ul><p>In all of these, AI acts as your DevOps co-pilot. It saves you hours — and enforces architecture at scale.</p><h3>Final Thoughts</h3><p>AI can significantly speed up how we build and prototype, but it requires a disciplined approach to be truly effective. The key is to treat AI as a collaborator that helps you think through problems, draft plans, and write code incrementally — not as a tool to deliver finished solutions out of the box. By investing time in guiding AI with clear context, iterating on plans, and reviewing every output carefully, you maintain control over quality and architectural integrity.</p><p>This playbook reflects my experience with AI so far, I have even more steps I’m testing out in the past weeks, but I want to continue testing them before sharing them publicly.</p><p>With the right process, AI can help you deliver faster without sacrificing maintainability or design standards. It’s about working smarter, not just faster.</p><p>If you’re experimenting with AI in your development workflow, I’d love to hear your experiences and lessons learned. Share tips so we can all improve how we collaborate with AI and build better software together 😁</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6cd5127946cd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Your monolith isn’t broken. But it’s slowing you down!]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://lucamezzalira.medium.com/your-monolith-isnt-broken-but-it-s-slowing-you-down-fcf0a2f12662?source=rss-9119c54d607d------2"><img src="https://cdn-images-1.medium.com/max/1920/1*wU3ZPi29We1Vmr-sdHJbzQ.png" width="1920"></a></p><p class="medium-feed-snippet">Before jumping into a migration, it&#x2019;s crucial to be clear about why you&#x2019;re considering micro-frontends in the first place.</p><p class="medium-feed-link"><a href="https://lucamezzalira.medium.com/your-monolith-isnt-broken-but-it-s-slowing-you-down-fcf0a2f12662?source=rss-9119c54d607d------2">Continue reading on Medium »</a></p></div>]]></description>
            <link>https://lucamezzalira.medium.com/your-monolith-isnt-broken-but-it-s-slowing-you-down-fcf0a2f12662?source=rss-9119c54d607d------2</link>
            <guid isPermaLink="false">https://medium.com/p/fcf0a2f12662</guid>
            <category><![CDATA[architecture]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[microservices]]></category>
            <dc:creator><![CDATA[Luca Mezzalira]]></dc:creator>
            <pubDate>Wed, 14 May 2025 14:12:14 GMT</pubDate>
            <atom:updated>2025-05-14T14:12:14.734Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[The data recovery challenge in the cloud era]]></title>
            <link>https://lucamezzalira.medium.com/the-data-recovery-challenge-in-the-cloud-era-209988ee6a62?source=rss-9119c54d607d------2</link>
            <guid isPermaLink="false">https://medium.com/p/209988ee6a62</guid>
            <category><![CDATA[s3]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[data]]></category>
            <category><![CDATA[disaster-recovery]]></category>
            <dc:creator><![CDATA[Luca Mezzalira]]></dc:creator>
            <pubDate>Tue, 17 Dec 2024 21:12:55 GMT</pubDate>
            <atom:updated>2024-12-17T21:12:55.654Z</atom:updated>
            <content:encoded><![CDATA[<p>In today’s digital-first world, businesses are generating and storing data at an unprecedented scale. With the rise of cloud computing, platforms like AWS S3 have become the backbone of modern data storage. They offer unmatched scalability and reliability, making them the go-to solution for organizations managing everything from customer records to financial transactions. The sheer volume of data being stored is staggering — according to recent statistics, over 100 trillion objects are stored in S3 buckets worldwide, a number that continues to grow exponentially.</p><p>However, with this exponential growth in data comes a significant challenge: how do you recover it when something goes wrong? Whether it’s accidental deletion, corruption, or a malicious attack, recovering critical data can be a daunting task. The complexity of cloud environments, coupled with the sheer scale of data involved, makes traditional recovery methods increasingly inadequate.</p><p>Disaster Recovery and Cyber Recovery are two critical aspects of modern data protection strategies. Disaster Recovery focuses on restoring systems and data after a catastrophic event, such as natural disasters, hardware failures, or human errors. Cyber Recovery, on the other hand, specifically addresses the restoration of systems and data following a cyberattack, such as ransomware or malicious data corruption. Both are essential for ensuring business continuity and minimizing downtime.</p><p>Imagine this scenario: a rapidly growing e-commerce company is conducting routine maintenance on its AWS S3 buckets. During this process, an engineer accidentally deletes a folder containing critical customer information, including order histories and payment details. Panic sets in as the team scrambles to recover the lost data. The clock is ticking, customers are waiting, and every passing minute could mean lost revenue or reputational damage. This scenario is not uncommon — it’s a reality some organizations face when they rely on cloud storage without robust recovery mechanisms in place.</p><p>The impact of data loss can be severe and far-reaching. Beyond the immediate financial implications, there’s the potential for long-term damage to customer trust, regulatory compliance issues, and disruption to business operations. In today’s data-driven economy, the ability to quickly and accurately recover lost or corrupted data isn’t just a nice-to-have — it’s a critical business imperative.</p><h3><strong>Current Solutions for AWS S3 Data Recovery</strong></h3><p>When it comes to recovering data stored in AWS S3, there are a few options available, each with its own set of advantages and limitations. Let’s explore these in more detail:</p><ol><li>AWS S3 Versioning: This is one of the most basic solutions offered natively by AWS. S3 versioning allows you to keep multiple versions of an object within a bucket, providing some level of protection against accidental deletions or overwrites. While helpful in certain situations, versioning has its limitations. It can quickly become expensive as storage costs increase with each new version of an object. Additionally, navigating through versions to find the specific one you need can be time-consuming and cumbersome, especially when dealing with large datasets or complex folder structures.</li><li>Manual Recovery: Another common approach is manual recovery using snapshots or backups stored elsewhere. This method often involves restoring data from a secondary location, which requires significant effort and expertise from the engineering team. For example, consider an e-commerce platform that experiences a failed system update, corrupting its product catalog stored in S3. Without an automated recovery solution, engineers might spend days manually piecing together the catalog from fragmented backups — time that could have been spent getting the platform back online. This approach is not only time-consuming but also prone to human error, potentially leading to incomplete or inaccurate data recovery.</li><li>AWS Backup: AWS offers a native backup solution that integrates seamlessly with S3 and other AWS services. AWS Backup provides a centralized way to manage and automate data protection across AWS services. For instance, consider our e-commerce platform scenario: if an engineer accidentally deletes a critical folder containing customer orders, AWS Backup can restore the data from a specific point in time backup. The recovery process is straightforward — administrators can use the AWS Backup console or AWS CLI to restore the deleted data, significantly reducing downtime and potential business impact. The service also provides audit logs and compliance reporting, making it easier to track recovery operations and maintain regulatory compliance. However, organizations need to carefully plan their backup strategy, including backup frequency and retention periods, to optimize costs while ensuring adequate data protection.</li></ol><p>Each of these solutions offers distinct advantages for different use cases. Building on these native AWS capabilities, third-party solutions provide additional features that complement the AWS ecosystem, combining enterprise-grade functionality with streamlined operations and cost efficiency.</p><h3><strong>Enter Clumio Backtrack</strong></h3><p>This is where Clumio Backtrack steps in as a solution for AWS S3 data recovery. Designed specifically for modern cloud environments, Backtrack offers an automated and scalable approach that eliminates many of the pain points associated with traditional methods. The solution’s capabilities are truly impressive, supporting up to 30 billion objects per bucket without any minimum size restrictions — a crucial feature for enterprises managing massive datasets.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ib4j2xhtIJqwAlrA55a04Q.png" /><figcaption>S3 Rewind with Clumio</figcaption></figure><p>One of its standout features is its ability to handle massive datasets efficiently. Unlike manual processes that require significant time and resources, Clumio Backtrack automates recovery tasks, enabling organizations to restore their data quickly and effortlessly. The system uses intelligent algorithms to identify and recover only the necessary data, minimizing recovery time and reducing the risk of data conflicts. What sets it apart is its near-instant recovery capabilities, complemented by powerful features like granular search across protected data and an intuitive calendar-based view for precise point-in-time recovery. During recovery operations, organizations can immediately access their restored buckets in read-only mode, ensuring business continuity while the full restoration process completes.</p><p>For instance, imagine a financial services firm hit by a ransomware attack that encrypts terabytes of sensitive data stored in S3. With traditional recovery methods, the firm might spend days or even weeks trying to restore their systems, potentially missing critical business opportunities and eroding customer trust. With Clumio Backtrack, they can roll back their data to a specific point in time before the attack occurred — restoring operations within hours rather than days. This rapid recovery capability can be the difference between a minor hiccup and a major business crisis.</p><p>Another key innovation is Backtrack’s point-in-time recovery capability. This feature allows organizations to revert their data to any moment in history with precision, ensuring minimal disruption and maximum accuracy. Whether it’s recovering accidentally deleted files or undoing changes made during a failed deployment, Backtrack makes it easy to pinpoint exactly what needs to be restored. This granular control is particularly valuable in complex scenarios where multiple changes have occurred over time, and you need to recover to a very specific state.</p><h3><strong>Key Advantages of Clumio Backtrack</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*itSrqq39ts41eEnk7hvpVQ.png" /><figcaption>Creato point-in-time copies with Clumio</figcaption></figure><p>The benefits of Clumio Backtrack go beyond just speed and efficiency — it also offers significant cost savings by leveraging existing AWS infrastructure. Traditional recovery solutions often require additional hardware or software investments, driving up costs over time. In contrast, Backtrack integrates seamlessly with AWS S3, minimizing expenses while delivering enterprise-grade functionality. This cost-effectiveness is particularly important for organizations looking to optimize their cloud spending without compromising on data protection.</p><p>Another advantage is its user-friendly interface, which simplifies complex recovery processes for IT teams. Instead of navigating through multiple tools or writing custom scripts, users can manage their recovery workflows through an intuitive dashboard. This ease of use empowers teams to focus on strategic initiatives rather than getting bogged down by operational tasks. The interface is designed to be accessible to both seasoned IT professionals and less technical users, democratizing the recovery process across the organization.</p><p>Moreover, Clumio Backtrack offers robust security features to ensure that your data remains protected throughout the recovery process. It employs end-to-end encryption, role-based access controls, and comprehensive audit logging to maintain the integrity and confidentiality of your data. This security-first approach is crucial in an era where data breaches and cyber attacks are increasingly common.</p><p><strong>Choosing the Right S3 Backup Solution</strong></p><p>When choosing between AWS Backup for S3 and Clumio Backtrack, customers should consider their specific needs and use cases. AWS Backup for S3 is an excellent choice for organizations deeply integrated into the AWS ecosystem, requiring native integration with other AWS services, and comfortable with managing backups through the AWS Management Console. It’s particularly suitable for businesses with moderate data volumes and those who prioritize continuous backups within a 35-day window.</p><p>On the other hand, Clumio Backtrack shines in scenarios involving massive datasets and the need for near-instant recovery. It’s ideal for enterprises managing billions of objects in S3, requiring rapid rollback capabilities, and seeking a user-friendly interface with features like global search and calendar views. Clumio Backtrack also offers advantages in terms of scalability, handling up to 30 billion objects per bucket without minimum object size restrictions, making it a strong contender for organizations with extensive data management needs. Additionally, its ability to provide instant access to restored buckets in a read-only format can be crucial for businesses prioritizing minimal downtime during recovery operations.</p><h3><strong>The Future of Cloud Data Recovery</strong></h3><p>Data recovery has always been a challenging aspect of IT operations, but it becomes even more complex in cloud environments where datasets are larger and more dynamic than ever before.</p><p>Clumio Backtrack addresses these challenges head-on by offering a fast, efficient, and cost-effective way to recover AWS S3 data at scale. Its unique features — such as automated workflows and point-in-time recovery — make it an invaluable tool for organizations looking to safeguard their critical assets.</p><p>As we look to the future, the importance of data resilience will only continue to grow. Organizations that invest in advanced recovery solutions like Clumio Backtrack will be better positioned to navigate the challenges of an increasingly data-driven world. They’ll be able to recover from incidents faster, minimize downtime, and maintain the trust of their customers and stakeholders.</p><p>If your organization relies on AWS S3 for storing important data, now is the time to rethink your recovery strategy. Don’t wait until disaster strikes — be proactive about protecting your business from potential downtime or data loss. The cost of inaction could be far greater than the investment in a robust recovery solution.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=209988ee6a62" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>