<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Rocky Yu</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://ryu.xin/</id>
  <link href="https://ryu.xin/" rel="alternate"/>
  <link href="https://ryu.xin/feed.xml" rel="self"/>
  <rights>All rights reserved 2026, Rocky Yu</rights>
  <subtitle>Long-form essays on software engineering, artificial intelligence, organizations, and people</subtitle>
  <title>
    <![CDATA[Software, AI & People]]>
  </title>
  <updated>2026-08-08T16:00:00.000Z</updated>
  <entry>
    <author>
      <name>Rocky Yu</name>
    </author>
    <category term="Software Engineering" scheme="https://ryu.xin/categories/software-engineering/"/>
    <category term="AI" scheme="https://ryu.xin/tags/AI/"/>
    <category term="Software Engineering" scheme="https://ryu.xin/tags/Software-Engineering/"/>
    <category term="Books" scheme="https://ryu.xin/tags/Books/"/>
    <category term="Programming" scheme="https://ryu.xin/tags/Programming/"/>
    <content>
      <![CDATA[<header class="abstract"><h2 data-no-number="true">Abstract</h2><p><em>The Art of Computer Programming</em>, <em>Code Complete</em>, <em>Refactoring</em>, <em>Design Patterns</em>, and <em>The Mythical Man-Month</em> do not become irrelevant when AI can write code. The deeper risk is that programmers once turned the ideas in those books into intuition by implementing things, tracing failures, maintaining old systems, and living with the consequences. AI can let us skip that experience and arrive directly at something that looks finished.</p><p>The canon is not simply aging. Its path into practice is being interrupted. Sending the next generation back to an all-manual workflow would be pointless, and there is no virtue in preserving drudgery. What matters is preserving prediction, close contact with implementation, causal feedback, explanation, and long-term ownership. Unless those acts are designed into AI-assisted work, practical wisdom will slowly flatten into prompt vocabulary.</p></header><p class="thesis">The part of programming culture worth passing on is not the ritual of typing code by hand. It is the ability to stay in direct contact with complexity. Classic books are compressed experience; our task is to build a learning loop in which that experience can expand again.</p><p class="part-label">Part I · The canon does not contain answers</p><h2 id="A-harder-version-of-“Do-these-books-still-matter-”"><span class="section-no">01</span><a href="#A-harder-version-of-“Do-these-books-still-matter-”" class="headerlink" title="A harder version of “Do these books still matter?”"></a>A harder version of “Do these books still matter?”</h2><p class="lead dropcap">I recently found myself asking a practical question: how useful are books such as <em>Code Complete</em>, <em>Refactoring</em>, and <em>Design Patterns</em> when AI can produce so much of the code? The easy answer is that they still teach us how to judge what AI writes. That is true, but it steps around the difficult part. How does someone who has never been trapped inside a bad codebase acquire the judgment to recognize one?</p><p>For many programmers of my generation, the feeling came before the terminology. Change one branch in a thousand-line method and an apparently unrelated feature fails. Follow an ambiguously named field through a dozen calls and you begin to sense that the design is wrong before you can explain why. Deploy a change to shared state without tests and you hesitate for a moment before pressing the button. That hesitation is already a form of knowledge. Books later gave names to what we had felt: divergent change, confused responsibility, hidden coupling. They turned experience into a vocabulary that could be examined and shared.</p><p>A young programmer today may follow a different route: describe the feature, generate an implementation, run the tests, and return any failures to the model. The defects and complexity remain, but the programmer may encounter them only through the model’s account. What gets delegated is not just the typing. It can also be the experience that teaches you where to look when something breaks.</p><p>The useful question, then, is no longer whether the classics are dated. It is where the experience that makes them intelligible will come from.</p><h2 id="One-shelf-holds-several-different-kinds-of-craft"><span class="section-no">02</span><a href="#One-shelf-holds-several-different-kinds-of-craft" class="headerlink" title="One shelf holds several different kinds of craft"></a>One shelf holds several different kinds of craft</h2><p>Calling all of these books guides to “writing clean code” misses most of what they contain. Together they span the distance from computation to organizational life.</p><div class="table-wrap"><table><caption>What classic engineering work preserves</caption><thead><tr><th>Layer</th><th>Representative books and essays</th><th>What they actually train</th></tr></thead><tbody><tr><td>Computation and abstraction</td><td><em>The Art of Computer Programming</em>, SICP, “The Humble Programmer”<sup class="ref"><a href="#ref-1">[1]</a></sup><sup class="ref"><a href="#ref-2">[2]</a></sup><sup class="ref"><a href="#ref-3">[3]</a></sup></td><td>Respect for the cost of time, space, state, and abstraction</td></tr><tr><td>Construction</td><td><em>Code Complete</em>, <em>The Pragmatic Programmer</em><sup class="ref"><a href="#ref-4">[4]</a></sup><sup class="ref"><a href="#ref-5">[5]</a></sup></td><td>Turning readability, defensive thinking, and responsibility into local choices</td></tr><tr><td>Safe change</td><td><em>Refactoring</em>, <em>Working Effectively with Legacy Code</em><sup class="ref"><a href="#ref-6">[6]</a></sup><sup class="ref"><a href="#ref-7">[7]</a></sup></td><td>Changing a live system while feedback protects its behavior</td></tr><tr><td>Design language</td><td><em>Design Patterns</em> and the pattern literature it inspired<sup class="ref"><a href="#ref-8">[8]</a></sup></td><td>Describing context, forces, variation, and tradeoffs</td></tr><tr><td>Systems and organizations</td><td><em>The Mythical Man-Month</em>, <em>Peopleware</em>, “No Silver Bullet,” “Programming as Theory Building”<sup class="ref"><a href="#ref-9">[9]</a></sup></td><td>Conceptual integrity, communication cost, and shared mental models</td></tr></tbody></table></div><p>Some of these books are too large to read straight through. Some use machines and languages that have long since disappeared. Modern type systems, frameworks, and delivery practices have absorbed or corrected parts of their advice. None of that makes them weightless. They preserve a history of how software learned to think: which failures exposed a weak idea, which practices survived contact with production, and which tradeoffs repeatedly proved expensive. Reading them gives us access to experience we did not have to acquire entirely on our own.</p><p>When Donald Knuth called programming an art, he was not appealing to mysterious talent. He meant the application of accumulated knowledge, skill, and ingenuity to real problems. TAOCP’s imaginary machine forces the reader to account for the cost of an algorithm. SICP offers a different lesson: change the evaluation model, representation of state, or abstraction boundary and the same problem becomes a different program. A capable tool can implement either version. It cannot remove the semantic and operational differences between them.</p><h2 id="A-pattern-is-compressed-accident-history"><span class="section-no">03</span><a href="#A-pattern-is-compressed-accident-history" class="headerlink" title="A pattern is compressed accident history"></a>A pattern is compressed accident history</h2><p>Ask an AI to “improve this code with the Strategy pattern” and it can produce an interface, concrete strategies, a factory, and tests within seconds. The shape appears so cheaply that it is easy to forget why patterns exist.</p><p>A pattern usually earns a name after people meet the same tension across many systems. A behavior really does vary independently. An external dependency repeatedly leaks into the core. A thicket of conditionals is better understood as state transition. The name is an index into that experience. Behind it sit a context, competing forces, known consequences, and the cost of leaving the problem alone.</p><p>Take Strategy. It rarely begins with a desire for an elegant interface. More often, a billing function accumulates ordinary users, VIP rules, promotions, cross-border taxes, and refund behavior until each change risks breaking another case. Eventually someone separates the part that genuinely varies, <em>how the charge is calculated</em>, from the rest of the flow. The pattern gives a name to that recurring pressure. Generating the familiar class structure is easy. Understanding the pattern means recognizing whether the same pressure is actually present in your code.</p><p>That is why generating a pattern and understanding one are different acts. Generation reproduces a shape. Judgment asks whether there is a stable axis of change here, whether the cost of another indirection is lower than the cost of the expected change, and what evidence would justify deleting the abstraction later.</p><div class="pullquote"><p>The canon is not a warehouse of standard answers. It is an index built from expensive failures.</p></div><p>That is also the transmission problem in miniature. We can copy the index perfectly. The experience to which it points cannot be downloaded.</p><p class="part-label">Part II · AI changes how experience is formed</p><h2 id="The-old-feedback-loop-was-inefficient-and-effective"><span class="section-no">04</span><a href="#The-old-feedback-loop-was-inefficient-and-effective" class="headerlink" title="The old feedback loop was inefficient, and effective"></a>The old feedback loop was inefficient, and effective</h2><p>The traditional route into engineering judgment was slow and often frustrating. A programmer wrote code, a later requirement or production failure exposed a weakness, and the repair required tracing unfamiliar state, reading an overlooked module, adding tests, and changing the system in small steps. Review supplied another person’s perspective. Long-term maintenance revealed the delayed cost of short-term decisions. The classics then gave names and structure to those scattered experiences. This loop was inefficient, but it repeatedly connected a decision to its consequences.</p><p>Peter Naur’s 1985 essay “Programming as Theory Building” argued that programmers create more than program text. They develop a theory of how a problem in the world is solved by a particular system. When the original team leaves, the files and documentation may remain while that theory disappears, forcing maintainers to build it again.<sup class="ref"><a href="#ref-9">[9]</a></sup></p><p>The argument lands differently now. Anyone who has inherited a well-documented system from a departed team knows the problem: each function may be readable while the reasons behind the boundaries remain obscure. A harmless-looking change can still violate an assumption that nobody wrote down. AI can explain every file on demand, but that does not mean the team shares a theory it can use when evidence is incomplete or constraints conflict. An explanation answers the current question. A theory lets maintainers make coherent decisions when there is no ready answer. The former can be generated; the latter has to be developed.</p><figure class="article-figure"><img src="/assets/articles/software-craft-after-ai/figure-01-broken-learning-loop.webp?v=f0a362254ede0442" width="1672" height="941" loading="lazy" alt="Two paths into software expertise: on one side a programmer learns through failure, tracing, repair, and maintenance; on the other a programmer directs automated machinery through a glass interface while the feedback loop breaks between delivery and understanding"><figcaption><p><strong>Figure 1 · AI can shorten more than the delivery path.</strong> The old loop forced action through causality and brought consequences back into judgment. An AI loop optimized only for a working result can finish the delivery while leaving understanding outside the circuit.</p></figcaption></figure><h2 id="Completion-and-comprehension-can-now-separate-at-scale"><span class="section-no">05</span><a href="#Completion-and-comprehension-can-now-separate-at-scale" class="headerlink" title="Completion and comprehension can now separate at scale"></a>Completion and comprehension can now separate at scale</h2><p>The speed gains from AI-assisted coding are real, and they are highly sensitive to the task. In a controlled 2022 experiment, participants with early GitHub Copilot access finished a standardized JavaScript HTTP server task 55.8 percent faster. The authors explicitly noted that the experiment did not measure collaboration or code quality in a large project.<sup class="ref"><a href="#ref-11">[11]</a></sup> METR studied experienced open-source developers working in repositories they knew well and found that early-2025 tools increased task time by 19 percent. Its 2026 update saw signals of a possible speedup from newer tools, but the researchers judged selection effects too serious for a reliable estimate of its size.<sup class="ref"><a href="#ref-16">[16]</a></sup></p><p>These results do not settle whether AI is “really” faster. They show how much the answer depends on the task, the developer’s familiarity with the repository, and the generation of tools being tested. More importantly, completion speed and depth of understanding are different measures. Someone can ship a working feature quickly while knowing little about why it works or when it will fail. AI makes that separation possible at a scale that older forms of abstraction did not.</p><p>An observational study of 21 novice programmers found that 20 completed the assigned task with generative AI. But AI did not resolve an existing problem for the weaker students: they still struggled to tell whether they understood the problem, and some mistook a finished task for mastery.<sup class="ref"><a href="#ref-12">[12]</a></sup></p><p>Another experiment asked 15 computer science graduate students to modify an existing codebase. With Copilot, they finished faster and passed more tests, but their understanding of the original code did not improve accordingly. Both studies are small and cannot support broad claims. Their narrower warning is still useful: completing a task is not the same as understanding the system.<sup class="ref"><a href="#ref-13">[13]</a></sup></p><p>This separation is not entirely new. Copying an answer, using a framework, or calling a cloud API has always allowed programmers to skip lower layers. AI differs in reach. A single interaction can delegate interpretation of the requirement, architectural choices, implementation, tests, and diagnosis. The result may be useful and correct, but much of the reasoning path can remain invisible to the person who accepts it. The saved time is real. So is the lost opportunity to calibrate judgment against consequences.</p><h2 id="Three-abilities-can-thin-out-without-much-pain"><span class="section-no">06</span><a href="#Three-abilities-can-thin-out-without-much-pain" class="headerlink" title="Three abilities can thin out without much pain"></a>Three abilities can thin out without much pain</h2><p>The first is a <strong>causal map</strong>. Someone who traces a difficult failure learns where state changes, how exceptions propagate, and why a seemingly redundant check may encode the memory of an earlier incident. Someone who sees only the final diff can know what the system contains without understanding what holds its behavior in place.</p><p>The second is <strong>calibration</strong>. Recognizing a code smell is not the same as deciding whether it matters now, whether two similar blocks express one concept or merely resemble each other, or whether an abstraction isolates real change rather than imagined change. Judgment develops when we make a prediction and compare it with the outcome. If AI supplies an apparently correct answer before we form a view of our own, that calibration step can disappear.</p><p>The third is <strong>authorship and responsibility</strong>. A mistake you make and later repair tends to change your next decision. When a model generates the code, fixes it, and explains the fix, it is easy to record the episode as “the model got this one wrong.” The immediate problem is solved, but nobody necessarily absorbs the lesson.</p><p>A survey of 319 knowledge workers found a related tension: greater confidence in generative AI was associated with less self-reported critical-thinking effort. The study did not suggest that thought simply vanished. It shifted toward verification, integration, and oversight. This was not a programming study, and its evidence was self-reported, so the result should be read cautiously. It nevertheless points to an important design problem: AI-assisted work needs new opportunities for active judgment because the old ones may not survive by default.<sup class="ref"><a href="#ref-14">[14]</a></sup></p><h2 id="When-practical-wisdom-becomes-prompt-vocabulary"><span class="section-no">07</span><a href="#When-practical-wisdom-becomes-prompt-vocabulary" class="headerlink" title="When practical wisdom becomes prompt vocabulary"></a>When practical wisdom becomes prompt vocabulary</h2><p>The likely future is not one in which nobody mentions the classics. SOLID, DDD, Clean Architecture, Strategy, and Repository may become more common than ever in prompts and repositories. Every name will sound professional and each layer will have a plausible explanation. Nobody will be able to say which real force the structure is resisting.</p><p>“Refactor this according to SOLID and appropriate design patterns” can become an incantation. A twenty-line function turns into Factory, Manager, Provider, Handler, and Resolver. The tests remain green and every class has a plausible justification, yet a small change now requires navigating five files to reconstruct the original flow. The system is not simpler; its complexity has acquired more respectable names. AI makes that kind of abstraction cheap to produce, while the maintenance cost is deferred to another person or another quarter.</p><p>That is the cultural hollowing-out I worry about. The vocabulary survives while the experience that gives it meaning becomes thinner. A programmer may speak fluently about boundaries, cohesion, and dependency inversion, yet have no way into a race condition, a data mismatch, or a slow production path. Knowing the terms is useful. It is not the same as having learned when and how they matter.</p><p class="part-label">Part III · Rereading the classics for an AI workflow</p><h2 id="The-great-big-books-teach-respect-for-cost"><span class="section-no">08</span><a href="#The-great-big-books-teach-respect-for-cost" class="headerlink" title="The great big books teach respect for cost"></a>The great big books teach respect for cost</h2><p>TAOCP is not a handbook for everyday web development, nor should it be a barrier to entry. Engineers do not need to implement sorting in MMIX before using a standard library. Its durable value is the discipline of asking what lies behind an operation that appears simple: the model, proof, boundary conditions, and costs that libraries and hardware usually hide. It teaches respect for those costs without demanding that every reader reproduce the machinery by hand.</p><p>AI makes implementation cheap, which makes it easier to confuse <em>generatable</em> with <em>understood</em>. Code can run and pass its tests while hiding an algorithm that fails at a larger scale. Studying algorithms and models of computation is not an exercise in recalling more facts than a model. It gives us questions to ask: What happens when the input grows by an order of magnitude? Which invariants carry correctness? Do the assumptions still hold under different precision, memory, or concurrency constraints? When is a mature library enough, and when does the implementation or original paper need to be read? Those questions turn “it seems to work” into an account of why it works and where it may fail.</p><p>SICP likewise matters for more than Scheme. It trains the reader to look through syntax toward evaluation, composition, state, and interpretation. An agent that can write ten languages makes that ability more valuable, not less: surface differences grow ever easier to erase, while semantic differences will still demand payment at runtime.</p><h2 id="Refactoring-should-recover-its-meaning-as-an-experiment"><span class="section-no">09</span><a href="#Refactoring-should-recover-its-meaning-as-an-experiment" class="headerlink" title="Refactoring should recover its meaning as an experiment"></a>Refactoring should recover its meaning as an experiment</h2><p>Of all the classics, <em>Refactoring</em> may have become more important. Fowler’s definition is deliberately narrow: improve internal structure through a sequence of small changes that preserve observable behavior. Small steps are a method of risk control, not an aesthetic preference. Tests are not only a final gate. They are feedback that says each step remains inside the known world.<sup class="ref"><a href="#ref-6">[6]</a></sup></p><p>AI is very good at producing a cleaner-looking version of a module. In the same change it may replace an interface, upgrade a dependency, alter an exception, and add tests tailored to the new implementation. When a caller fails weeks later, the commit offers little help in locating the behavioral change because rewriting and refactoring were mixed together. Refactoring is safe precisely because observable behavior is held constant while the internal structure changes. Once a new behavior or implementation strategy enters the same step, the team loses that guarantee and makes the source of a regression harder to trace.</p><p><em>Working Effectively with Legacy Code</em> adds another practical lesson: an old system usually lacks, before it lacks elegance, the seams that let you sense behavior and separate dependencies.<sup class="ref"><a href="#ref-7">[7]</a></sup> An AI-era team can turn that lesson into an explicit change contract. List observable behavior and unknown regions first. Add characterization tests. Restrict the write scope. Validate every small diff independently. Move to the next step only when the evidence permits it. The agent can perform much of the mechanical work; a human still defines what must not change.</p><h2 id="Treat-every-pattern-as-a-falsifiable-design-hypothesis"><span class="section-no">10</span><a href="#Treat-every-pattern-as-a-falsifiable-design-hypothesis" class="headerlink" title="Treat every pattern as a falsifiable design hypothesis"></a>Treat every pattern as a falsifiable design hypothesis</h2><p>Patterns do not need to be banned, and they should not be enabled by default. A better rule is to write each pattern as a hypothesis that reality is allowed to overturn.</p><div class="diagnostic"><h3>Questions a pattern should answer before it enters the code</h3><ul><li><strong>Context:</strong> Which responsibility or dependency is creating friction now?</li><li><strong>Pressure:</strong> Which dimension has changed independently, or is supported by credible evidence that it will?</li><li><strong>Minimum move:</strong> What is the smallest useful separation short of the full pattern?</li><li><strong>Cost:</strong> What navigation, debugging, and testing cost will the indirection add?</li><li><strong>Disconfirming evidence:</strong> What would show that the abstraction is wrong?</li><li><strong>Deletion condition:</strong> If the anticipated change never appears, when should this layer be merged or removed?</li></ul></div><p>Under this discipline, Strategy is a claim that there is a real axis of independent change, not merely a familiar set of class names. Adapter protects the core from the semantics of an external model. Observer trades an obvious call path for looser coupling in time and dependency; whether that trade is worthwhile depends on the context. AI is useful here because it can generate several candidate structures and counterexamples quickly. The engineer’s job is to compare them against evidence rather than reward the most recognizable pattern.</p><h2 id="Organizational-classics-remind-us-that-code-is-not-the-whole-system"><span class="section-no">11</span><a href="#Organizational-classics-remind-us-that-code-is-not-the-whole-system" class="headerlink" title="Organizational classics remind us that code is not the whole system"></a>Organizational classics remind us that code is not the whole system</h2><p><em>The Mythical Man-Month</em>, <em>Peopleware</em>, and Naur’s essay address different subjects, but they share an important premise: software is more than text. It is also a set of concepts, a communication structure, a working environment, and an allocation of responsibility. Faster local implementation does not remove any of these concerns. Code may be generated in minutes, but a team still has to decide whether it should be merged, who approves it, and who responds when it fails. Brooks’s “no silver bullet” remains relevant because much of the difficulty lies in deciding what to build and coordinating the people who build it.</p><p>DORA’s 2025 research describes AI as an amplifier of an organization’s existing capabilities. It can magnify strengths as well as weaknesses, so the returns depend on the system into which the tool is introduced.<sup class="ref"><a href="#ref-15">[15]</a></sup> A coherent repository gives an agent stable examples to follow. Fast tests and short feedback loops allow a team to absorb more change safely. Clear responsibility makes escalation possible when risk appears. In a team with vague boundaries, stale knowledge, and little shared understanding, AI can instead produce more locally plausible changes that fail to fit together. The tool does not create those conditions, but it can make their consequences arrive faster.</p><p>Reading the classics in the AI era therefore cannot remain a matter of individual taste. Their ideas need somewhere to attach: review, task design, incident analysis, architecture decisions, and team development. Otherwise the knowledge you finish reading still has nowhere to land.</p><p class="part-label">Part IV · A new apprenticeship for software craft</p><h2 id="Restore-feedback-not-scarcity"><span class="section-no">12</span><a href="#Restore-feedback-not-scarcity" class="headerlink" title="Restore feedback, not scarcity"></a>Restore feedback, not scarcity</h2><p>Asking new programmers to avoid AI and write everything by hand for several years is neither realistic nor educational by itself. Much of the old friction was simple drudgery: looking up syntax, copying boilerplate, porting the same logic between frameworks, or waiting for a build. Removing that work is a genuine improvement.</p><p>Other kinds of friction are educational because they change the next decision. Predicting an outcome before acting, tracing a state transition personally, explaining an abstraction to another engineer, and maintaining a change months later all connect judgment with evidence. The aim is not to preserve pain. It is to remove drudgery without removing feedback.</p><p>Cognitive apprenticeship moves through modeling, coaching, scaffolding, articulation, reflection, and exploration, with support gradually withdrawn as the learner gains competence.<sup class="ref"><a href="#ref-10">[10]</a></sup> AI fits this model well. It can demonstrate how an expert traces a failure, provide progressively stronger hints, generate counterexamples, and compare several solutions. The least useful learning design reverses the sequence by supplying a polished answer before the learner has formed a model of the problem. The tool remains available, but the learner has little to do beyond accepting its output.</p><h2 id="Separate-production-mode-from-learning-mode"><span class="section-no">13</span><a href="#Separate-production-mode-from-learning-mode" class="headerlink" title="Separate production mode from learning mode"></a>Separate production mode from learning mode</h2><p>A team does not have to sacrifice delivery speed on every task. It does have to admit that finishing work and building capability are different modes, then reserve explicit capacity for the second.</p><div class="table-wrap"><table><caption>The same AI tools in two different modes</caption><thead><tr><th>Dimension</th><th>Production mode</th><th>Learning mode</th></tr></thead><tbody><tr><td>Goal</td><td>Deliver efficiently within a risk boundary</td><td>Build a transferable causal model and better judgment</td></tr><tr><td>AI role</td><td>Implementer, researcher, validation runner</td><td>Coach, adversary, hint provider, failure simulator</td></tr><tr><td>Human act</td><td>Define constraints, review evidence, own release</td><td>Predict first, trace personally, explain tradeoffs, compare outcomes</td></tr><tr><td>Task choice</td><td>Automate low-risk mechanical work</td><td>Select representative failures, legacy code, and boundary problems</td></tr><tr><td>Done means</td><td>Functionality, tests, performance, rollback</td><td>Can explain, modify, and recognize an incorrect transfer</td></tr></tbody></table></div><p>For a novice, a vague “no-AI zone” is difficult to enforce and easy to experience as punishment. A <strong>difficulty budget</strong> is more precise: identify the parts of a task the learner must attempt before receiving a complete solution. In debugging, the learner can draw the call path and record a hypothesis before using AI to test it. In an algorithm exercise, they can state the complexity and invariants while AI provides hints in stages. More automation becomes available as the learner’s own model becomes stronger. The default should follow the person’s capability, not the tool’s capacity to generate.</p><p>Senior engineers are learning as well. They must divide large tasks into units an agent can complete and return with useful evidence, detect architectural drift in code that looks locally tidy, design validations whose success carries real information, and review a much larger volume of output without losing judgment. The classics provide a language for assessing these decisions. Current practice must adapt that language to a different means of production, and even experienced engineers are still learning how.</p><h2 id="Six-feedback-devices-that-fit-into-ordinary-team-life"><span class="section-no">14</span><a href="#Six-feedback-devices-that-fit-into-ordinary-team-life" class="headerlink" title="Six feedback devices that fit into ordinary team life"></a>Six feedback devices that fit into ordinary team life</h2><div class="principles"><div class="principle"><strong>Predict before generating.</strong> Write down the affected modules, highest-risk behavior, expected tests, and invariants before the prompt. Without a prediction, there is nothing to calibrate.</div><div class="principle"><strong>Write a refactoring contract.</strong> State observable behavior, permitted scope, and validation for every step. Do not let a large rewrite pass as a small refactor.</div><div class="principle"><strong>Keep human-led failure autopsies.</strong> For production incidents, races, and data errors, have people draw the timeline, call path, and state transitions before AI supplies counterexamples. An incident is not only a ticket to close. It is scarce teaching material.</div><div class="principle"><strong>Give every abstraction a record.</strong> Capture the pressure that justified a pattern, rejected alternatives, expected benefit, and deletion condition. Review why it exists, not just whether it has a respectable name.</div><div class="principle"><strong>Make understanding a deliverable.</strong> For an important change, the owner must be able to explain the critical path, failure modes, and rollback without AI. If that cannot be done, the work is not complete.</div><div class="principle"><strong>Carry ownership through time.</strong> Developers should maintain the systems they build with AI, join the on-call rotation, participate in review, and make the next change. Short-term choices become durable experience only when consequences cross quarter boundaries.</div></div><figure class="article-figure"><img src="/assets/articles/software-craft-after-ai/figure-02-ai-apprenticeship-loop.webp?v=3b8b3246dcce7a23" width="1672" height="941" loading="lazy" alt="A programmer and an AI share a circular workbench moving through prediction, constrained generation, stress testing, human tracing, explanation, and long-term maintenance, with operational evidence feeding the next judgment"><figcaption><p><strong>Figure 2 · A new feedback loop for AI-assisted work.</strong> AI can remain at the bench, but it cannot place the human outside the causal chain. Prediction, constrained action, verification, explanation, and ownership turn one delivery into judgment that can be reused on the next.</p></figcaption></figure><h2 id="Senior-programmers-will-still-need-a-nose-for-trouble"><span class="section-no">15</span><a href="#Senior-programmers-will-still-need-a-nose-for-trouble" class="headerlink" title="Senior programmers will still need a nose for trouble"></a>Senior programmers will still need a nose for trouble</h2><p>Teams also need better measures. If the scorecard includes only closed tickets and merge speed, the cost of understanding is easy to push into the future. Delivery metrics should be considered alongside less convenient questions: Where does rework cluster? How many people can explain a critical module without asking AI? How expensive is it to modify code generated three months ago? Did an incident produce a reusable test or rule? Does review catch semantic problems or merely improve presentation? These signals are imperfect, but they reveal whether a team is accumulating understanding or borrowing against its future.</p><p>None of this means everyone must master all of TAOCP or that senior engineers should write every function by hand. A healthy engineering culture is not a shared reading list or vocabulary. It consists of habits: respecting complexity, refusing to equate passing tests with understanding, deleting a failed abstraction instead of hiding it behind another layer, naming the behaviors that must not change, investigating a failure before blaming the model, and accepting responsibility for what happens after release. No single book contains those habits, but the best books help us recognize and practice them.</p><p>The books still belong in that culture, but the way we read them will change. <em>The Art of Computer Programming</em> can be read beside a profiler and a model-generated algorithm. <em>Refactoring</em> can become a protocol for agent changes. <em>Design Patterns</em> can become a review form for design hypotheses. <em>The Mythical Man-Month</em> and <em>Peopleware</em> can help a team resist the naïve arithmetic that more agents automatically mean more throughput. A classic no longer waits for the mythical month when we finally read it cover to cover. It supplies a longer history and a more accurate language at the moment a real problem makes us ready for it.</p><div class="pullquote"><p>The next generation does not need to fall into every old hole. It does need to see how holes form and take responsibility for repairing the road.</p></div><p>AI is making implementation cheaper. That raises the value of knowing why a design works, what should not be generated, and who owns the result when it fails. Software craft will not disappear merely because less code is typed by hand, but it will not pass to the next generation simply because the classics remain on the shelf. It survives only if teams design understanding into the workflow, preserve feedback, and attach responsibility to real people.</p><p>A programmer does not need to repeat every old hardship to develop sound judgment. They do need direct contact with the system: enough to trace a failure, explain its cause, decide how to repair it, and live with the result. Keeping people inside that causal loop is how software craft can continue in the age of AI.</p><section class="references" id="references"><h2 data-no-number="true">References and further reading</h2><ol><li id="ref-1">Donald E. Knuth, <a href="https://cs.stanford.edu/~knuth/taocp.html"><em>The Art of Computer Programming</em></a>, Stanford University.</li><li id="ref-2">Harold Abelson, Gerald Jay Sussman, Julie Sussman, <a href="https://mitpress.mit.edu/9780262543231/structure-and-interpretation-of-computer-programs/"><em>Structure and Interpretation of Computer Programs</em></a>, MIT Press.</li><li id="ref-3">Edsger W. Dijkstra, <a href="https://www.cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340.html">“The Humble Programmer”</a>, ACM Turing Award Lecture, 1972.</li><li id="ref-4">Steve McConnell, <a href="https://www.microsoftpressstore.com/store/code-complete-9780735619678"><em>Code Complete, Second Edition</em></a>, Microsoft Press, 2004.</li><li id="ref-5">David Thomas and Andrew Hunt, <a href="https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/"><em>The Pragmatic Programmer, 20th Anniversary Edition</em></a>, 2019.</li><li id="ref-6">Martin Fowler, <a href="https://www.martinfowler.com/books/refactoring.html"><em>Refactoring: Improving the Design of Existing Code</em></a>, second edition, 2018.</li><li id="ref-7">Michael Feathers, <a href="https://www.informit.com/store/working-effectively-with-legacy-code-9780132931779"><em>Working Effectively with Legacy Code</em></a>, 2004.</li><li id="ref-8">Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, <a href="https://www.pearson.com/en-us/subject-catalog/p/design-patterns-elements-of-reusable-object-oriented-software/P200000009480/9780321700698"><em>Design Patterns: Elements of Reusable Object-Oriented Software</em></a>, 1994.</li><li id="ref-9">Peter Naur, <a href="https://gwern.net/doc/cs/algorithm/1985-naur.pdf">“Programming as Theory Building”</a>, 1985.</li><li id="ref-10">Allan Collins, John Seely Brown, Susan E. Newman, <a href="https://eric.ed.gov/?id=ED284181">“Cognitive Apprenticeship: Teaching the Craft of Reading, Writing, and Mathematics”</a>, 1987.</li><li id="ref-11">Sida Peng, Eirini Kalliamvakou, Peter Cihon, Mert Demirer, <a href="https://arxiv.org/abs/2302.06590">“The Impact of AI on Developer Productivity: Evidence from GitHub Copilot”</a>, 2023.</li><li id="ref-12">James Prather et al., <a href="https://arxiv.org/abs/2405.17739">“The Widening Gap: The Benefits and Harms of Generative AI for Novice Programmers”</a>, ICER 2024.</li><li id="ref-13">Yunhan Qiao et al., <a href="https://arxiv.org/abs/2511.02922">“Code Comprehension with GitHub Copilot: Performance Gains, Comprehension Trade-offs, and Behavioral Predictors in Brownfield Programming”</a>, preprint, revised 2026.</li><li id="ref-14">Hao-Ping Lee et al., <a href="https://www.microsoft.com/en-us/research/publication/the-impact-of-generative-ai-on-critical-thinking-self-reported-reductions-in-cognitive-effort-and-confidence-effects-from-a-survey-of-knowledge-workers/">“The Impact of Generative AI on Critical Thinking”</a>, CHI 2025.</li><li id="ref-15">DORA, <a href="https://dora.dev/research/2025/dora-report/"><em>State of AI-assisted Software Development 2025</em></a>, Google Cloud, 2025.</li><li id="ref-16">METR, <a href="https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/">early-2025 experienced open-source developer study</a> and <a href="https://metr.org/blog/2026-02-24-uplift-update/">2026 experiment-design update</a>.</li></ol></section>]]>
    </content>
    <id>https://ryu.xin/posts/software-craft-after-ai/</id>
    <link href="https://ryu.xin/posts/software-craft-after-ai/"/>
    <published>2026-08-07T16:00:00.000Z</published>
    <summary>From The Art of Computer Programming and Refactoring to Design Patterns and The Mythical Man-Month, an essay about rebuilding the feedback loops through which software craft is learned.</summary>
    <title>Can Software Craft Be Passed On in the Age of AI?</title>
    <updated>2026-08-08T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Rocky Yu</name>
    </author>
    <category term="Software Engineering" scheme="https://ryu.xin/categories/software-engineering/"/>
    <category term="AI" scheme="https://ryu.xin/tags/AI/"/>
    <category term="Low-Code" scheme="https://ryu.xin/tags/Low-Code/"/>
    <category term="Software Engineering" scheme="https://ryu.xin/tags/Software-Engineering/"/>
    <category term="Platform Engineering" scheme="https://ryu.xin/tags/Platform-Engineering/"/>
    <content>
      <![CDATA[<header class="abstract"><h2 data-no-number="true">Abstract</h2><p>AI coding lets one person turn a few sentences into a convincing application prototype. In doing so, it undermines the most visible promise of traditional low-code. Natural language is closer to business intent than drag-and-drop, while generated code can be more flexible than learning another proprietary expression language. A low-code product whose main achievement is saving keystrokes has good reason to worry.</p><p>Yet there is a wide gap between generating software that runs and entrusting a continuing business operation to it. Permissions, data consistency, failure recovery, performance, audit, upgrades, and ownership live in that gap. The scarce asset in a mature low-code platform is not its canvas. It is the set of production-tested components, models, and runtime contracts underneath. AI can interpret intent and propose a change; the platform can constrain and reuse; the engineering system can verify and deliver. Natural language plus a CLI is not necessarily the final interface, but it looks like a credible entrance to the next phase.</p></header><p class="thesis">AI coding will first displace the old low-code proposition of replacing hand-written code with drag-and-drop. If the next generation of low-code can become a machine-readable, verifiable, reversible foundation for enterprise applications, it will inherit a harder and more valuable job: making generation fast without making change uncontrollable.</p><p class="part-label">Part I · When code becomes cheap</p><h2 id="Why-the-death-of-low-code-sounds-plausible"><span class="section-no">01</span><a href="#Why-the-death-of-low-code-sounds-plausible" class="headerlink" title="Why the death of low-code sounds plausible"></a>Why the death of low-code sounds plausible</h2><p class="lead dropcap">The classic low-code demo begins with a table dragged onto a canvas. A data source is attached, a form is configured, and a working management application appears within minutes. The result felt remarkable because the alternative was assumed to be slower: find developers, create a project, choose a stack, implement the interface and API, then wait for deployment. That comparison has changed.</p><p>A user can now ask an AI for a supplier onboarding application. Suppliers submit credentials; procurement performs the first review; legal checks the contract; finance verifies the bank account; high-risk suppliers receive an additional compliance review; every action must be traceable. A few minutes later, the pages, API, database, and sign-in flow may already exist. The result may not be reliable, but it can look remarkably complete.</p><p>In his talk “Software Is Changing (Again),” Andrej Karpathy describes large language models as a new kind of computer programmed through natural language. <sup class="ref"><a href="#ref-1">[1]</a></sup> Follow that argument into application development and drag-and-drop begins to look indirect. The user does not really want to say, “Place a dropdown in the second column.” The user wants to say, “High-risk suppliers require an additional compliance decision.” If natural language can carry the latter, the canvas loses much of its advantage as the primary interface.</p><p>This is not the first time a higher-level abstraction has challenged low-code. Code generators, fourth-generation languages, model-driven development, and cloud services have all removed implementation work. AI is different because it can work with incomplete intent, explain its interpretation, and revise the result without requiring the user to learn a precise formal language first. The low barrier once associated with low-code is no longer exclusive.</p><p>I therefore agree with the first half of the pessimistic case. <strong>If writing less code remains a platform’s main claim to value, its moat is disappearing.</strong> A fixed template is not necessarily more adaptable than generated code. A proprietary formula is not necessarily easier than natural language. A constrained component set may offer less freedom than a conventional codebase. AI does not need to replace the whole platform at once. It only has to invalidate the reason customers originally accepted its constraints.</p><h2 id="Zero-to-running-has-become-genuinely-cheap"><span class="section-no">02</span><a href="#Zero-to-running-has-become-genuinely-cheap" class="headerlink" title="Zero to running has become genuinely cheap"></a>Zero to running has become genuinely cheap</h2><p>The clearest effect of AI coding is that software work can begin with “let us make one and see” rather than a request ticket. Product managers can test an interaction themselves. Operations teams can create a temporary tool. A founder can compare several product directions in a day. Ideas that would never have reached an engineering backlog can now acquire an executable form.</p><p>Addy Osmani calls the resulting experience the “70% problem.” AI can take someone to a surprisingly complete first version, while the remaining distance to maintainable, production-worthy software still demands architecture, edge-case reasoning, and verification. <sup class="ref"><a href="#ref-2">[2]</a></sup> The percentage is best treated as a useful engineering metaphor, not a universal project measurement. The first stretch feels quick because it is easy to demonstrate. Much of the last stretch appears only under failure, growth, and change.</p><p>A complaint-management prototype may already include authentication, a list, a detail view, and a state transition. Before production, the questions change:</p><ul><li>How does the system identify and merge duplicate complaints from the same customer?</li><li>Customer service agents may see only their product line, while quality leads see across lines. Is that rule enforced centrally or reimplemented in every page?</li><li>Does “no response within 24 hours” use elapsed time or a business calendar? What happens on a holiday or while a case is paused?</li><li>If a notification succeeds but the state update fails, can a retry escalate the case twice?</li><li>When a complaint contains private customer information, what rules govern exports, search indexes, logs, and backups?</li><li>When the workflow changes six months later, do in-flight cases remain on the old version or migrate to the new one?</li></ul><p>These questions rarely appear in the first screenshot. They determine whether a company should trust the application with customer relationships and service obligations.</p><div class="table-wrap"><table><caption>How evidence changes from prototype to enterprise application</caption><thead><tr><th>Stage</th><th>Common evidence of “done”</th><th>What remains unanswered</th></tr></thead><tbody><tr><td>Prototype</td><td>The page opens and the happy path can be demonstrated</td><td>Is the idea worth pursuing, and is the interaction understandable?</td></tr><tr><td>Usable application</td><td>Real users can complete a task and save data</td><td>Are permissions, edge cases, and failures correct?</td></tr><tr><td>Production system</td><td>Tests, monitoring, audit, and release records exist</td><td>Can it be trusted under real load and real failure?</td></tr><tr><td>Long-lived asset</td><td>It can be upgraded, migrated, recovered, and handed over</td><td>Can the next change remain controlled?</td></tr></tbody></table></div><h2 id="A-prototype-can-be-most-dangerous-when-it-looks-finished"><span class="section-no">03</span><a href="#A-prototype-can-be-most-dangerous-when-it-looks-finished" class="headerlink" title="A prototype can be most dangerous when it looks finished"></a>A prototype can be most dangerous when it looks finished</h2><p>A rough prototype invites skepticism. A polished interface with smooth transitions and a deployment URL does the opposite. Visual completeness becomes a proxy for engineering completeness, and “a few fixes before launch” begins to sound reasonable.</p><p>Enterprise qualities are rarely plugins fitted at the end. A data model’s treatment of history sets the limit for audit and migration. Whether permissions are enforced by the service or scattered through the frontend determines the exposure to unauthorized access. Transaction boundaries determine whether a partial failure can be recovered. Dependency choices determine whether growth can be accommodated or requires a rewrite. These decisions already exist in the first version, even when nobody has asked them to survive scrutiny.</p><p>AI increases the scale of this misjudgment. One agent creates pages, another adds APIs, a third changes the database, and a fourth edits deployment configuration. Every local answer may be plausible while no one understands the assembled system. Producing ten times more code does not create ten times more review capacity, test coverage, or architectural understanding. The bottleneck moves from “Who can write this?” to “Who can prove this?”</p><div class="pullquote"><p>When everyone can generate software, the first version is no longer scarce. The scarce capability is keeping the tenth version worthy of trust.</p></div><p class="part-label">Part II · Enterprises buy controlled change</p><h2 id="Enterprise-is-a-statement-of-responsibility-not-size"><span class="section-no">04</span><a href="#Enterprise-is-a-statement-of-responsibility-not-size" class="headerlink" title="Enterprise is a statement of responsibility, not size"></a>Enterprise is a statement of responsibility, not size</h2><p>“Enterprise-grade” is often confused with a larger feature set or a more elaborate stack. Microservices, containers, and Kubernetes become ceremonial markers of maturity. In practice, a three-screen approval tool may need enterprise safeguards if it carries real money, customer data, or regulatory obligations. A fifty-screen demonstration with no continuing dependency is still a prototype.</p><p>A more useful definition is a statement of responsibility: <strong>the organization is willing to entrust an ongoing business operation to this system and knows who must detect, explain, and recover it when something goes wrong.</strong></p><p>That responsibility needs at least six kinds of certainty:</p><ul><li><strong>Outcome certainty.</strong> The same business conditions produce the same result, and retries or concurrent actions do not silently create conflicting facts.</li><li><strong>Boundary certainty.</strong> Identity, role, tenant, and data permissions remain consistent at every entry point; security cannot depend on one page remembering to hide a button.</li><li><strong>Operational certainty.</strong> The system can isolate, degrade, or recover when a dependency times out, a network becomes unreliable, or traffic changes abruptly.</li><li><strong>Change certainty.</strong> The impact of a model, workflow, or interface change can be inspected; old data can be migrated; a failed release can be reversed.</li><li><strong>Evidence certainty.</strong> It is possible to reconstruct who acted, when, with which information, and under which rule.</li><li><strong>Ownership certainty.</strong> Business meaning, technical risk, and production release have accountable owners. AI is not one of them.</li></ul><p>These properties are not proportional to the number of features. They determine whether software becomes an organizational asset rather than a disposable output.</p><h2 id="AI-raises-output-the-engineering-system-decides-what-it-amplifies"><span class="section-no">05</span><a href="#AI-raises-output-the-engineering-system-decides-what-it-amplifies" class="headerlink" title="AI raises output; the engineering system decides what it amplifies"></a>AI raises output; the engineering system decides what it amplifies</h2><p>DORA’s 2025 research on AI-assisted software development offers a more useful conclusion than either “AI works” or “AI harms delivery.” AI acts as an amplifier of an organization’s existing strengths and weaknesses. The study associated AI adoption with higher delivery throughput while delivery stability remained under pressure. <sup class="ref"><a href="#ref-3">[3]</a></sup> That does not predict the outcome for an individual team. It does warn against treating local coding speed as end-to-end delivery performance.</p><p>In a team with clear boundaries, fast tests, short feedback loops, and dependable releases, AI can reproduce good practice more quickly. In a team where requirements change verbally, permission rules are scattered, tests are chronically deferred, and deployment depends on memory, AI can multiply inconsistency just as efficiently. Generation has no direction of its own. The surrounding engineering system determines whether it amplifies order or disorder.</p><p>This is where low-code may find a more defensible purpose. It does not have to beat AI at generating code. It can supply engineering facts that already exist: how identity is integrated, how workflow state is persisted, which components may access sensitive fields, how tasks are timed, how data is audited, and how applications are released and rolled back. AI need not reinvent those answers for every project.</p><h2 id="The-valuable-part-of-low-code-lives-below-the-canvas"><span class="section-no">06</span><a href="#The-valuable-part-of-low-code-lives-below-the-canvas" class="headerlink" title="The valuable part of low-code lives below the canvas"></a>The valuable part of low-code lives below the canvas</h2><p>A mature table component appears to offer columns, filters, pagination, and buttons. Its real accumulation sits underneath. How does it paginate large datasets? Do field permissions also constrain query and export? How are concurrent updates detected? What do locale and time zone do to sorting? How does the component behave on mobile or with assistive technology? What is retried after failure? Which actions produce audit evidence?</p><p>AI can certainly generate a table on demand. Generating a similar appearance does not reproduce every incident, correction, and trade-off learned over years of operation. The value of a mature component is not the number of lines it saves. It is a compressed history of failure turned into reusable default behavior.</p><figure class="article-figure"><img src="/assets/articles/ai-coding-low-code-trusted-build/figure-01-compressed-experience.webp?v=3ea49ca1d30f82a3" width="1672" height="941" loading="lazy" alt="A simple business table and form supported by a much larger hidden structure of permissions, concurrency, localization, audit, recovery, accessibility, and monitoring"><figcaption><p><strong>Figure 1 · A component is compressed engineering experience.</strong> The visible feature is small; the boundary behavior learned in real projects is much larger. AI can reconstruct the surface quickly. A trusted platform supplies the defaults that never appear in the demo path.</p></figcaption></figure><p>The same accumulation exists in workflow, identity, files, messaging, scheduling, and integration. An approval engine is not merely a set of connected boxes. It must account for withdrawal, reassignment, additional reviewers, duplicate submission, old workflow versions, departed employees, time zones, and business calendars. A file service is not just an upload button. It includes malware scanning, access control, lifecycle rules, and retention.</p><p>None of this means that using a mature component guarantees a stable application. Components can be combined incorrectly, and platforms have defects. The defensible claim is narrower and more useful: <strong>reusing proven capabilities reduces the amount of foundational failure each project must rediscover, but it does not eliminate architecture or acceptance testing.</strong></p><h2 id="From-development-tool-to-runtime-contract"><span class="section-no">07</span><a href="#From-development-tool-to-runtime-contract" class="headerlink" title="From development tool to runtime contract"></a>From development tool to runtime contract</h2><p>If the canvas is no longer central, what remains of low-code? I believe the answer is an application model that both people and machines can understand:</p><ul><li>the fields, uniqueness rules, states, and lifecycle of a business object;</li><li>the nodes, transitions, conditions, validations, and compensation paths in a process;</li><li>who may perform an action and which fields and records that person may see;</li><li>the semantic components on a page and the business capabilities on which they depend;</li><li>capacity, availability, audit, recovery, region, and retention requirements;</li><li>the live instances affected by a change and the checks required before release.</li></ul><p>When this information exists only as canvas coordinates and proprietary JSON, it remains configuration inside a closed tool. Once it has stable semantics, versions, interfaces, diffs, and validation rules, it becomes a runtime contract. AI can generate the contract, people can review it, the platform can execute it, and a delivery pipeline can verify it.</p><p>Writing on Martin Fowler’s site, Evan Bottcher describes a digital platform as self-service APIs, tools, services, knowledge, and support presented as a compelling internal product. A good platform offers a safe and compliant paved road rather than forcing every team down one mandated route. <sup class="ref"><a href="#ref-4">[4]</a></sup> The next generation of low-code should work the same way. It cannot become a larger shared-services queue, and it cannot use “governance” as an excuse for poor usability. Trusted defaults must be easier to consume than bypassing the platform and rebuilding them.</p><p class="part-label">Part III · Natural language plus CLI, not a magic textbox</p><h2 id="Natural-language-should-carry-business-intent"><span class="section-no">08</span><a href="#Natural-language-should-carry-business-intent" class="headerlink" title="Natural language should carry business intent"></a>Natural language should carry business intent</h2><p>Drag-and-drop works well for a local layout adjustment. It is a poor medium for the complete meaning of a business process. When a user asks for supplier onboarding, the important material is the set of objects, roles, transitions, exceptions, and obligations, not the coordinates of controls.</p><p>A useful AI should not immediately create pages. It should first turn the request into a plan that people can challenge:</p><div class="diagnostic"><h3>A structured interpretation of supplier onboarding</h3><ul><li><strong>Business objects:</strong> Supplier, credential, contract, bank account, risk review, and approval record.</li><li><strong>Roles:</strong> Supplier contact, procurement, legal, finance, compliance lead, and platform administrator.</li><li><strong>Main flow:</strong> Submission, procurement screening, legal review, account verification, risk classification, then approval or return.</li><li><strong>Conditional paths:</strong> High-risk suppliers require compliance review; expired credentials trigger resubmission.</li><li><strong>Operational constraints:</strong> Field-level permission, full audit, document retention, business calendar, escalation, and rollback.</li><li><strong>Open questions:</strong> Who owns risk classifications? Does a contract update restart the whole process? Can suppliers see internal rejection notes?</li></ul></div><p>This step can look like a delay because no code has appeared. In reality, it prevents one of the most expensive mistakes: a fluent interface hiding the assumptions the AI made on the user’s behalf. Natural language should not leave ambiguity permanently ambiguous. Its value is helping a team turn ambiguity into confirmable structure earlier.</p><h2 id="A-CLI-bridges-intent-and-engineered-delivery"><span class="section-no">09</span><a href="#A-CLI-bridges-intent-and-engineered-delivery" class="headerlink" title="A CLI bridges intent and engineered delivery"></a>A CLI bridges intent and engineered delivery</h2><p>Why introduce a CLI when the user can already describe the outcome? Because a sentence is suitable for expressing a goal, not for serving as a production change record. Enterprise delivery must identify the target environment, current version, exact mutation, validation result, and recovery material. A CLI turns those actions into repeatable, composable, auditable commands. It also lets an AI operate through business semantics instead of screen coordinates or guessed internal JSON.</p><p>The current Spark CLI provides a concrete example. It establishes an authentication profile, application, editable version, and workflow context before exposing commands such as add a node, connect a transition, or attach a validation rule. High-impact writes require an explicit <code>--yes</code>. The result can be checked and exported as a package. The visual designer remains the place for graphical inspection and human governance; the CLI handles automation, batch work, structured output, and AI integration. <sup class="ref"><a href="#ref-5">[5]</a></sup></p><p>The following is an illustrative scenario assembled from real command semantics. It assumes that the application, workflow, form, and reusable Step already exist. The names explain the method; they do not refer to a particular production environment.</p><figure class="highlight bash"><div class="table-wrap"><table><tbody><tr><td class="code"><pre><span class="line"><span class="comment"># Prove the target context instead of inferring it from chat history</span></span><br><span class="line">spark auth use spark-dev</span><br><span class="line">spark-designer task app use customer-service</span><br><span class="line">spark-designer task current</span><br><span class="line">spark-designer task workflow use <span class="string">"Complaint Handling"</span></span><br><span class="line">spark-designer task workflow current</span><br><span class="line">spark-designer task workflow describe --json</span><br><span class="line"></span><br><span class="line"><span class="comment"># Read the rules registered by the target service, then prepare a change plan</span></span><br><span class="line">spark-designer task workflow rule-types</span><br><span class="line"></span><br><span class="line"><span class="comment"># After a person approves the plan, add a quality review for major complaints</span></span><br><span class="line">spark-designer task workflow add-node \</span><br><span class="line">  --<span class="built_in">type</span> status \</span><br><span class="line">  --name <span class="string">"Quality Review"</span> \</span><br><span class="line">  --step <span class="string">"Quality Review"</span> \</span><br><span class="line">  --<span class="built_in">yes</span></span><br><span class="line"></span><br><span class="line">spark-designer task workflow connect \</span><br><span class="line">  <span class="string">"Product Review"</span> \</span><br><span class="line">  <span class="string">"Quality Review"</span> \</span><br><span class="line">  --name <span class="string">"Escalate Major Complaint"</span> \</span><br><span class="line">  --form qualityReview \</span><br><span class="line">  --<span class="built_in">yes</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Read back the result, run checks, and preserve recovery material</span></span><br><span class="line">spark-designer task workflow describe</span><br><span class="line">spark-designer task check workflow-config --<span class="built_in">yes</span></span><br><span class="line">spark-designer task package <span class="built_in">export</span> \</span><br><span class="line">  --output complaint-management-backup.json</span><br></pre></td></tr></tbody></table></div></figure><p>This is less magical than the invented <code>platform create</code> command in the original outline, and more useful for that reason. AI can still translate a business request into these operations, but it must show the target context, actual capability catalog, and expected change. A person confirms before the write; the tool reads back afterwards; the designer and a suitable runtime environment remain part of validation. The CLI does more than save typing. It gives generation an evidence trail that can be questioned.</p><div class="callout"><p><strong>Natural language is not deployment authority.</strong> It expresses intent. A structured plan exposes assumptions. The CLI performs traceable actions. Platform checks, a test environment, and accountable people decide whether the result may enter production.</p></div><h2 id="A-trusted-build-is-a-loop-not-a-prompt"><span class="section-no">10</span><a href="#A-trusted-build-is-a-loop-not-a-prompt" class="headerlink" title="A trusted build is a loop, not a prompt"></a>A trusted build is a loop, not a prompt</h2><p>Combining AI and low-code into a responsible delivery process requires roughly seven movements:</p><ol><li><strong>Express intent.</strong> A business owner states the outcome, roles, exceptions, and constraints that must not be violated.</li><li><strong>Form a plan.</strong> AI decomposes objects, workflows, permissions, components, and open questions without immediately changing production data.</li><li><strong>Prove context.</strong> Tools read the actual application, version, environment, and capability catalog so the wrong target is not modified.</li><li><strong>Compose capabilities.</strong> The platform prefers mature identity, workflow, SLA, audit, notification, and data components.</li><li><strong>Generate the difference.</strong> AI creates only the model, configuration, or extension code not covered by the platform, with an explicit impact surface.</li><li><strong>Verify the result.</strong> Automated checks cover primary flows, permission matrices, retries, escalation, recovery, and performance baselines; people validate business meaning and high-risk decisions.</li><li><strong>Operate and learn.</strong> Monitoring, audit, versioning, progressive delivery, and rollback produce evidence for the next change.</li></ol><figure class="article-figure"><img src="/assets/articles/ai-coding-low-code-trusted-build/figure-02-trusted-build-loop.webp?v=9e9074ab42429636" width="1672" height="941" loading="lazy" alt="A business intention moves through AI planning, a catalog of trusted components, several verification gates, and human approval into a running enterprise application, with operational evidence returning as feedback"><figcaption><p><strong>Figure 2 · The control chain from intent to trusted operation.</strong> Speed comes from interpreting intent and reusing capabilities. Trust comes from context, constraints, verification, accountable approval, and operational feedback. Remove any one of these and “an enterprise app from one sentence” merely defers the bill until after launch.</p></figcaption></figure><div class="table-wrap"><table><caption>Three approaches to application construction</caption><thead><tr><th>Approach</th><th>Primary interface</th><th>Default output</th><th>Strongest advantage</th><th>Main risk</th></tr></thead><tbody><tr><td>Open-ended AI coding</td><td>Natural language</td><td>Arbitrary code and dependencies</td><td>Fast exploration and high freedom</td><td>Architectural drift, verification debt, unclear ownership</td></tr><tr><td>Traditional low-code</td><td>Visual canvas and configuration</td><td>Proprietary platform model</td><td>Reuse and consistent delivery for common features</td><td>Awkward expression, constrained design, lock-in</td></tr><tr><td>AI with a trusted platform</td><td>Natural language, CLI, API, and canvas</td><td>Constrained, verifiable application model</td><td>Intent speed combined with engineering accumulation</td><td>Platform limits, incorrect composition, false certainty</td></tr></tbody></table></div><p>The third approach is not a mechanical sum of the first two. Its generation space is different. Open-ended AI coding may choose any framework, dependency, or design. A trusted platform prefers approved components, shared identity, and standard connectors. Sensitive actions must be audited, and releases must pass known gates. This reduces freedom, but it also reduces the cost of proving the same foundational properties for every new application.</p><p class="part-label">Part IV · Low-code still needs a revolution of its own</p><h2 id="“Fast-and-good”-is-not-automatic"><span class="section-no">11</span><a href="#“Fast-and-good”-is-not-automatic" class="headerlink" title="“Fast and good” is not automatic"></a>“Fast and good” is not automatic</h2><p>AI and low-code can improve speed and quality together, but the mechanism matters.</p><p>Speed comes mostly from interpreting intent and automating boilerplate configuration, documentation, and differential implementation. Quality comes mostly from mature components and a shared runtime, not from AI becoming incapable of error. Stability comes from failure boundaries, observability, and recovery. Reliability comes from constraints, tests, audit, and release ownership. Maintainability comes from models, code, versions, and decision records existing together.</p><p>Remove any one of those pieces and the promise changes. Natural language without a stable platform creates a fast-growing code pile. A closed platform without a better intent interface leaves users trapped in laborious configuration. Both together, without validation and responsibility, send mistakes into production at greater speed.</p><p>The division of labor is therefore subtler than “AI supplies speed and low-code supplies stability.” AI can help with testing and governance; a poor platform can slow everything down. The effective pattern is to let probabilistic generation propose candidates, deterministic systems enforce constraints, and people remain responsible for judgments that cannot be outsourced.</p><h2 id="Seven-changes-the-next-platform-must-make"><span class="section-no">12</span><a href="#Seven-changes-the-next-platform-must-make" class="headerlink" title="Seven changes the next platform must make"></a>Seven changes the next platform must make</h2><p>Years of component development do not guarantee that a low-code platform will survive this transition. If the accumulated knowledge remains locked inside browser clicks, private formats, and manual operations, AI cannot invoke it reliably and an enterprise cannot inspect it well.</p><div class="principles"><div class="principle"><strong>Models must be readable.</strong> Pages, data, workflows, permissions, and dependencies need stable semantics, not just canvas coordinates.</div><div class="principle"><strong>Changes must be comparable.</strong> Every generation should expose its diff, impact surface, breaking changes, and unverified risk.</div><div class="principle"><strong>Operations must be automatable.</strong> CLI and API coverage should include reading, mutation, checking, export, and release, with structured output.</div><div class="principle"><strong>Configuration must be versioned.</strong> Application models belong in Git or an equivalent system where they can be reviewed, reversed, and replayed.</div><div class="principle"><strong>Non-functional requirements must be first-class.</strong> Performance targets, availability, retention, deployment region, recovery objectives, and cost cannot wait until launch.</div><div class="principle"><strong>Extension and exit must exist.</strong> Specialized logic needs a controlled code boundary, while data, models, and interfaces need a migration path.</div><div class="principle"><strong>Generation must be explainable.</strong> The platform should state why a component was selected, what changed, what evidence exists, and how failure will be recovered.</div></div><p>Forrester analysts Diego Lo Giudice and John Bratincevic use the term AppGen for a related direction: an AI-native, business-aware full-stack platform with intermediate models between business intent and executable systems, plus domain knowledge and governance embedded in the platform. <sup class="ref"><a href="#ref-6">[6]</a></sup> Whether that label survives does not matter much, and their timeline for reshaping the software lifecycle remains a forecast. The more durable observation is that low-code and generative AI are converging, and the competitive unit is shifting from an editor to the entire application delivery chain.</p><p>Security cannot be established by a platform promise either. NIST’s Secure Software Development Framework places security requirements, provenance, design decisions, release integrity, and vulnerability response across the development lifecycle. <sup class="ref"><a href="#ref-7">[7]</a></sup> A platform that expects to carry core enterprise work must turn requirements like these into executable defaults and evidence, not check them once in a procurement questionnaire.</p><h2 id="A-stronger-platform-needs-clearer-boundaries-and-an-exit"><span class="section-no">13</span><a href="#A-stronger-platform-needs-clearer-boundaries-and-an-exit" class="headerlink" title="A stronger platform needs clearer boundaries and an exit"></a>A stronger platform needs clearer boundaries and an exit</h2><p>Not all software belongs on a shared low-code runtime. Novel interaction models, extreme performance or real-time requirements, infrastructure systems, algorithmically distinctive products, and regulated scenarios the platform has not proven may require direct engineering control. Even an ordinary business application can contain a rule too specific to force into the wrong component.</p><p>AI can also deepen platform lock-in. In the past, a developer at least knew which configuration screens had been used. In the future, AI may continuously invoke proprietary platform semantics while the application portfolio expands faster than the team can map its dependencies. A responsible platform needs data export, open interfaces, versioned models, observable runtime behavior, and explicit extension boundaries. A good paved road has signs and exits. It does not turn its guardrails into walls.</p><p>False certainty remains another danger. Stable components can still be assembled into an unstable system. An automatically generated permission matrix may be internally complete while misunderstanding the organization. Every test may pass because the tests simply repeat the AI’s mistaken assumption. A platform can lower risk. It cannot define correctness on behalf of the business owner or accept production consequences on behalf of the technical owner.</p><div class="pullquote"><p>Trust does not mean that the system has assumed human responsibility. It means that the facts, boundaries, and evidence required for responsibility no longer depend on memory.</p></div><h2 id="The-destination-is-not-No-Code-but-Trusted-Build"><span class="section-no">14</span><a href="#The-destination-is-not-No-Code-but-Trusted-Build" class="headerlink" title="The destination is not No Code, but Trusted Build"></a>The destination is not No Code, but Trusted Build</h2><p>AI coding will eliminate some low-code products. Platforms built mainly on templates, drag-and-drop, and the promise that non-programmers can make apps will struggle to justify their learning cost and lock-in. Natural language is more direct, conventional code is more open, and AI will keep improving the conversion between them.</p><p>Cheaper code does not make the whole cost of enterprise software cheap. If anything, more candidate implementations make proven components, explicit runtime contracts, automated governance, and recoverable delivery more scarce. Enterprises do not need a larger supply of code with unknown origins. They need controlled change at a lower cost.</p><p>The most competitive low-code platform may no longer begin with a canvas. A user states the business objective and AI produces a structured plan. The platform composes pages, data, workflow, and permissions from trusted capabilities. CLI and API calls make every mutation traceable. Tests, policy, and accountable approval decide whether to release. Operational evidence improves the next generation.</p><p>I call this <strong>Trusted Build</strong>, not to invent another market category, but to change the acceptance questions. We should ask more than whether the system can generate:</p><ul><li>Does it express the business intent and surface its unknown assumptions?</li><li>Does it reuse proven capabilities instead of rebuilding infrastructure?</li><li>Can it provide evidence about permissions, data, performance, and failure paths?</li><li>Is the change explainable, reversible, and transferable to another owner?</li><li>If the platform stops fitting, does the organization still own its data and business knowledge?</li></ul><p>If those questions have credible answers, AI coding and low-code are not engaged in a simple replacement war. AI changes the application interface. Low-code contributes capabilities selected by time and failure. The engineering system constrains both into a delivery process for which someone can responsibly answer.</p><p>The contest is no longer about who can let a non-programmer make software. AI has already pushed that door open. The harder question comes next: <strong>when everyone can generate software, who can make it worthy of an enterprise’s long-term trust?</strong></p><section class="references" id="references"><h2 data-no-number="true">References and further reading</h2><ol><li id="ref-1"><a href="https://www.youtube.com/live/LCEmiRjPEtQ">Andrej Karpathy, “Software Is Changing (Again),” AI Startup School</a>, Y Combinator, 2025.</li><li id="ref-2"><a href="https://addyo.substack.com/p/the-70-problem-hard-truths-about">Addy Osmani, “The 70% Problem: Hard Truths About AI-Assisted Coding”</a>, 2024.</li><li id="ref-3"><a href="https://dora.dev/research/2025/dora-report/">DORA, <em>State of AI-assisted Software Development 2025</em></a>, Google Cloud, 2025.</li><li id="ref-4"><a href="https://martinfowler.com/articles/talk-about-platforms.html">Evan Bottcher, “What I Talk About When I Talk About Platforms”</a>, MartinFowler.com, 2018.</li><li id="ref-5"><a href="https://spark.hiforce.ai/docs/spark-cli/overview/">Spark CLI Overview</a>, HiFORCE Spark, 2026.</li><li id="ref-6"><a href="https://www.forrester.com/blogs/appgen-is-here-say-goodbye-to-software-development-as-you-know-it/">Diego Lo Giudice and John Bratincevic, “AppGen Is Here: Say Goodbye To Software Development As You Know It”</a>, Forrester, 2025.</li><li id="ref-7"><a href="https://csrc.nist.gov/projects/ssdf">NIST, <em>Secure Software Development Framework (SSDF) Version 1.1</em></a>, 2022, updated 2026.</li></ol></section>]]>
    </content>
    <id>https://ryu.xin/posts/ai-coding-low-code-trusted-build/</id>
    <link href="https://ryu.xin/posts/ai-coding-low-code-trusted-build/"/>
    <published>2026-08-05T16:00:00.000Z</published>
    <summary>AI coding weakens the old low-code speed advantage, but makes proven components, runtime contracts, and enterprise governance more valuable. A practical argument for combining natural language, Spark CLI, and a trusted application platform.</summary>
    <title>Will AI Coding Kill Low-Code?</title>
    <updated>2026-08-05T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Rocky Yu</name>
    </author>
    <category term="Software Engineering" scheme="https://ryu.xin/categories/software-engineering/"/>
    <category term="AI" scheme="https://ryu.xin/tags/AI/"/>
    <category term="Software Engineering" scheme="https://ryu.xin/tags/Software-Engineering/"/>
    <category term="Organizations" scheme="https://ryu.xin/tags/Organizations/"/>
    <category term="Books" scheme="https://ryu.xin/tags/Books/"/>
    <content>
      <![CDATA[<header class="abstract"><h2 data-no-number="true">Abstract</h2><p>AI has made code generation astonishingly fast. It has also encouraged a dangerous assumption: if implementation is cheaper, software projects should move faster and teams should shrink. In practice, the opposite pressures soon appear. More generated code means more to understand, test, coordinate, and own. The more agents can do in parallel, the more human attention, judgment, and accountability become points of congestion.</p><p><em>Peopleware</em> was never merely a book about noisy offices or management technique. It was a book about the conditions under which knowledge work can happen: how concentration forms, how teams cohere, how trust makes learning possible, and how management quietly destroys all three. AI has not made those questions obsolete. It has simply added machines to the list of things that can interrupt us, while giving every strength and weakness in an organization a larger lever.</p></header><p class="thesis">AI has changed the speed of software production. It has not changed the fact at the heart of <em>Peopleware</em>: the hardest part of a software project is rarely the code. It is the people living with it.</p><p class="part-label">Part I · The people hidden by the tools</p><h2 id="Why-revisit-Peopleware-now"><span class="section-no">01</span><a href="#Why-revisit-Peopleware-now" class="headerlink" title="Why revisit Peopleware now?"></a>Why revisit <em>Peopleware</em> now?</h2><p class="lead dropcap">The first time I read <em>Peopleware</em>, I took it for a book about managing software teams. Its concerns seemed wonderfully concrete: noisy offices, too many meetings, impossible schedules, staff turnover, team cohesion, and the many ways a manager can dismantle a good team without quite realizing it.</p><p>Reading it again after the arrival of AI coding tools, I noticed that Tom DeMarco and Timothy Lister were asking a more fundamental question. <strong>In software development, is the real constraint technical—or human?</strong></p><p>For years, the industry treated productivity as a typing problem. We invented higher-level languages, more capable frameworks, better IDEs, and increasingly automated delivery pipelines. AI has carried that instinct to its logical extreme. One developer can now ask several agents to search a repository, change code, write tests, inspect logs, and update documentation at the same time. Work that once took days can produce a plausible candidate in hours.</p><p>And yet projects have not acquired infinite speed. Requirements are still ambiguous. Systems still have histories. Boundaries still require judgment. Releases still fail. Responsibility still has to land somewhere. When the third edition of <em>Peopleware</em> appeared in 2013, its publisher still described software development as being shaped by human rather than technical issues. In the age of agents, that claim feels sharper, not weaker.<sup class="ref"><a href="#ref-1">[1]</a></sup></p><blockquote><p>As execution gets cheaper, framing, judgment, verification, and ownership get more expensive. AI did not remove the human bottleneck. It moved it upstream from the keyboard into the decision chain.</p></blockquote><h2 id="The-bottleneck-did-not-disappear-It-moved"><span class="section-no">02</span><a href="#The-bottleneck-did-not-disappear-It-moved" class="headerlink" title="The bottleneck did not disappear. It moved."></a>The bottleneck did not disappear. It moved.</h2><p>In conventional development, implementation time was the most visible scarcity. Plans revolved around one question: how long will it take to build? AI cuts that cost dramatically, but it does not reduce every adjacent cost at the same rate. Someone still has to understand the problem, choose an approach, review the change, verify the business rules, assess security, plan a migration, observe the release, and restore service when things go wrong.</p><p>The cost simply travels downstream. The old shape of the work might have been four hours of coding followed by one hour of review. The new shape might be ten minutes of generation followed by two hours of reconstruction and verification. In the first case, the waiting happened before production. In the second, the queue forms after it. Measure only generation and the improvement looks spectacular. Measure the entire value stream and the gain may be modest—or swallowed by rework.</p><p>DORA’s 2025 research on AI-assisted software development treats this as a systems problem. AI magnifies the conditions already present in a team and its delivery system. Strong platforms, loosely coupled architectures, and fast feedback can absorb a larger volume of change. Weak tests, slow workflows, and tightly coupled systems turn that same volume into instability.<sup class="ref"><a href="#ref-6">[6]</a></sup></p><div class="callout"><p><strong>The useful comparison is not “human coding speed” versus “AI coding speed.”</strong></p><p>It is whether the whole system moves a problem from discovery to safe, maintainable value any faster.</p></div><p>That is where a modern reading of <em>Peopleware</em> begins: never mistake the local speed of a tool for the productivity of an organization.</p><p class="part-label">Part II · Attention becomes the new production line</p><h2 id="AI-removed-waiting—and-created-more-interruption"><span class="section-no">03</span><a href="#AI-removed-waiting—and-created-more-interruption" class="headerlink" title="AI removed waiting—and created more interruption"></a>AI removed waiting—and created more interruption</h2><p>One of the most durable ideas in <em>Peopleware</em> is the value of uninterrupted time. Programmers, designers, and architects rarely do their best work in the gaps between notifications. The problem, the code, the business constraints, and the available design choices have to coexist in the mind long enough to become a usable model.</p><p>That model may take fifteen minutes to assemble; it may take half an hour. A message that consumes two minutes can therefore cost much more than two minutes. Research on task switching finds the same pattern: changing tasks requires people to shift goals and reactivate rules, and the cost grows with the complexity of those rules.<sup class="ref"><a href="#ref-2">[2]</a></sup></p><p>In the old development environment, interruptions mostly came from other people: a product manager asking for status, a tester reporting a bug, a manager calling an impromptu meeting, a colleague asking for help. In the AI environment, machines have joined the queue.</p><p>A developer may have three, five, or more agents running at once: one refactoring a service, another building a UI, a third writing tests, a fourth reading production logs. Each returns results, asks questions, requests permissions, reports a failure, or waits for a decision. The developer stops working on one coherent problem and starts hopping among several partially remembered worlds:</p><ul><li>What exactly did agent A change, and did it cross the task boundary?</li><li>Is agent B’s failing test a code problem or an environment problem?</li><li>Which approach did agent C take, and what assumptions did it discard?</li><li>How do I stop agent D from “helpfully” refactoring an unrelated module?</li><li>How do these independent outputs fit back into one system?</li></ul><p>The programmer has become a scheduler of concurrent cognitive work. The catch is simple: agents can run in parallel; human understanding, judgment, and accountability remain largely serial.</p><figure class="article-figure"><img src="/assets/articles/peopleware-ai-era/figure-peopleware-attention-bottleneck.webp?v=43cae87c946f1926" width="1672" height="941" loading="lazy" alt="An engineer sits at the center of a circular workspace while many AI tools send tasks and results inward, making human attention the bottleneck"><figcaption><p><strong>Figure 1 · The attention bottleneck.</strong> Machines can produce ten results at once. A person still has to rebuild the context, judge the risk, and accept responsibility one result at a time. Concurrency expands the supply of candidates, not the bandwidth of the human mind.</p></figcaption></figure><p>This explains a distinctly modern kind of exhaustion. You may spend little of the day typing and still finish it depleted. The effort went into rebuilding context, handling exceptions, and closing cognitive loops that kept reopening.</p><div class="pullquote"><p>Managers once interrupted programmers with meetings. Now programmers can launch ten agents and interrupt themselves.</p></div><h2 id="Code-is-abundant-High-quality-attention-is-not"><span class="section-no">04</span><a href="#Code-is-abundant-High-quality-attention-is-not" class="headerlink" title="Code is abundant. High-quality attention is not."></a>Code is abundant. High-quality attention is not.</h2><p>The easiest mistake in AI-assisted development is to confuse lower implementation cost with lower cost everywhere. When generation capacity surges upstream, review, testing, integration, and decision-making become the new places where work waits.</p><p>Code can be generated in parallel; careful review cannot scale without limit. Options can be produced in batches; a team still has to choose among them. Tests can run automatically; someone still has to understand why they failed. Agents can retry indefinitely; people still own the production incident. If every workflow sends every exception to a human, attention becomes the single-threaded lock shared by the entire automation system.</p><p>A manager therefore needs questions more useful than “How many more agents can we add?”</p><div class="principles"><div class="principle"><strong>Is the input ready?</strong> — Which tasks deserve generation, and which problems are still too vague to delegate?</div><div class="principle"><strong>Can the output be filtered?</strong> — What should be rejected, deduplicated, or combined automatically before it reaches an engineer?</div><div class="principle"><strong>Is ownership explicit?</strong> — Who makes the final call, verifies business correctness, and decides to merge or release?</div><div class="principle"><strong>Is concurrency bounded?</strong> — How many live contexts can one person carry without losing the shape of the system?</div></div><p>Without answers, adding agents is like increasing the speed of an upstream conveyor belt after the line is already jammed. The result is not faster delivery. It is a review backlog, an overloaded test system, architectural drift, and more operational risk.</p><p>When production becomes cheap, the organization has to protect attention—not spend it even faster.</p><h2 id="The-codebase-grew-The-team’s-understanding-did-not"><span class="section-no">05</span><a href="#The-codebase-grew-The-team’s-understanding-did-not" class="headerlink" title="The codebase grew. The team’s understanding did not."></a>The codebase grew. The team’s understanding did not.</h2><p>Software organizations have always been tempted to substitute visible activity for difficult-to-measure value: lines of code, commit counts, features shipped, tickets closed, sprint velocity. AI makes those proxies more dangerous.</p><p>An agent can produce thousands of lines in minutes. It can create a dozen modules in one pass. It can turn a small fix into a handsome, fully structured refactor. If output is still the measure of productivity, AI can make almost any team’s numbers look excellent.</p><p>But code is not automatically an asset. It becomes one only when the team understands it, has evidence that it works, can change it safely, and knows why it exists. Otherwise, faster generation does not build capability. It builds <strong>cognitive debt</strong>.</p><p>When a developer writes a piece of code, they usually remember why it took that shape, which boundary conditions mattered, and which alternatives were rejected. The documentation may be incomplete, but the decision passed through a human mind. AI-generated code can arrive in the repository without that journey. It may run. It may pass the tests. It may even look cleaner than the handwritten version. And no one on the team may truly own it.</p><figure class="article-figure"><img src="/assets/articles/peopleware-ai-era/figure-peopleware-cognitive-debt.webp?v=411f4e0c90bf18ba" width="1672" height="941" loading="lazy" alt="Three team members study a limited system map while AI tools rapidly expand a vast modular city beyond a narrow bridge"><figcaption><p><strong>Figure 2 · Cognitive debt.</strong> The system expands in code while the team’s shared mental model remains on the other side of the bridge. The real risk is not who wrote the code, but whether anyone can explain it, change it, and recover it.</p></figcaption></figure><p>This creates a convincing project illusion. The feature is done. The demo works. The repository is growing. Yet the engineers are looking at a system that feels less familiar every week. Only when production misbehaves, a business rule changes, or a cross-cutting refactor becomes necessary does the organization discover that generated code never became controlled software capability.</p><p>In 2025, METR ran a randomized study with 16 experienced developers working on 246 real tasks in mature open-source repositories. With the particular tools and sample used at the time, developers allowed to use AI took about 19 percent longer on average, even while believing they had become faster. The researchers stressed that this was a snapshot of early-2025 tools and a specific population. By 2026, selection effects made a follow-up experiment too unreliable to support a confident current estimate. The enduring lesson is not that “AI makes developers slower.” It is that <strong>feeling faster is not a substitute for measuring the whole workflow.</strong><sup class="ref"><a href="#ref-7">[7]</a></sup><sup class="ref"><a href="#ref-8">[8]</a></sup></p><div class="callout"><p><strong><em>Peopleware</em> warned us:</strong> do not confuse time at a desk with useful work.</p><p><strong>The AI-era corollary:</strong> do not confuse model output with capability the team has actually acquired.</p></div><p class="part-label">Part III · A team is not a container to be compressed</p><h2 id="Psychological-safety-is-part-of-AI-reliability"><span class="section-no">06</span><a href="#Psychological-safety-is-part-of-AI-reliability" class="headerlink" title="Psychological safety is part of AI reliability"></a>Psychological safety is part of AI reliability</h2><p><em>Peopleware</em> returns again and again to a truth that management theory often misses: a team cannot be assembled into cohesion by command. A real team develops trust, a shared purpose, an identity, and enough autonomy to act as a unit. None of these qualities matters less in the AI era. They matter more.</p><p>As AI takes on more coding work, engineers have reasonable questions. Is my experience becoming less valuable? Is the company adopting AI to help me, or to reduce headcount? If I turn my working methods into a skill or an agent, am I documenting my way out of a job? When generated code fails, who is accountable?</p><p>If management avoids those questions and talks only about efficiency, people protect themselves. Some keep useful methods private rather than turn them into organizational knowledge. Some perform adoption without changing how they work. Some create complexity only they can explain. Others lower their sense of ownership because “the model wrote it.” None of this is irrational. It is what uncertainty produces when candor feels unsafe.</p><p>Amy Edmondson defined team psychological safety as a shared belief that interpersonal risk-taking is safe within the team. Her study of 51 work teams associated psychological safety with learning behavior, which in turn connected to team performance.<sup class="ref"><a href="#ref-3">[3]</a></sup> AI collaboration demands exactly this kind of risk-taking. People have to be able to say:</p><ul><li>“I do not understand this generated code yet.”</li><li>“The tests pass, but I do not believe they cover the real risk.”</li><li>“My prompt sent this in the wrong direction. We should start again.”</li><li>“This problem is not ready for more automation. We need to clarify it first.”</li></ul><figure class="article-figure"><img src="/assets/articles/peopleware-ai-era/figure-peopleware-psychological-safety.webp?v=790d147eef7c493b" width="1672" height="941" loading="lazy" alt="Five team members discuss incomplete system models around a shared table while their collaboration forms a protective structure and AI tools provide materials"><figcaption><p><strong>Figure 3 · Safety creates room to learn.</strong> A team can catch mistakes before production only if incomplete models, doubts, and bad news are welcome at the same table. Agents bring material; trust determines whether that material receives an honest evaluation.</p></figcaption></figure><p>If an organization makes “I don’t know” unsafe, AI magnifies false certainty. The model answers confidently. The engineer hesitates to object. The manager wants a visible win. Those three forces can carry code that nobody understands through every review and into production.</p><div class="pullquote"><p>Psychological safety is not a soft corporate benefit. It is the mechanism that lets bad news reach the team before it becomes an incident.</p></div><h2 id="Teamicide-in-the-AI-era"><span class="section-no">07</span><a href="#Teamicide-in-the-AI-era" class="headerlink" title="Teamicide in the AI era"></a>Teamicide in the AI era</h2><p><em>Peopleware</em> coined a wonderfully severe word: <em>teamicide</em>. Capable teams are often damaged not by a lack of talent, but by the way they are managed—impossible deadlines, constant reshuffling, internal competition, excessive standardization, and process used as a substitute for trust.</p><p>AI gives management several new ways to commit the same old crime.</p><h3 id="Turn-engineers-into-agent-operators"><a href="#Turn-engineers-into-agent-operators" class="headerlink" title="Turn engineers into agent operators"></a>Turn engineers into agent operators</h3><p>A manager may decide that the model can now handle most technical work, gradually remove design authority from engineers, and leave them to receive tasks, invoke agents, and submit the results. Output may rise for a while. Judgment will not. People who are no longer expected to make design decisions eventually lose the opportunity—and then the ability—to make good ones.</p><h3 id="Turn-AI-use-into-an-individual-output-contest"><a href="#Turn-AI-use-into-an-individual-output-contest" class="headerlink" title="Turn AI use into an individual output contest"></a>Turn AI use into an individual output contest</h3><p>Who generated the most code? Who closed the most tickets? Who ran the most agents at once? These metrics look objective and reward exactly the wrong thing: local activity at the expense of shared review, knowledge, and responsibility. The SPACE framework already argues that developer productivity spans satisfaction and well-being, performance, activity, communication and collaboration, and efficiency and flow. No single activity metric can stand in for the whole.<sup class="ref"><a href="#ref-4">[4]</a></sup> As generation gets cheaper, the distance between activity and value only grows.</p><h3 id="Cut-until-the-system-loses-its-memory"><a href="#Cut-until-the-system-loses-its-memory" class="headerlink" title="Cut until the system loses its memory"></a>Cut until the system loses its memory</h3><p>Once some tasks can be automated, it is tempting to conclude that work once done by ten people now requires three. But those ten people did more than write code. They carried business memory, operational judgment, cross-functional relationships, customer context, on-call experience, and spare capacity for the unexpected. Those contributions are almost invisible in task counts. They are also what let a team recover when reality departs from the plan.</p><p>The people who look least productive on a dashboard may be carrying the context the system cannot regenerate.</p><div class="table-wrap"><table><caption>Three common forms of AI-era teamicide</caption><thead><tr><th>Management move</th><th>Short-term appearance</th><th>Long-term loss</th></tr></thead><tbody><tr><td>Reduce engineers to operators</td><td>Faster tasks, more uniform process</td><td>Weaker design judgment; no owner for hard problems</td></tr><tr><td>Rank people by AI activity</td><td>More commits, code, and closed tickets</td><td>Local optimization, shallow review, hoarded knowledge</td></tr><tr><td>Cut roles by automatable task count</td><td>Rapid reduction in labor cost</td><td>Lost memory, resilience, and recovery capacity</td></tr></tbody></table></div><h2 id="The-best-AI-team-is-not-the-one-with-the-fewest-people"><span class="section-no">08</span><a href="#The-best-AI-team-is-not-the-one-with-the-fewest-people" class="headerlink" title="The best AI team is not the one with the fewest people"></a>The best AI team is not the one with the fewest people</h2><p>The AI era has produced an extreme but seductive picture of the future: one founder, surrounded by a tireless workforce of agents. That model can produce prototypes at remarkable speed. It may even operate a small product with clear boundaries. It is less convincing as a plan for the long life of a complex system, because the hardest problems in such systems are rarely questions of code generation.</p><p>Complex systems need the friction of different responsibilities. Architects think about long-term evolution. Developers see implementation and readability. Testers search for failure paths. Operators watch runtime behavior. Product people ask whether the work creates value. Security specialists imagine the paths ordinary use never takes.</p><p>AI can simulate each role and list the questions it might ask. What it struggles to reproduce is the judgment created by real consequences. The person responsible for production stability treats a harmless-looking dependency update differently. Someone who has lived through a financial reconciliation failure asks about idempotency before being prompted. Someone who has served the same customers for years knows which innocent sentence in the requirements is actually non-negotiable. That knowledge comes from experience under responsibility, not from information alone.</p><p>The aim of a strong AI team, then, is not to drive the human count toward zero. It is to move human time away from mechanical implementation and toward work that carries more value: framing problems, designing boundaries, testing reality, handling exceptions, building knowledge, repairing systems, and making tradeoffs that can be explained.</p><div class="callout"><p><strong>AI’s value is not that it can erase the team. It is that it can let the team spend its attention differently.</strong></p><p>Removing pointless labor is a means. Preserving judgment, learning, and recovery capacity is the return.</p></div><p class="part-label">Part IV · Designing an environment for people and agents</p><h2 id="The-manager’s-new-job-redesign-the-work-environment"><span class="section-no">09</span><a href="#The-manager’s-new-job-redesign-the-work-environment" class="headerlink" title="The manager’s new job: redesign the work environment"></a>The manager’s new job: redesign the work environment</h2><p>In the view of <em>Peopleware</em>, management is not primarily the art of keeping people busy. It is the work of creating an environment in which people can get something done. That idea survives intact in the AI era, but the environment has become larger.</p><p>It now includes more than quiet rooms, sensible meetings, and stable teams. It includes which resources an agent may access; which actions require human approval; which results must pass automated checks; how much of the system one task may change; how context is preserved and handed over; how concurrent workflows avoid overwriting each other; how work stops, rolls back, and recovers after failure; and who owns the final result.</p><p>None of this can be solved by adding one clever sentence to a prompt. If an organization buys AI tools for everyone but leaves the development system untouched, AI becomes an accelerator bolted onto the old machinery. It produces code faster. It does not make the requirements clearer, the decisions wiser, the tests stronger, or the releases safer.</p><figure class="article-figure"><img src="/assets/articles/peopleware-ai-era/figure-peopleware-human-agent-environment.webp?v=630ce7b744eb3d61" width="1672" height="941" loading="lazy" alt="AI tools send a large stream of modules into a system where people sort and validate them through recovery paths and quiet workspaces before they reach a stable shared environment"><figcaption><p><strong>Figure 4 · The environment is the control system.</strong> Management is not the act of demanding more upstream generation. It is the design of boundaries, gates, feedback, recovery paths, and quiet spaces that let speed arrive in a system people can understand and own.</p></figcaption></figure><p>The real change is to treat software delivery as an operating system shared by people and agents. Machines search, generate, repeat, and perform preliminary checks. People define goals, resolve ambiguity, make tradeoffs, recognize risk, and accept responsibility. The interface between those roles has to be explicit. So does the pace.</p><h2 id="Treat-human-attention-as-capacity-not-as-a-free-resource"><span class="section-no">10</span><a href="#Treat-human-attention-as-capacity-not-as-a-free-resource" class="headerlink" title="Treat human attention as capacity, not as a free resource"></a>Treat human attention as capacity, not as a free resource</h2><p>The most common design error in an AI workflow is to count model throughput without counting human absorption. A patch may cost almost nothing to generate. Turning it into a trustworthy change still requires review time, domain knowledge, test evidence, and a release window. If any one of those is scarce, candidates wait in line.</p><div class="equation"><p><strong>Effective delivery = min (generation, understanding, verification, release and recovery)</strong> This is a management constraint, not a formal equation: system throughput is bounded by its narrowest point.</p></div><p>Even a team with unlimited agents cannot deliver faster than its weakest control loop. Too much work in progress also damages the very capacity needed to clear it. Unfinished reviews, unanswered questions, parallel branches, and unresolved options occupy working memory and make every context switch more expensive.</p><p>Limiting concurrency is not a retreat from modern tooling. It is an engineering measure that protects cognitive integrity. A team can start with a few unglamorous practices:</p><ul><li>Set a limit on active agent workflows per engineer instead of rewarding unlimited concurrency.</li><li>Filter low-confidence, duplicate, and out-of-scope results automatically before asking for human attention.</li><li>Require every agent to deliver a change summary, key assumptions, verification evidence, and known gaps.</li><li>Reserve uninterrupted, notification-free time for understanding and reviewing complex work.</li><li>Measure the path from start to safe production, not merely the time the model spent generating.</li></ul><p>Productivity research supports this broader view. SPACE rejects the single metric; DORA emphasizes the way platforms, process, architecture, and value streams shape the outcome of AI adoption.<sup class="ref"><a href="#ref-4">[4]</a></sup><sup class="ref"><a href="#ref-6">[6]</a></sup> The manager’s real optimization target is not “model calls per engineer.” It is whether the team can deliver the right value with less cognitive strain and more dependable quality.</p><h2 id="Six-Peopleware-rules-for-AI-teams"><span class="section-no">11</span><a href="#Six-Peopleware-rules-for-AI-teams" class="headerlink" title="Six Peopleware rules for AI teams"></a>Six <em>Peopleware</em> rules for AI teams</h2><p>Bringing <em>Peopleware</em> into an agent workflow does not require a grand new management doctrine. A better place to start is to turn respect for human work into concrete system constraints.</p><div class="principles"><div class="principle"><strong>01 · Protect continuity</strong> — Treat deep understanding and review time as production capacity. Batch agent updates instead of making every event an interruption.</div><div class="principle"><strong>02 · Limit work in progress</strong> — Bound concurrency by human capacity to understand and verify, not by the number of tasks the tools can launch.</div><div class="principle"><strong>03 · Keep decisions and ownership together</strong> — Name who frames the goal, accepts the risk, and owns the release. “AI-generated” must never mean ownerless.</div><div class="principle"><strong>04 · Reward shared capability</strong> — Recognize reusable knowledge, review quality, and team outcomes—not code volume, commit counts, or the number of agents used.</div><div class="principle"><strong>05 · Make uncertainty speakable</strong> — Leaders should model questions, admit what they do not know, and thank people for bad news. Challenging the model is normal engineering work.</div><div class="principle"><strong>06 · Preserve memory and slack</strong> — Experience without a visible output is not waste. Stable teams, cross-training, and recovery capacity are insurance for the system.</div></div><div class="diagnostic"><h3>A five-minute diagnostic for managers</h3><ol><li>Can the team say whether generation, understanding, verification, or release capacity is currently the scarcest?</li><li>How many active agent workflows does one engineer carry? Was that number chosen deliberately?</li><li>When was a model output last rejected? Did the reason become a rule, test, or evaluation?</li><li>Can someone say “I don’t understand this code” without being judged as bad at AI?</li><li>Is time saved by AI reinvested in learning, quality, and customer value—or immediately filled with more work?</li></ol></div><h2 id="The-better-AI-gets-the-more-Peopleware-matters"><span class="section-no">12</span><a href="#The-better-AI-gets-the-more-Peopleware-matters" class="headerlink" title="The better AI gets, the more Peopleware matters"></a>The better AI gets, the more <em>Peopleware</em> matters</h2><p><em>The Mythical Man-Month</em> taught us that adding people does not accelerate a software project linearly because communication and coordination grow with the team. <em>Peopleware</em> went further: even without adding people, even with better tools, productivity collapses when an organization ignores cognition, emotion, relationships, and the conditions of work.</p><p>AI has not overturned either book. It has given their old problems new forms.</p><p>We once worried about adding programmers to a late project. Now we should worry about adding agents to a process already out of control. Managers once consumed engineers’ days with meetings, reports, and procedure. Now model output, permission requests, review queues, and parallel tasks can consume the same finite attention. Teams once lost flow to office noise. Now they can lose it to AI workflows that never stop asking for the next decision.</p><p>The more capable the tool becomes, the easier it is to see the person as the slow, expensive component that should be compressed. Yet this is exactly when judgment, trust, responsibility, and imagination become most valuable. AI can generate code, but it cannot decide on behalf of an organization what deserves to exist. It can offer options, but it cannot carry the consequences of choosing one. It can imitate the language of collaboration, but it cannot automatically create trust.</p><p>After rereading <em>Peopleware</em>, my conclusion is not the comforting slogan that people will never be replaced. It is something less reassuring and more useful:</p><p>AI will not make a software organization better by itself. It will make the organization more like itself.</p><p>An organization that trusts people, protects focus, and cares about quality can use AI to extend its abilities dramatically. One that worships metrics, exhausts teams, and chases short-term output will use the same technology to accumulate technical debt, cognitive debt, and organizational debt at greater speed. DORA’s description of AI as an amplifier gives that observation a timely empirical echo.<sup class="ref"><a href="#ref-5">[5]</a></sup></p><p>The software teams that lead the next era may not run the most agents or have permanent access to the strongest model. They may simply be the first to understand that when code is no longer scarce, people are what must be protected.</p><section class="references" id="references"><h2 data-no-number="true">References and further reading</h2><p class="note"><em>Peopleware</em> provides the essay’s central line of argument. The research below is used to ground the discussion of task switching, psychological safety, and productivity measurement. Links point to publishers, paper records, or the research organizations themselves.</p><ol><li id="ref-1">DeMarco, Tom, and Timothy Lister. <em><a href="https://www.pearson.com/en-us/subject-catalog/p/peopleware-productive-projects-and-teams/P200000000214/9780321934116">Peopleware: Productive Projects and Teams</a></em>, 3rd ed. Addison-Wesley Professional, 2013.</li><li id="ref-2">Rubinstein, Joshua S., David E. Meyer, and Jeffrey E. Evans. “<a href="https://pubmed.ncbi.nlm.nih.gov/11518143/">Executive Control of Cognitive Processes in Task Switching</a>.” <em>Journal of Experimental Psychology: Human Perception and Performance</em>, 27(4), 2001.</li><li id="ref-3">Edmondson, Amy. “<a href="https://doi.org/10.2307/2666999">Psychological Safety and Learning Behavior in Work Teams</a>.” <em>Administrative Science Quarterly</em>, 44(2), 1999.</li><li id="ref-4">Forsgren, Nicole, et al. “<a href="https://www.microsoft.com/en-us/research/publication/the-space-of-developer-productivity-theres-more-to-it-than-you-think/">The SPACE of Developer Productivity: There’s More to It Than You Think</a>.” <em>ACM Queue</em>, 19(1), 2021.</li><li id="ref-5">Harvey, Nathen, and Derek DeBellis. “<a href="https://cloud.google.com/blog/products/ai-machine-learning/announcing-the-2025-dora-report">Announcing the 2025 DORA Report: State of AI-Assisted Software Development</a>.” Google Cloud Blog, 2025.</li><li id="ref-6">DORA / Google Cloud. “<a href="https://cloud.google.com/resources/content/2025-dora-ai-assisted-software-development-report">2025 State of AI-Assisted Software Development Report</a>.” 2025.</li><li id="ref-7">Becker, Joel, et al. “<a href="https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/">Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity</a>.” METR, 2025.</li><li id="ref-8">Becker, Joel, et al. “<a href="https://metr.org/blog/2026-02-24-uplift-update/">We Are Changing Our Developer Productivity Experiment Design</a>.” METR, 2026.</li><li id="ref-9">Brooks, Frederick P. Jr. <em>The Mythical Man-Month: Essays on Software Engineering</em>. Addison-Wesley, 1975; Anniversary Edition, 1995.</li><li id="ref-10">Skelton, Matthew, and Manuel Pais. <em>Team Topologies: Organizing Business and Technology Teams for Fast Flow</em>. IT Revolution, 2019.</li></ol></section>]]>
    </content>
    <id>https://ryu.xin/posts/peopleware-ai-era/</id>
    <link href="https://ryu.xin/posts/peopleware-ai-era/"/>
    <published>2026-07-30T16:00:00.000Z</published>
    <summary>A fresh reading of Peopleware for the age of coding agents: when code is abundant, attention, trust, judgment, and shared responsibility become the scarce resources.</summary>
    <title>Revisiting Peopleware: The Better AI Gets, the More Software Depends on People</title>
    <updated>2026-07-30T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Rocky Yu</name>
    </author>
    <category term="Software Engineering" scheme="https://ryu.xin/categories/software-engineering/"/>
    <category term="AI" scheme="https://ryu.xin/tags/AI/"/>
    <category term="Software Engineering" scheme="https://ryu.xin/tags/Software-Engineering/"/>
    <category term="Architecture" scheme="https://ryu.xin/tags/Architecture/"/>
    <category term="Books" scheme="https://ryu.xin/tags/Books/"/>
    <content>
      <![CDATA[<header class="abstract"><h2 data-no-number="true">Abstract</h2><p>Generative AI has pushed the marginal cost of producing code to a level few software teams would have believed possible only a few years ago. That has encouraged a seductive conclusion: if code can be produced almost on demand, the old laws of software engineering must be on their way out.</p><p>This essay argues the opposite. What endures in <em>The Mythical Man-Month</em> is not Brooks’s view of a particular language or tool. It is his account of complexity, communication, organizational structure, and conceptual integrity. AI changes the division of labor and the speed of feedback. It does not decide what a product ought to be, which constraints matter, or who remains answerable when a system fails.</p><p>The chapters that follow revisit Brooks’s central arguments and carry them forward into coding agents, multi-agent coordination, context engineering, architecture constraints, evaluation, and organizational knowledge. The point is neither that AI is merely another tool nor that it makes software engineering obsolete. The control plane of software development is moving upward—from code toward knowledge, boundaries, and systems of verification.</p></header><p class="thesis">AI has not retired <em>The Mythical Man-Month</em>. It has enlarged the question: from organizing programmers to produce code, to organizing people and agents to keep complexity under control.</p><p class="part-label">Part I · Returning to Brooks's problem</p><h2 id="Why-reread-The-Mythical-Man-Month-now"><span class="section-no">01</span><a href="#Why-reread-The-Mythical-Man-Month-now" class="headerlink" title="Why reread The Mythical Man-Month now?"></a>Why reread <em>The Mythical Man-Month</em> now?</h2><p class="lead dropcap">When <em>The Mythical Man-Month</em> first appeared in 1975, software was typed into terminals by hand, build cycles were expensive, and large systems were the province of a small number of institutions. Half a century later, we can ask a model—in ordinary language—to write an endpoint, expand a test suite, migrate a framework, or dispatch several agents into isolated workspaces. It looks like a different profession. Yet we have arrived at a version of Brooks’s old tar pit: output rises, but the system does not necessarily become easier to understand; more participants join the work, but the project does not necessarily finish sooner. <sup class="ref"><a href="#ref-1">[1]</a></sup></p><p>The book survives because it is less concerned with tools than with ratios. How much of the work can be parallelized, and how much still depends on sequential decisions? How much local speed becomes end-to-end throughput? How much new capability can a system absorb before its cognitive burden outruns the team that owns it? Tools change those ratios. They do not make them disappear.</p><p>AI makes visible output unusually easy to count: lines changed, pull requests opened, prototypes produced, tickets closed. The less visible liabilities accumulate elsewhere—unstated assumptions, permissions no one modeled, migration paths no one rehearsed, on-call load, hidden coupling, and the mental model a future maintainer will have to reconstruct. Brooks’s enduring contribution is to pull our attention away from the pile of output and back toward the shape of the system.</p><p>A useful rereading therefore starts with three questions. Which costs has AI actually removed, and which has it merely pushed downstream? What happens to coordination when the set of contributors includes agents whose context is assembled afresh for each run? And what kind of knowledge and governance turns faster generation into software that can remain healthy for years?</p><h2 id="What-a-5-billion-bet-taught-us-about-software"><span class="section-no">02</span><a href="#What-a-5-billion-bet-taught-us-about-software" class="headerlink" title="What a $5 billion bet taught us about software"></a>What a $5 billion bet taught us about software</h2><p>Brooks did not arrive at his conclusions from a quiet study. In 1964 IBM introduced System/360, a compatible family of computers intended to replace several incompatible product lines. IBM remembers the program as a $5 billion, bet-the-company gamble; Fred Brooks was one of its project leaders. Its defining commercial promise was portability within the family: customers could grow their hardware without rewriting all their software. <sup class="ref"><a href="#ref-3">[3]</a></sup></p><p>A unified hardware architecture created a platform, but it also concentrated unprecedented complexity in OS/360. Compatibility requirements, machine configurations, delivery schedules, organizational growth, and communication paths became one engineering problem. Under that pressure Brooks saw the flaw in treating software as divisible labor. Some tasks have an irreducible order. Newcomers must learn the system. Interfaces have to be negotiated. Existing team members stop producing while they explain, align, and integrate.</p><p>The modern parallel is not that an AI agent resembles a 1960s programmer. It is that we are living through another change in the production platform. Software organizations once treated the number of people available to write code as a scarce resource. Code supply is now expanding, so scarcity moves elsewhere: precise problem framing, domain judgment, architectural context, credible verification, and accountability for production outcomes. The production function has changed. Any organization that continues to manage the old scarcity will accumulate a large inventory of work that appears finished but has not truly been absorbed.</p><div class="callout"><p><strong>The useful historical analogy:</strong> System/360 unlocked reuse through a common architecture and exposed a new class of operating-system scale problems. AI unlocks code generation through a common language interface and exposes a new class of problems in knowledge consistency, verification capacity, and responsibility.</p></div><h2 id="What-did-fifty-years-of-software-engineering-actually-change"><span class="section-no">03</span><a href="#What-did-fifty-years-of-software-engineering-actually-change" class="headerlink" title="What did fifty years of software engineering actually change?"></a>What did fifty years of software engineering actually change?</h2><p>Read as a list of technologies, the last fifty years look like a sequence of revolutions. Read as an engineering history, they form a surprisingly continuous line. Structured programming constrained arbitrary control flow. Object orientation tried to gather data and behavior into comprehensible units. Agile shortened the distance between a requirement and the feedback that could disprove it. Cloud computing made infrastructure programmable. DevOps brought build, test, release, and operations into one feedback system; platform engineering turned that system into an internal product. AI coding and Agent Engineering extend the same movement by making candidate implementation—and parts of the toolchain itself—delegable.</p><dl class="timeline"><dt>1968</dt><dd>The “software crisis” entered public debate, and software engineering began to take shape as a discipline.</dd><dt>1975</dt><dd><em>The Mythical Man-Month</em> distilled the scheduling, organizational, and design lessons of large software programs. <sup class="ref"><a href="#ref-1">[1]</a></sup></dd><dt>1987</dt><dd>Brooks published “No Silver Bullet,” separating essential complexity from accidental difficulty. <sup class="ref"><a href="#ref-2">[2]</a></sup></dd><dt>1990s</dt><dd>Object orientation, design patterns, and open-source collaboration widened the boundary of reuse.</dd><dt>2001</dt><dd>The Agile Manifesto emphasized working software, human interaction, customer collaboration, and responsiveness to change. <sup class="ref"><a href="#ref-10">[10]</a></sup></dd><dt>2010s</dt><dd>Cloud, continuous delivery, SRE, and DevOps pulled feedback and operations into everyday development.</dd><dt>2021</dt><dd>Natural-language code completion reached a mass audience; developers began working alongside models.</dd><dt>2024</dt><dd>Tool use and protocols such as MCP made it easier to connect models to repositories, data, and external systems. <sup class="ref"><a href="#ref-28">[28]</a></sup></dd><dt>2025–26</dt><dd>Coding agents moved beyond completion to reading repositories, editing files, running tests, preparing changes for review, and working in parallel agent workbenches. <sup class="ref"><a href="#ref-24">[24]</a></sup> <sup class="ref"><a href="#ref-25">[25]</a></sup></dd></dl><p>AI is not an alien break in this history; it is the next rise in the level of abstraction. Every such rise removes some manual work and creates a new control surface. High-level languages needed compilers and type systems. Cloud needed infrastructure as code and observability. Continuous delivery needed automated gates. Agents need context, tool permissions, run traces, evaluations, and human approval.</p><figure class="article-figure"><img src="/assets/articles/mythical-man-month-ai-era/figure-01-software-engineering-evolution-en.webp?v=58f227e34c1f3662" width="1360" height="768" loading="lazy" alt="Fifty years of software engineering, from Code and Framework to Platform, Cloud, AI Coding, Agent Engineering, and Knowledge Engineering"><figcaption><p><strong>Figure 1 · Fifty years of software engineering.</strong> From Code to Knowledge Engineering, execution becomes increasingly automated while the engineering control plane rises toward orchestration, constraints, and organizational knowledge.</p></figcaption></figure><p class="part-label">Part II · Eight classic arguments, read for the AI era</p><h2 id="AI-changes-the-speed-of-coding-not-the-existence-of-essential-complexity"><span class="section-no">04</span><a href="#AI-changes-the-speed-of-coding-not-the-existence-of-essential-complexity" class="headerlink" title="AI changes the speed of coding, not the existence of essential complexity"></a>AI changes the speed of coding, not the existence of essential complexity</h2><p>In “No Silver Bullet,” Brooks separates two sources of difficulty. <em>Essential complexity</em> belongs to the problem itself: the relationships the software must faithfully express. <em>Accidental complexity</em> is imposed by our tools, representations, and implementation process. The distinction is often flattened into a slogan—“AI can only remove accidental complexity”—but the reality is more interesting.</p><p>AI plainly reduces a great deal of implementation friction. Boilerplate, data conversion, familiar endpoints, test scaffolding, query construction, first-draft documentation, and translation across languages can all be produced faster. It can also help people explore the essential problem by summarizing interviews, proposing counterexamples, comparing designs, tracing dependencies, and explaining an unfamiliar domain. AI is not merely a faster typist. Used well, it expands the surface area of thought.</p><p>Assistance is not abolition. A bank still has to decide what evidence justifies declining a transaction. A medical system still needs a defensible definition of acceptable risk. A collaboration product still has to reconcile permission inheritance, retention policy, and legal obligations. A model can offer candidate answers. It cannot make the trade-offs vanish, and it cannot grant itself the authority to bear the consequences.</p><p>There is a second-order effect as well. When accidental costs fall, systems tend to grow. If another service, setting, workflow, or abstraction can be added almost for free, “one more” becomes the default answer. The local implementation gets easier while the whole system becomes harder to hold in mind. This is complexity rebound: coding cost saved at one point in the value stream is consumed by more features, dependencies, states, and operational obligations elsewhere.</p><blockquote><p>“There is no single development … which by itself promises even one order-of-magnitude improvement.”</p><p>Frederick P. Brooks Jr., “No Silver Bullet,” 1987 <sup class="ref"><a href="#ref-2">[2]</a></sup></p></blockquote><p>Brooks was not arguing against progress. He was arguing against the promise that one breakthrough would transform the entire economics of building software. AI may deliver order-of-magnitude gains on particular tasks. Once the unit of analysis expands from “produce a function” to “operate the right system safely for a decade,” the claim has to be tested again.</p><h2 id="Brooks’s-Law-more-agents-can-make-a-bad-architecture-fail-faster"><span class="section-no">05</span><a href="#Brooks’s-Law-more-agents-can-make-a-bad-architecture-fail-faster" class="headerlink" title="Brooks’s Law: more agents can make a bad architecture fail faster"></a>Brooks’s Law: more agents can make a bad architecture fail faster</h2><blockquote><p>“Adding manpower to a late software project makes it later.”</p><p><em>The Mythical Man-Month</em>, Chapter 2 <sup class="ref"><a href="#ref-1">[1]</a></sup></p></blockquote><p>The law bites when three conditions hold: the work cannot be divided cleanly, newcomers need context, and the outputs must eventually be integrated. Human teams meet all three conditions. Agent systems do too. Ten agents do not create ten times the throughput if they read different versions of the requirement, edit the same surface, invent incompatible interfaces, and leave a human to settle the semantic conflicts at the end.</p><p>An agent appears to have almost no onboarding cost. Give it a repository, instructions, and tools, and it can begin. But its context is not durable understanding; it is a selection of information assembled, compressed, and reconstructed for a particular run. More parallel tasks mean more context slices, branches, build slots, and candidate changes demanding judgment. Where boundaries are vague, agents scale the vagueness with impressive efficiency.</p><p>A contemporary form of Brooks’s Law might read: <strong>adding agents to a project that has lost its conceptual boundaries usually produces more locally plausible work that cannot be safely combined.</strong> The remedy is not to reject parallelism. It is to improve divisibility first: define ownership, stabilize interfaces, write acceptance conditions, restrict write scopes, make every change independently testable—and only then choose the level of concurrency.</p><div class="table-wrap"><table><caption>The coordination costs of adding people and adding agents</caption><thead><tr><th>Source of cost</th><th>Human team</th><th>Agent team</th><th>Engineering response</th></tr></thead><tbody><tr><td>Acquiring context</td><td>Training, meetings, code reading</td><td>Retrieval, instructions, context compression</td><td>A concise system map and well-formed task packet</td></tr><tr><td>Decision consistency</td><td>Different experience and mental models</td><td>Different prompts, models, and samples</td><td>ADRs, contracts, examples, and invariants</td></tr><tr><td>Write conflicts</td><td>Several people editing the same module</td><td>Parallel branches with semantic conflicts</td><td>Ownership boundaries and small-batch integration</td></tr><tr><td>Quality judgment</td><td>Finite reviewer attention</td><td>Candidate output outruns verification</td><td>Automated gates plus risk-tiered review</td></tr><tr><td>Accountability</td><td>Roles backed by organizational authority</td><td>An agent cannot own a production outcome</td><td>A named human approver and a rollback path</td></tr></tbody></table></div><h2 id="The-Surgical-Team-are-agents-its-digital-counterpart"><span class="section-no">06</span><a href="#The-Surgical-Team-are-agents-its-digital-counterpart" class="headerlink" title="The Surgical Team: are agents its digital counterpart?"></a>The Surgical Team: are agents its digital counterpart?</h2><p>Brooks borrowed Harlan Mills’s idea of a “surgical team”: one chief programmer preserves the intellectual unity of the design and implementation, while specialists support that person much as anesthetists, nurses, and technicians support a surgeon. The point was not to celebrate the lone hero. It was to avoid dividing one central design evenly among many people and hoping that coherence would somehow emerge.</p><p>Coding agents give the idea a new and quite practical form. A technical lead can ask one agent to search the project history, another to write a migration, a third to extend the tests, and others to inspect security risks or update documentation. The lead keeps authority over the problem statement, the choice of design, and the final merge. OpenAI’s 2025 introduction of Codex described an engineering agent that could work on software tasks in parallel, inside isolated cloud environments, run tests, and return changes for review. By 2026, the product surface had shifted further toward supervising several long-running agents at once. <sup class="ref"><a href="#ref-24">[24]</a></sup> <sup class="ref"><a href="#ref-25">[25]</a></sup></p><p>This digital surgical team works only when the surgeon actually understands the system. If the lead merely distributes vague requests and nobody maintains the whole model, the arrangement becomes ten scalpels cutting at once. AI cannot supply an absent design authority. It can only amplify the authority, rules, and blind spots already present.</p><p>Nor should a modern version reproduce every weakness of a single-expert hierarchy. Conceptual authority may be concentrated, but evidence and dissent should be distributed. A security agent should be able to challenge the favored design; a test agent should look for counterexamples; a domain expert should be able to reject a false premise; important decisions should still face team review. The strongest structure is not “one person is always right,” but “one design thread remains legible while disagreement is deliberately organized.”</p><figure class="article-figure"><img src="/assets/articles/mythical-man-month-ai-era/figure-02-digital-surgical-team.webp?v=d56a31a4cdf1e66a" width="1672" height="941" loading="lazy" alt="A Digital Surgical Team with a human Tech Lead at the center, connected to Research, Implementation, Test, Security, and Documentation agents, with all output passing through a common validation and merge gate"><figcaption><p><strong>Figure 2 · The Digital Surgical Team.</strong> A human Tech Lead preserves conceptual integrity and carries final responsibility. Five specialist agents contribute research, implementation, testing, security, and documentation; every output passes through a shared Validation &amp; Merge Gate before it becomes an accepted change.</p></figcaption></figure><h2 id="Conceptual-integrity-is-becoming-a-scarce-advantage"><span class="section-no">07</span><a href="#Conceptual-integrity-is-becoming-a-scarce-advantage" class="headerlink" title="Conceptual integrity is becoming a scarce advantage"></a>Conceptual integrity is becoming a scarce advantage</h2><p>Brooks considered conceptual integrity the most important quality in system design. Users do not experience the organization chart behind a product. They experience whether the product follows a predictable set of ideas: whether the same word means the same thing, similar actions behave alike, errors are expressed consistently, and permissions and data lifecycles obey a recognizable logic.</p><p>Conceptual integrity is not the same as stylistic consistency. A formatter can standardize indentation, but it cannot decide whether “customer” and “account” belong to the same domain boundary. A framework can standardize controller code, but it cannot decide whether inventory should be reserved at order time, payment time, or shipment. The integrity that matters lives in meaning and trade-offs.</p><p>AI magnifies the difference. In a repository with precise names, stable boundaries, and tests that express business invariants, an agent can infer a sound pattern from many consistent examples. In a ten-year-old codebase containing five competing architectures, it has no reliable way to know which one represents the future. A model tends to choose the most locally plausible answer, and a historical accident quietly becomes the next convention.</p><p>This is why domain-driven design, architecture decision records, the C4 model, and evolutionary architecture have fresh importance in the AI era. <sup class="ref"><a href="#ref-12">[12]</a></sup> <sup class="ref"><a href="#ref-16">[16]</a></sup> <sup class="ref"><a href="#ref-17">[17]</a></sup> <sup class="ref"><a href="#ref-18">[18]</a></sup> Each, in a different way, makes the reason behind a design searchable, reviewable, and traceable. Their purpose is not to feed a model more prose. It is to give people and models a small, stable set of concepts they can share.</p><div class="callout"><p><strong>Conceptual integrity is a form of semantic compression.</strong> When a handful of principles explain a great many local decisions, a system is easier to learn and predict. When every file requires its own explanation, the system has lost that compressibility. AI is exceptionally good at amplifying the first kind of system—and at producing plausible deviations in the second.</p></div><h2 id="The-documentary-hypothesis-the-central-repository-will-be-a-knowledge-repository"><span class="section-no">08</span><a href="#The-documentary-hypothesis-the-central-repository-will-be-a-knowledge-repository" class="headerlink" title="The documentary hypothesis: the central repository will be a knowledge repository"></a>The documentary hypothesis: the central repository will be a knowledge repository</h2><p>In his “documentary hypothesis,” Brooks argued that a project needs a small set of pivotal documents to express its objectives, constraints, organization, budget, schedule, and interfaces. The lesson was never that more documentation is always better. It was that a few authoritative objects are needed to preserve a shared reality. In the AI era, that principle is more dependable than “the code is the documentation.”</p><p>When most code was written by people, an experienced developer could sometimes recover intent from names, commit history, and implementation detail. When agents generate substantial amounts of code quickly, the code looks more like the sediment left by decisions; it may contain very little of their rationale. An implementation passing today’s tests does not tell its next owner which behaviors are contractual promises, which are temporary choices, or which changes require a data migration or a customer notice.</p><p>A useful knowledge repository needs at least six kinds of material: business vocabulary and important scenarios; a system map and ownership boundaries; architectural principles and ADRs; interface and data contracts; build, test, and release instructions; and the lessons of incidents, rollbacks, and security boundaries. Prompts, skills, project rules, retrieval indexes, and agent memory can form an access layer. They are not substitutes for the underlying facts.</p><p>Documentation also needs a lifecycle. Material without an owner or a version—material that cannot be tested and expires separately from the code—gives an agent confidently wrong context. The healthier pattern is straightforward: one authoritative source for each fact; decisions linked to changes; contracts checked by machines wherever possible; examples drawn from real tests; and a way to detect and remove stale material.</p><div class="table-wrap"><table><caption>From code repository to knowledge repository</caption><thead><tr><th>Knowledge layer</th><th>Question it answers</th><th>Useful form</th><th>How it is verified</th></tr></thead><tbody><tr><td>Intent</td><td>Why are we doing this, and for whom?</td><td>Business goals, scenarios, measures</td><td>User feedback and outcome measures</td></tr><tr><td>Concepts</td><td>What do the system’s words mean?</td><td>Domain vocabulary, bounded contexts</td><td>Cross-team terminology review</td></tr><tr><td>Decisions</td><td>Why did we choose this design?</td><td>ADRs, risks, alternatives</td><td>Links to changes and periodic review</td></tr><tr><td>Contracts</td><td>Which behavior must not break?</td><td>Schemas, APIs, policies, invariants</td><td>Contract tests and static rules</td></tr><tr><td>Operations</td><td>How do we build, release, and recover?</td><td>Runbooks, automated scripts</td><td>Drills and observability</td></tr><tr><td>Agent layer</td><td>How should an agent act correctly?</td><td>Instructions, skills, permissions, memory</td><td>Evaluations, trace audits, human approval</td></tr></tbody></table></div><h2 id="Why-Babel-failed-shared-language-is-still-infrastructure"><span class="section-no">09</span><a href="#Why-Babel-failed-shared-language-is-still-infrastructure" class="headerlink" title="Why Babel failed: shared language is still infrastructure"></a>Why Babel failed: shared language is still infrastructure</h2><p><em>The Mythical Man-Month</em> uses Babel to discuss a failure of communication. Projects fail not only because the technology is hard, but because their participants cease to share a language and a picture of the system. As a group grows, its potential communication paths rise roughly with the square of its size. Hierarchies, modules, and interfaces exist in part to prevent every participant from having to communicate with every other one.</p><p>Agents do not tire of meetings, but they bring their own version of Babel. One reads the product specification, another reads the code, and a third receives only the task description. Each may carry a different definition of “done.” A larger context window does not settle conflicts between sources, determine which one is current, or establish which one has authority. Memory can make matters worse by carrying an obsolete judgment cleanly and consistently into a new task.</p><p>Open protocols such as the Model Context Protocol (MCP) and Agent2Agent (A2A) aim, respectively, to standardize how models connect to tools and data and how agents interoperate. <sup class="ref"><a href="#ref-28">[28]</a></sup> <sup class="ref"><a href="#ref-29">[29]</a></sup> This work matters, but a protocol answers whether information can be exchanged, not whether its meaning is agreed. HTTP allowed services to communicate; it did not eliminate contract failures in distributed systems. Agents being able to call one another does not give them a shared understanding.</p><p>Context engineering is therefore an information-architecture problem before it is a prompt-size problem. A system needs priorities among sources, timestamps, scope, versions, and a way to resolve conflict. A handoff should contain the decision summary, open questions, evidence, and validation status—not merely the full chat transcript. Shared language has to be designed.</p><h2 id="The-second-system-effect-when-features-become-nearly-free"><span class="section-no">10</span><a href="#The-second-system-effect-when-features-become-nearly-free" class="headerlink" title="The second-system effect when features become nearly free"></a>The second-system effect when features become nearly free</h2><p>Brooks observed that designers of a second system are tempted to include every idea they restrained themselves from putting into the first. The result is often bloated and over-engineered. AI makes that temptation stronger. Features once rejected because they were expensive can now appear as prototypes in hours. An abstraction that once demanded careful debate can be produced by asking a model to “make it more general.”</p><p>The cost of generating a feature and the cost of owning it are not the same number. Every new capability widens the test matrix, permission surface, documentation, monitoring, compatibility promise, and set of choices presented to users. Agents are good at completing a visible happy path. Most long-term cost lies in the failure paths: how old data migrates, how partial success is compensated, what happens when a dependency times out, and how an audit explains an automated decision.</p><p>The danger in vibe coding is not the use of natural language. It is the confusion of “it runs” with “we can responsibly own it.” Prototypes should move fast. Once a system carries real money, data, or organizational process, it owes a productionization tax: threat modeling, observability, capacity planning, recovery, data governance, and service objectives. AI can help pay that tax. It cannot declare the bill nonexistent.</p><p>Resisting the second-system effect means valuing deletion as highly as addition. Give the product a feature budget. Ask what concept each new concept replaces. Put limits on dependencies and configuration. Judge value by product outcomes, not generation speed. Mature AI engineering is not the ability to make anything; it is the judgment not to generate what should not exist.</p><figure class="article-figure"><img src="/assets/articles/mythical-man-month-ai-era/figure-03-complexity-rebound-curve-en.webp?v=6840b6f42a6636dc" width="1360" height="768" loading="lazy" alt="A complexity rebound curve in which implementation cost per feature falls with AI while feature count, dependency count, and verification burden rise, causing total cost of ownership to rebound without constraints"><figcaption><p><strong>Figure 3 · The complexity rebound curve.</strong> AI lowers the cost of an individual implementation while stimulating growth in features, dependencies, and verification load. Without sufficient architectural constraints and verification capacity, the local efficiency gain turns into higher total cost of ownership after the inflection point.</p></figcaption></figure><h2 id="Plan-to-throw-one-away-from-grand-rewrites-to-replaceable-experiments"><span class="section-no">11</span><a href="#Plan-to-throw-one-away-from-grand-rewrites-to-replaceable-experiments" class="headerlink" title="Plan to throw one away: from grand rewrites to replaceable experiments"></a>Plan to throw one away: from grand rewrites to replaceable experiments</h2><p>“Plan to throw one away” is often repeated as a romantic case for the rewrite. Its real warning is that a first design, made before the problem is understood, will usually be a learning instrument. AI does make exploratory implementation cheaper. A team can compare data models, API shapes, or migration strategies quickly, using working code rather than slides to expose what it does not yet know.</p><p>Brooks reconsidered the maxim in the anniversary edition. He came to favor incremental growth: a system should develop through continuing feedback, not by completing one disposable whole and then replacing it wholesale. That revision matters even more now. AI lowers the cost of regenerating an implementation; it does not lower the cost of replacing a production system by the same amount. Production contains data, customer habits, external integrations, audit history, and hard-won operating knowledge. None can be recreated with a prompt.</p><p>The modern rule should be: <strong>make experiments disposable and assets migratable.</strong> Isolate uncertainty in a spike, sandbox, or shadow implementation. State the learning goal before the work enters the main branch. Protect external behavior with contract tests, make database migrations reversible, and replace old capability a piece at a time. When a prototype accidentally becomes production, require an explicit ownership and production-readiness review; having run once is not an inheritance mechanism.</p><p>AI also makes it practical to generate several candidates for the same requirement and choose among them with evaluations and benchmarks. Throwing one away then becomes the ordinary cost of search, not a failure. The evaluation criteria must come first, however. Otherwise, the team is simply choosing the most attractive of several answers it cannot explain.</p><h2 id="No-silver-bullet-why-the-myth-keeps-returning"><span class="section-no">12</span><a href="#No-silver-bullet-why-the-myth-keeps-returning" class="headerlink" title="No silver bullet: why the myth keeps returning"></a>No silver bullet: why the myth keeps returning</h2><p>Every generation of software technology spends a little time cast as the silver bullet: fourth-generation languages, objects, components, low-code systems, microservices, cloud-native platforms, and now large language models. All created genuine value. All met a new form of complexity when their field of application widened. The myth returns because a local gain in production is so easily projected onto the delivery of the whole system.</p><p>AI is unusual in that it touches many stages at once—requirements, design exploration, implementation, testing, operations, and knowledge retrieval. Its reach may prove broader than that of any previous single tool. Breadth is still not freedom from constraints. As long as software models a changing world, it must deal with incomplete requirements, conflicting aims, organizational power, and an unknowable future.</p><p>“No silver bullet” must not become an excuse for conservatism. Brooks did not claim that tools were useless. He argued that no single technology promised an order-of-magnitude improvement in software productivity, reliability, and simplicity within a decade. <sup class="ref"><a href="#ref-2">[2]</a></sup> An engineer can hold two ideas at once: use AI aggressively to remove repetitive work, and refuse to treat demo speed as lifecycle evidence.</p><p>Durable improvement usually comes from a combination: smaller system boundaries, clearer domain models, shorter feedback loops, better tools, more automated verification, safer releases, and healthier organizational design. AI can strengthen that combination. It cannot stand in for it.</p><div class="table-wrap"><table><caption>Brooks's arguments and their AI-era counterparts</caption><thead><tr><th>Brooks’s subject</th><th>The AI-era question</th><th>Principle to preserve</th></tr></thead><tbody><tr><td>The Tar Pit</td><td>Generation is easy; production and maintenance remain hard</td><td>Define done across the lifecycle, not at the demo</td></tr><tr><td>The Mythical Man-Month</td><td>More agents add context and integration taxes</td><td>Decompose first, then parallelize</td></tr><tr><td>The Surgical Team</td><td>One lead coordinates specialist agents</td><td>Concentrate conceptual authority; distribute evidence and challenge</td></tr><tr><td>Aristocracy, Democracy, and System Design</td><td>How should a design thread coexist with broad participation?</td><td>Open the decision process; keep the resulting semantics coherent</td></tr><tr><td>Second-System Effect</td><td>Cheap feature generation causes scope to explode</td><td>Use complexity budgets and deliberate deletion</td></tr><tr><td>Passing the Word</td><td>How do rules, skills, and memory travel?</td><td>Name the authoritative source, version, and scope</td></tr><tr><td>Why Did the Tower of Babel Fail?</td><td>Context fragments across agents</td><td>Use a shared language and structured handoffs</td></tr><tr><td>Calling the Shot</td><td>Agent task duration and success are difficult to estimate</td><td>Use historical data, percentiles, and confidence</td></tr><tr><td>Ten Pounds in a Five-Pound Sack</td><td>Context, compute, latency, and cost remain finite</td><td>Select information; do not assume infinite context</td></tr><tr><td>The Documentary Hypothesis</td><td>The knowledge repository becomes a generation control plane</td><td>Prefer a few high-signal, verifiable documents</td></tr><tr><td>Plan to Throw One Away</td><td>Several experimental implementations can be generated quickly</td><td>Discard experiments; preserve migratable data and contracts</td></tr><tr><td>Sharp Tools</td><td>Models, MCP, sandboxes, and CI form a toolchain</td><td>Keep it least-privileged, reproducible, and auditable</td></tr><tr><td>The Whole and the Parts</td><td>Local tests pass while system behavior is wrong</td><td>Layer unit, contract, end-to-end tests, and evaluations</td></tr><tr><td>Hatching a Catastrophe</td><td>Small deviations surface together late in integration</td><td>Use small batches, WIP limits, and leading signals</td></tr><tr><td>The Other Face</td><td>AI-generated interfaces and explanations shape trust</td><td>Treat comprehensibility as a product contract</td></tr><tr><td>No Silver Bullet</td><td>Model capability is mistaken for system capability</td><td>Separate task benchmarks, team throughput, and business outcomes</td></tr></tbody></table></div><p class="part-label">Part III · From AI Coding to Agent Engineering</p><h2 id="From-code-assets-to-knowledge-assets"><span class="section-no">13</span><a href="#From-code-assets-to-knowledge-assets" class="headerlink" title="From code assets to knowledge assets"></a>From code assets to knowledge assets</h2><p>Software organizations have long treated source code as their central asset, and with good reason: code is the final authority executed by the machine. As AI generation becomes ordinary, however, the economics begin to change. More implementations can be reproduced from specifications, contracts, and examples. Some code starts to resemble a compiled artifact or a cache—still important and carefully controlled, but no longer a complete account of the organization’s rarest knowledge.</p><p>That idea should not be stretched into another grand claim. Production code is not a temporary file that can be deleted on a whim. It contains verified edge cases, performance work, compliance evidence, and repairs made after incidents. If the knowledge that produced it is incomplete, the code itself may be the only surviving truth. “Code as cache” is a directional observation: stronger specifications and verification make more implementation detail reproducible. It is not a description of where most systems are today.</p><p>The assets that grow in value are those behind generation and judgment: domain models, constraints, policy, decision records, evaluation suites, failure cases, operational experience, tool capabilities, and permission models. They determine what an agent can produce and what must never enter production. TOGAF’s Architecture Repository, DDD’s domain knowledge, and SRE runbooks begin to look like parts of the same control plane. <sup class="ref"><a href="#ref-12">[12]</a></sup> <sup class="ref"><a href="#ref-14">[14]</a></sup> <sup class="ref"><a href="#ref-20">[20]</a></sup></p><p>Knowledge assets differ from code assets in a fundamental way: storage alone does not make them valuable. Knowledge needs provenance, an owner, an applicability boundary, a refresh cycle, and a process for resolving conflict. A vector database can retrieve a passage; it cannot decide whether that passage still represents an organizational decision. Knowledge Engineering is less about retrieval scores than about governing what counts as fact.</p><figure class="article-figure"><img src="/assets/articles/mythical-man-month-ai-era/figure-04-software-asset-center-migration-en.webp?v=be78cd1278c5ca21" width="1360" height="768" loading="lazy" alt="Software assets plotted against reproducibility and governance value, moving from Source Code through Framework and Platform to Knowledge, Skill, Memory, and Architecture Repository"><figcaption><p><strong>Figure 4 · The center of gravity in software assets.</strong> As implementation becomes more reproducible, value moves from code, frameworks, and platforms toward knowledge, skills, memory, and the Architecture Repository. These assets form an organizational control plane through versioned decisions, constraints, and policies.</p></figcaption></figure><h2 id="Agent-Engineering-beyond-the-prompt-toward-an-operating-system"><span class="section-no">14</span><a href="#Agent-Engineering-beyond-the-prompt-toward-an-operating-system" class="headerlink" title="Agent Engineering: beyond the prompt, toward an operating system"></a>Agent Engineering: beyond the prompt, toward an operating system</h2><p>Prompt Engineering asks how a single input can elicit a better output. Context Engineering asks which information a model should receive, and when. Loop Engineering deals with how a model uses tools, observes results, corrects itself, and stops. Agent Engineering places that model inside an operable, observable, governable system. Knowledge Engineering, finally, manages the production and lifecycle of the facts on which the whole system depends.</p><p>These are not competing phases. They contain one another. A good prompt cannot repair bad data. Good context cannot make an unbounded permission safe. A sound loop cannot rescue the wrong goal, and a well-designed agent cannot compensate for the absence of an authoritative source of organizational knowledge. As the engineering matures, attention shifts from “What did the model say?” to “Under what conditions may this system act, and how can its result be proved?”</p><p>OpenAI’s practical guide treats models, tools, and instructions as foundational, distinguishes single-agent from multi-agent orchestration, and emphasizes guardrails. The Agents SDK brings tool use, handoffs, sessions, human intervention, and tracing into the runtime; traces can capture generations, tool calls, handoffs, and guardrail events. <sup class="ref"><a href="#ref-26">[26]</a></sup> <sup class="ref"><a href="#ref-27">[27]</a></sup> Anthropic’s account of effective agents offers a complementary lesson: begin with simple, composable patterns and add autonomy only when the value of the task justifies the added complexity. <sup class="ref"><a href="#ref-30">[30]</a></sup></p><p>The family resemblance to Brooks is strong. A few clear components beat an ornate framework. Organization and interfaces matter more than headcount. The system needs a control thread a person can still follow. Agent Engineering is not the art of connecting more models. It is the design of an execution organization that can delegate safely, detect drift, retain evidence, and stop when it should.</p><div class="table-wrap"><table><caption>Five engineering layers, from prompt to knowledge</caption><thead><tr><th>Layer</th><th>Core question</th><th>Primary artifacts</th><th>Typical failure</th></tr></thead><tbody><tr><td>Prompt</td><td>How is the current task expressed?</td><td>Goal, constraints, output format</td><td>Ambiguous instructions, no acceptance test</td></tr><tr><td>Context</td><td>Which facts are needed?</td><td>Retrieval, project map, state summary</td><td>Stale, conflicting, or noisy information</td></tr><tr><td>Loop</td><td>How does the system observe, act, and stop?</td><td>Tool calls, retries, budgets, stop conditions</td><td>Loops, needless calls, compounding errors</td></tr><tr><td>Agent</td><td>How is work delegated and carried through?</td><td>Roles, permissions, handoffs, guardrails, traces</td><td>Blurred responsibility, excess authority, poor auditability</td></tr><tr><td>Knowledge</td><td>How are facts produced and refreshed?</td><td>Domain models, ADRs, contracts, evaluations, memory</td><td>Decay, unknown provenance, fossilized rules</td></tr></tbody></table></div><h2 id="Multiple-agents-are-an-organizational-design-not-free-parallelism"><span class="section-no">15</span><a href="#Multiple-agents-are-an-organizational-design-not-free-parallelism" class="headerlink" title="Multiple agents are an organizational design, not free parallelism"></a>Multiple agents are an organizational design, not free parallelism</h2><p>Treating agents like cloud instances is one of the most misleading analogies in this field. Computation scales out cleanly when it has no shared state. Software work commonly revolves around shared concepts and shared files. Multiple agents help when the work is genuinely divisible: independent modules, distinct evidence sources, non-overlapping verification roles, or candidate results that can be recombined through explicit contracts.</p><p>As coupling rises, four taxes appear. There is a <em>decomposition tax</em>: someone must cut the problem into units that can actually be completed independently. There is a <em>context tax</em>: each agent needs enough information, without contradictions. There is a <em>coordination tax</em>: dependencies, order, and changes have to be scheduled. And there is a <em>verification tax</em>: the local results must eventually be shown to fit together at the system level.</p><p>Multi-agent designs tend to use one of two basic shapes. In a manager pattern, a central agent retains control and invokes specialist agents as tools. In a handoff pattern, control passes to a new specialist. The first keeps the main thread coherent; the second allows greater specialist autonomy in a long workflow. Neither is universally better. The choice depends on who must retain the final context, whether mistakes are reversible, and whether a transfer of control should involve the user. <sup class="ref"><a href="#ref-26">[26]</a></sup> <sup class="ref"><a href="#ref-27">[27]</a></sup></p><p>The most useful rule still comes from queueing theory and continuous delivery: limit work in progress, keep batches small, and integrate early. Starting twenty tasks at once and settling the conflicts at the end is rarely as effective as maintaining a few high-value parallel streams, each continually passing build, test, and contract gates. The faster the agents work, the more important WIP limits become; otherwise, verification is simply the new late project.</p><figure class="article-figure"><img src="/assets/articles/mythical-man-month-ai-era/figure-05-multi-agent-throughput-model-en.webp?v=2af89814048e70c5" width="1360" height="768" loading="lazy" alt="A multi-agent throughput model in which theoretical parallel gain is reduced by decomposition, context, coordination, and verification taxes until marginal gain becomes negative as task coupling rises"><figcaption><p><strong>Figure 5 · The multi-agent throughput model.</strong> Net throughput is theoretical parallel gain minus the costs of decomposition, context, coordination, and verification. Those taxes grow with coupling; beyond a certain point, adding another agent produces negative marginal value.</p></figcaption></figure><h2 id="Architecture-must-become-executable-governance"><span class="section-no">16</span><a href="#Architecture-must-become-executable-governance" class="headerlink" title="Architecture must become executable governance"></a>Architecture must become executable governance</h2><p>Architecture documents have traditionally been written for people to read. With agents in the development path, architectural principles also have to operate at execution time. “Keep modules loosely coupled” is too vague on its own. A useful rule says which modules may depend on which, which service alone may write a particular class of data, which APIs require idempotency keys, which directories an agent must not edit, and which changes need approval from a security owner.</p><p>Architecture now needs two representations. One expresses intent for people: principles, models, trade-offs, and the reasons for exceptions. The other expresses constraints for machines: types, schemas, static-analysis rules, policy as code, tests, CI gates, permission manifests, and deployment checks. Intent without enforcement becomes a wish. Enforcement without intent becomes a prohibition nobody can explain.</p><p>An Architecture Guardian should not merely be another agent that leaves comments. It should be a layered control system. Low-risk rules run automatically. Medium-risk deviations require an explanation. High-risk actions require human approval. Every exception carries an owner and an expiry date. Tools follow least privilege; reading and writing are separated; an agent stops before an irreversible production action by default; important runs remain auditable; sensitive context has an explicit boundary.</p><p>Testing also expands into evaluation. Deterministic code can be checked with input-output assertions. A system containing models must also be evaluated for task success, tool choice, factuality, safety, cost, latency, and regression. Its evaluation suite should grow from real failures and critical business scenarios. Otherwise a model upgrade can improve the headline score while quietly changing the behavior at the edge of the business.</p><div class="principles"><div class="principle"><strong>01 · Constraints have scope</strong> — Every rule names its source and the directory or system boundary where it applies. A global slogan does not govern every task.</div><div class="principle"><strong>02 · Evidence is reproducible</strong> — An agent delivers more than a patch: it includes verification commands, a summary of results, and the risks it did not verify.</div><div class="principle"><strong>03 · Authority is narrow</strong> — By default, an agent receives only the tools, network, files, and environment access required for its task.</div><div class="principle"><strong>04 · Exceptions expire</strong> — Every bypass has an owner, a reason, a review date, and an automatic reminder.</div><div class="principle"><strong>05 · Changes can be reversed</strong> — Rollback, compensation, and data recovery are completion criteria—not patches invented after an incident.</div><div class="principle"><strong>06 · Runs can be audited</strong> — Record critical context, tool calls, approvals, and results without retaining sensitive material without limit.</div></div><h2 id="Rethinking-productivity-more-code-is-not-faster-value"><span class="section-no">17</span><a href="#Rethinking-productivity-more-code-is-not-faster-value" class="headerlink" title="Rethinking productivity: more code is not faster value"></a>Rethinking productivity: more code is not faster value</h2><p>The worst managerial response to AI is to prove the return on investment with lines of code, commit counts, or tasks completed by agents. The SPACE framework already warns that developer productivity spans satisfaction and well-being, performance, activity, communication and collaboration, and efficiency and flow. No single measure can stand in for all five. <sup class="ref"><a href="#ref-21">[21]</a></sup> As generation gets cheaper, the distance between visible activity and delivered value only widens.</p><p>Empirical results also argue for restraint. In 2025, METR ran a randomized controlled trial with 16 developers working on 246 real tasks in mature open-source projects they knew well. Under the study’s particular population and early-2025 tools, the group allowed to use AI took about 19 percent longer on average. The researchers explicitly framed the result as a snapshot of a population, a toolset, and a moment—not a conclusion that AI will always reduce productivity. <sup class="ref"><a href="#ref-32">[32]</a></sup> Its most useful lesson is simpler: feeling faster is not a measurement.</p><p>The 2025 DORA report approaches the other side of the question. It describes successful AI adoption as a systems problem rather than a tool problem, and emphasizes value-stream management as the means by which local gains become product performance. <sup class="ref"><a href="#ref-31">[31]</a></sup> That is a Brooks-shaped argument. Individual speed is not project throughput; project throughput is not a business outcome. Architecture, platforms, process, and culture mediate the effect of the tool.</p><p>A credible scorecard watches four levels at once. At the task level: completion time, rework, and evaluation pass rate. At the engineering-system level: change lead time, deployment frequency, failure rate, and recovery time. At the team level: cognitive load, review queues, and the spread of knowledge. At the business level: user outcomes, risk, and total cost. The analysis should also separate greenfield work from legacy systems, familiar repositories from unfamiliar ones, and short tasks from long ones. An average is not a universal law.</p><div class="callout"><p><strong>A better headline measure:</strong> how long does it take a proposed business change to become verified, reversible, maintainable reality? “How much did the agent generate?” rewards inventory. The first question follows the flow of value.</p></div><h2 id="The-human-role-moves-toward-intent-boundaries-and-responsibility"><span class="section-no">18</span><a href="#The-human-role-moves-toward-intent-boundaries-and-responsibility" class="headerlink" title="The human role moves toward intent, boundaries, and responsibility"></a>The human role moves toward intent, boundaries, and responsibility</h2><p>“AI amplifies architects, not programmers” is memorable and incomplete. Good programmers have never been mere typists. At the level of code, they discover contradictions in requirements, performance limits, and failure modes. The change is not that programmers disappear while architects prevail. It is that every software role has to move toward judgments with greater leverage.</p><p>The engineer’s growing responsibilities include turning vague problems into testable hypotheses; finding domain boundaries and invariants; designing tasks that can be delegated safely; creating evaluations that expose mistakes; understanding the consequences for security, data, and operations; and maintaining a habit of disproof when a model offers a fluent answer. Reading and reviewing may matter more than personally entering every line.</p><p>Architects cannot retreat into the writing of rules either. Architecture is a set of decisions continually tested by code, measurements, and incidents. It belongs in the value stream. The architect needs to see where agents misread the system, which rules are routinely bypassed, and which boundaries create needless coordination—and then simplify the system in response. Governing AI behavior and governing software boundaries are becoming the same work.</p><p>Responsibility, above all, cannot be outsourced. An agent may propose a migration; the person approving the outage window still needs to understand the risk. An agent may generate an access policy; the person signing the compliance statement still needs to know who can reach the data. “The model recommended it” must not become an organizational passive voice. Every irreversible decision should have an answer to four questions: Who authorized it? On what evidence? How will it be monitored? How can it be undone?</p><figure class="article-figure"><img src="/assets/articles/mythical-man-month-ai-era/figure-06-human-work-center-migration-en.webp?v=4c67bf3f92956301" width="1360" height="768" loading="lazy" alt="Human effort moving from Typing toward Reviewing, Framing, Governing, and Learning as generation becomes more automated, with all five forms of work continuing to exist"><figcaption><p><strong>Figure 6 · The changing center of human work.</strong> As generation becomes more automated, Typing remains but a larger share of human time moves toward Reviewing, Framing, Governing, and Learning. The layers are not eliminated in sequence; judgment, stewardship, and feedback simply carry more weight.</p></figcaption></figure><p class="part-label">Part IV · An engineering path for organizations</p><h2 id="From-individual-acceleration-to-organizational-capability"><span class="section-no">19</span><a href="#From-individual-acceleration-to-organizational-capability" class="headerlink" title="From individual acceleration to organizational capability"></a>From individual acceleration to organizational capability</h2><p>The most common mistake in adopting coding agents is to buy seats first and wait for productivity to appear. Individuals can gain locally without much governance. Scaling the gain across an organization requires absorptive capacity. The sequence below is not a maturity certification. It is a practical order of operations intended to keep learning ahead of risk.</p><h3 id="Phase-one-choose-bounded-verifiable-work"><a href="#Phase-one-choose-bounded-verifiable-work" class="headerlink" title="Phase one: choose bounded, verifiable work"></a>Phase one: choose bounded, verifiable work</h3><p>Begin with tasks such as adding tests, synchronizing documentation, upgrading dependencies, fixing static-analysis findings, and building internal scaffolding. Each task class needs clear acceptance conditions, a dependable build, and a rollback path. Record baseline time and rework, not merely satisfaction. High-risk production actions, critical permissions, and irreversible data migrations should not yet be autonomous.</p><h3 id="Phase-two-repair-the-knowledge-entrance-and-feedback-loop"><a href="#Phase-two-repair-the-knowledge-entrance-and-feedback-loop" class="headerlink" title="Phase two: repair the knowledge entrance and feedback loop"></a>Phase two: repair the knowledge entrance and feedback loop</h3><p>Give each repository a one-page system map: how to build, test, and run it; its major modules and owners; and its critical constraints and prohibitions. Remove stale documentation, add high-value tests, and shorten CI. Agents do not offer a shortcut around engineering health. Brittle tests and slow feedback directly limit how many useful loops an agent can complete.</p><h3 id="Phase-three-make-architectural-rules-machine-checkable"><a href="#Phase-three-make-architectural-rules-machine-checkable" class="headerlink" title="Phase three: make architectural rules machine-checkable"></a>Phase three: make architectural rules machine-checkable</h3><p>Choose three to five of the most expensive kinds of drift—cross-layer dependencies, unauthorized data access, incompatible APIs, missing migrations, or leakage of sensitive information, for example—and turn them into static rules, contract tests, or policy gates. Keep the rule set small enough to trust, and give exceptions a formal route.</p><h3 id="Phase-four-delegate-by-risk-tier"><a href="#Phase-four-delegate-by-risk-tier" class="headerlink" title="Phase four: delegate by risk tier"></a>Phase four: delegate by risk tier</h3><p>Classify work by reversibility, data sensitivity, blast radius, and user impact. Low-risk changes may be generated and verified automatically. Medium-risk work gets a named reviewer. For high-risk work, the agent researches and proposes but does not act. Every tier preserves provenance and traces. Permissions are granted for the task, not left open indefinitely.</p><h3 id="Phase-five-add-multiple-agents-and-long-running-work-later"><a href="#Phase-five-add-multiple-agents-and-long-running-work-later" class="headerlink" title="Phase five: add multiple agents and long-running work later"></a>Phase five: add multiple agents and long-running work later</h3><p>Introduce specialist agents through a manager or handoff only after the failure modes of the single-agent workflow are understood. Give every handoff a structured packet: objective, current state, evidence, change scope, unresolved risks, and next step. Limit work in progress, and give long-running tasks budgets, checkpoints, and stop conditions.</p><h3 id="Phase-six-turn-incidents-and-evaluations-into-knowledge"><a href="#Phase-six-turn-incidents-and-evaluations-into-knowledge" class="headerlink" title="Phase six: turn incidents and evaluations into knowledge"></a>Phase six: turn incidents and evaluations into knowledge</h3><p>Convert misgenerations, missed defects, bad tool calls, and human takeovers into evaluation cases or clearer constraints. Regularly delete ineffective rules and obsolete memory. A mature organization is not one that never makes a mistake. It is one in which every mistake sharpens the control plane instead of merely lengthening the prompt.</p><div class="table-wrap"><table><caption>An operating checklist for Agent Engineering</caption><thead><tr><th>Area</th><th>Question before release</th><th>Minimum evidence</th></tr></thead><tbody><tr><td>Objective</td><td>What counts as complete—and what does not?</td><td>Executable acceptance conditions</td></tr><tr><td>Context</td><td>Where do facts come from, and which source wins a conflict?</td><td>Source, version, timestamp</td></tr><tr><td>Tools</td><td>What may the agent read or write? Can it cause an external effect?</td><td>Permission manifest and sandbox policy</td></tr><tr><td>Verification</td><td>Who proves both local and system behavior?</td><td>Tests, evaluations, scans, and human review</td></tr><tr><td>Runtime</td><td>What happens on timeout, looping, or partial failure?</td><td>Budget, retry, stopping, and compensation policies</td></tr><tr><td>Accountability</td><td>Who approves irreversible actions and takes over on failure?</td><td>Named approver and escalation path</td></tr><tr><td>Learning</td><td>How does failure update knowledge and evaluation?</td><td>Postmortem, test case, and rule-version history</td></tr></tbody></table></div><h2 id="Software-engineering’s-next-job-governing-generative-systems"><span class="section-no">20</span><a href="#Software-engineering’s-next-job-governing-generative-systems" class="headerlink" title="Software engineering’s next job: governing generative systems"></a>Software engineering’s next job: governing generative systems</h2><p>The next era of software engineering will not be one in which nobody writes code. It will be one in which more systems contain deterministic software, probabilistic models, and agents able to take action. Their boundaries will be more dynamic than those of conventional applications: the same objective may produce different paths; tools and data change in real time; persistent memory carries the past into the present. Engineering expands from managing static artifacts to managing generative behavior.</p><p>The first change is that <strong>specifications become first-class assets again</strong>. This is not a return to enormous waterfall documents. It means maintaining evolvable, testable intent: scenarios, contracts, invariants, policies, and evaluations. Specifications and implementations will exchange feedback more rapidly and may even generate parts of one another, but people retain judgment over meaning.</p><p>The second is that <strong>the software supply chain becomes a knowledge supply chain</strong>. Organizations will track not only the origin of dependency packages, but also the models, instructions, tools, knowledge sources, and evaluation versions used by an agent. A defect may enter through an expired retrieval result, contaminated memory, or a changed permission—not through a code commit.</p><p>The third is that <strong>architecture extends from structural design to behavioral governance</strong>. Yesterday’s diagrams mainly explained how components connect. Tomorrow’s must also say who may act for whom, which decisions require approval, how a system presents evidence, and when autonomy must stop. Security, compliance, SRE, product, and architecture will meet earlier in the work.</p><p>The fourth is that <strong>source code is no longer the only human-machine boundary</strong>. Natural language, schemas, policies, skills, evaluation sets, and operational traces all define system behavior. Teams will need to version, test, review, release, and roll back these objects as they do code. Prompt review, skill review, and memory review are not replacements for code review; they are new surfaces of review.</p><p>The fifth is that <strong>advantage comes from the feedback system, not from one model</strong>. Foundation models will change and tools will converge. What remains difficult to copy is the organization’s way of encoding domain knowledge as boundaries, turning real failures into evaluations, turning operational evidence into improvements, and letting agents accelerate within those constraints. The stronger the loop, the more AI behaves like leverage. The weaker the loop, the more it behaves like an amplifier of complexity.</p><figure class="article-figure"><img src="/assets/articles/mythical-man-month-ai-era/figure-07-software-engineering-control-chain-en.webp?v=4808ec36e9c3bce8" width="1360" height="768" loading="lazy" alt="A software engineering control chain from Problem to Intent, Architecture, Knowledge, Agent, Code, Deployment, Evidence, and Learning, with Evidence feeding back into Intent, Knowledge, and Evaluation"><figcaption><p><strong>Figure 7 · The software engineering control chain.</strong> The path from Problem to Learning crosses a control plane, an execution plane, and an evidence-and-learning plane. Production Evidence continually recalibrates Intent, updates Knowledge, and expands Evaluation, making engineering a closed learning system rather than a one-way code-generation pipeline.</p></figcaption></figure><h3 id="Conclusion-Brooks-was-not-wrong-the-object-of-management-has-changed"><a href="#Conclusion-Brooks-was-not-wrong-the-object-of-management-has-changed" class="headerlink" title="Conclusion: Brooks was not wrong; the object of management has changed"></a>Conclusion: Brooks was not wrong; the object of management has changed</h3><p>In 1975, the visible problem was how to organize programmers to deliver software systems of unprecedented size. In 2026, the problem has widened: how to organize people, models, tools, knowledge, and automation as they evolve a system together. We used to review commits; now we must also review an agent’s context and trail of action. We used to manage communication among developers; now we must manage handoffs among agents. Architectural constraints once lived mainly in human memory; now they must be understandable to people and executable by machines.</p><p>Some things have not changed. Software is still a model of a real problem, and every model contains choices. Complex systems still need conceptual integrity. Communication still consumes time. More participants still create coordination. Rapid production still does not replace sound judgment. Responsibility still belongs to people and institutions.</p><p>What has changed is the location of scarcity. Code is no longer the rarest input; knowledge and verification become the bottlenecks. Prototypes and candidate solutions are cheap, while selection and long-term ownership matter more. Agents amplify an architect’s reach—and propagate an architectural mistake at the same speed.</p><p>The deepest lesson of <em>The Mythical Man-Month</em> for the AI era is therefore not to distrust new tools, but to put them back inside the system. AI can help a good team verify, learn, and ship faster. It can also help an organization with unclear boundaries accumulate unexplained code at unprecedented speed. The difference has never been generation alone. It is the presence of clear intent, coherent concepts, dependable feedback, and people willing to own the consequences.</p><p>When code becomes cheap, judgment becomes expensive. When agents become ordinary, the heart of software engineering will be the reality they are required to obey.</p><section class="references" id="references"><h2 data-no-number="true">References and further reading</h2><p class="note">Product and research material is current to the source-update date shown above. Links point to authors, publishers, research teams, or official project pages wherever possible.</p><ol><li id="ref-1">Brooks, Frederick P. Jr. <em>The Mythical Man-Month: Essays on Software Engineering</em>. Addison-Wesley, 1975; Anniversary Edition, 1995.</li><li id="ref-2">Brooks, Frederick P. Jr. “<a href="https://doi.org/10.1109/MC.1987.1663532">No Silver Bullet—Essence and Accidents of Software Engineering</a>.” <em>Computer</em>, 20(4), 1987.</li><li id="ref-3">IBM. “<a href="https://www.ibm.com/history/system-360">The IBM System/360</a>.” IBM History.</li><li id="ref-4">Parnas, David L. “<a href="https://doi.org/10.1145/361598.361623">On the Criteria To Be Used in Decomposing Systems into Modules</a>.” <em>Communications of the ACM</em>, 1972.</li><li id="ref-5">Conway, Melvin E. “<a href="https://www.melconway.com/Home/Committees_Paper.html">How Do Committees Invent?</a>” <em>Datamation</em>, 1968.</li><li id="ref-6">Dijkstra, Edsger W. “<a href="https://www.cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340.html">The Humble Programmer</a>.” ACM Turing Lecture, 1972.</li><li id="ref-7">Royce, Winston W. “Managing the Development of Large Software Systems.” Proceedings of IEEE WESCON, 1970.</li><li id="ref-8">Boehm, Barry W. “<a href="https://doi.org/10.1109/2.59">A Spiral Model of Software Development and Enhancement</a>.” <em>Computer</em>, 1988.</li><li id="ref-9">Gamma, Erich, et al. <em>Design Patterns: Elements of Reusable Object-Oriented Software</em>. Addison-Wesley, 1994.</li><li id="ref-10">Beck, Kent, et al. “<a href="https://agilemanifesto.org/">Manifesto for Agile Software Development</a>.” 2001.</li><li id="ref-11">Fowler, Martin. “<a href="https://martinfowler.com/articles/continuousIntegration.html">Continuous Integration</a>.” 2006.</li><li id="ref-12">Evans, Eric. <em>Domain-Driven Design: Tackling Complexity in the Heart of Software</em>. Addison-Wesley, 2003.</li><li id="ref-13">Humble, Jez, and David Farley. <em>Continuous Delivery</em>. Addison-Wesley, 2010.</li><li id="ref-14">Beyer, Betsy, et al., eds. “<a href="https://sre.google/sre-book/table-of-contents/">Site Reliability Engineering</a>.” O’Reilly / Google, 2016.</li><li id="ref-15">Forsgren, Nicole, Jez Humble, and Gene Kim. <em>Accelerate</em>. IT Revolution, 2018.</li><li id="ref-16">Nygard, Michael. “<a href="https://www.cognitect.com/blog/2011/11/15/documenting-architecture-decisions">Documenting Architecture Decisions</a>.” 2011.</li><li id="ref-17">Brown, Simon. “<a href="https://c4model.com/">The C4 Model for Visualising Software Architecture</a>.”</li><li id="ref-18">Ford, Neal, Rebecca Parsons, and Patrick Kua. <em>Building Evolutionary Architectures</em>. O’Reilly, 2017.</li><li id="ref-19">Skelton, Matthew, and Manuel Pais. <em>Team Topologies</em>. IT Revolution, 2019.</li><li id="ref-20">The Open Group. “<a href="https://pubs.opengroup.org/togaf-standard/adm/chap07.html">TOGAF Standard: Architecture Repository</a>.”</li><li id="ref-21">Forsgren, Nicole, et al. “<a href="https://www.microsoft.com/en-us/research/publication/the-space-of-developer-productivity-theres-more-to-it-than-you-think/">The SPACE of Developer Productivity: There’s More to It Than You Think</a>.” <em>ACM Queue</em>, 2021.</li><li id="ref-22">Jimenez, Carlos E., et al. “<a href="https://arxiv.org/abs/2310.06770">SWE-bench: Can Language Models Resolve Real-World GitHub Issues?</a>” 2023.</li><li id="ref-23">NIST. “<a href="https://www.nist.gov/itl/ai-risk-management-framework">AI Risk Management Framework</a>.” 2023.</li><li id="ref-24">OpenAI. “<a href="https://openai.com/index/introducing-codex/">Introducing Codex</a>.” May 2025.</li><li id="ref-25">OpenAI. “<a href="https://openai.com/index/introducing-the-codex-app/">Introducing the Codex App</a>.” February 2026.</li><li id="ref-26">OpenAI. “<a href="https://openai.com/business/guides-and-resources/a-practical-guide-to-building-ai-agents/">A Practical Guide to Building Agents</a>.”</li><li id="ref-27">OpenAI. “<a href="https://openai.github.io/openai-agents-python/">OpenAI Agents SDK Documentation</a>”; see also <a href="https://openai.github.io/openai-agents-python/tracing/">Tracing</a>.</li><li id="ref-28">Anthropic. “<a href="https://www.anthropic.com/news/model-context-protocol">Introducing the Model Context Protocol</a>.” November 2024.</li><li id="ref-29">Google Developers Blog. “<a href="https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/">Announcing the Agent2Agent Protocol</a>.” April 2025.</li><li id="ref-30">Anthropic. “<a href="https://www.anthropic.com/engineering/building-effective-agents">Building Effective Agents</a>.” December 2024.</li><li id="ref-31">DORA / Google Cloud. “<a href="https://cloud.google.com/resources/content/2025-dora-ai-assisted-software-development-report">2025 State of AI-assisted Software Development Report</a>.” 2025.</li><li id="ref-32">Becker, Joel, et al. “<a href="https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/">Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity</a>.” METR, 2025.</li><li id="ref-33">Anthropic. “<a href="https://www.anthropic.com/engineering/claude-code-best-practices">Claude Code: Best Practices for Agentic Coding</a>.” 2025.</li><li id="ref-34">Fowler, Martin. “<a href="https://martinfowler.com/articles/2025-nature-abstraction.html">The New Nature of Abstraction in Software Development</a>.” 2025.</li><li id="ref-35">Thoughtworks. “<a href="https://www.thoughtworks.com/radar">Technology Radar</a>.” Continuous series.</li><li id="ref-36">Allspaw, John, and Paul Hammond. “<a href="https://www.youtube.com/watch?v=LdOe18KhtT4">10+ Deploys Per Day: Dev and Ops Cooperation at Flickr</a>.” Velocity, 2009.</li></ol></section>]]>
    </content>
    <id>https://ryu.xin/posts/mythical-man-month-ai-era/</id>
    <link href="https://ryu.xin/posts/mythical-man-month-ai-era/"/>
    <published>2026-07-23T16:00:00.000Z</published>
    <summary>A rereading of The Mythical Man-Month for the age of coding agents, context engineering, and knowledge-driven software development.</summary>
    <title>Rereading The Mythical Man-Month: Software Engineering in the Age of AI</title>
    <updated>2026-07-23T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Rocky Yu</name>
    </author>
    <category term="Software Engineering" scheme="https://ryu.xin/categories/software-engineering/"/>
    <category term="AI" scheme="https://ryu.xin/tags/AI/"/>
    <category term="Software Engineering" scheme="https://ryu.xin/tags/Software-Engineering/"/>
    <category term="Reliability" scheme="https://ryu.xin/tags/Reliability/"/>
    <category term="SRE" scheme="https://ryu.xin/tags/SRE/"/>
    <content>
      <![CDATA[<header class="abstract"><h2 data-no-number="true">Abstract</h2><p>AI-assisted development has compressed feature work from hours to minutes, but production systems do not run under ideal conditions. Databases become unavailable, networks time out, clients repeat requests, deployments stop halfway, and operators make mistakes. That is why so many AI-generated systems share the same contradiction: they look complete as software and naive as operations.</p><p>Reliability is not an infrastructure layer to add after launch. It is a set of behaviors that must be defined with the product: how failure is detected, how far it can spread, what the service does while degraded, how data remains recoverable, and how people intervene safely. AI can implement many of these mechanisms—but only after we make failure part of the assignment.</p></header><p class="thesis">Functional requirements say what the system should do when things go right. Reliability requirements say what the system must still protect when they do not.</p><p class="part-label">Part I · Put failure back into the design</p><h2 id="Functionally-complete-operationally-naive"><span class="section-no">01</span><a href="#Functionally-complete-operationally-naive" class="headerlink" title="Functionally complete, operationally naive"></a>Functionally complete, operationally naive</h2><p class="lead dropcap">Over the past two years, AI-assisted development has changed the pace of software construction. APIs, data models, frontend components, and test scaffolds that once took hours can now appear in minutes. The danger is not that this code never works. It is that the code usually proves only one thing: it works along the happy path we arranged for it.</p><p>Production does not remain on that path. A database becomes briefly unavailable. A third-party API slows down during peak traffic. A client repeats an order because the first response never arrived. Half the fleet accepts a release while the other half fails to start. A harmless-looking configuration change bypasses every test written for the application code.</p><p>For an order-creation API, the questions that separate a demo from a production service are therefore different:</p><ul><li>If a client retries after an ambiguous timeout, can it create two orders?</li><li>If inventory is reserved and the payment call times out, what state is the order in?</li><li>If a dependency stays slow, can it exhaust threads, connections, or queues upstream?</li><li>During a partial rollout, can old and new versions safely share the same data?</li><li>How will the on-call engineer locate the failure and restore service without making it worse?</li></ul><p>These are not advanced optimizations. They are the other half of the feature. A system that defines only success has not yet been fully specified.</p><h2 id="Reliability-is-more-than-a-string-of-nines"><span class="section-no">02</span><a href="#Reliability-is-more-than-a-string-of-nines" class="headerlink" title="Reliability is more than a string of nines"></a>Reliability is more than a string of nines</h2><p>Availability is the most familiar expression of reliability, but it is not the whole of it. A 99.9% figure describes an allowed amount of failure over a window. On its own, it does not tell us whether that failure harmed the most important customers, corrupted data, remained invisible for hours, or required the one engineer who understands the system to recover it.</p><p>A more useful view asks four connected questions:</p><div class="table-wrap"><table><caption>Four views of reliability</caption><thead><tr><th>View</th><th>Question</th><th>Typical evidence</th></tr></thead><tbody><tr><td>Availability</td><td>Can users access the service at the promised time and quality?</td><td>SLIs, SLOs, error budgets</td></tr><tr><td>Resilience</td><td>Can the system continue, or degrade deliberately, during a local fault?</td><td>Isolation, load shedding, redundancy, degradation tests</td></tr><tr><td>Recoverability</td><td>Can it return to a known-good state after resilience is exhausted?</td><td>MTTR, RTO, RPO, recovery drills</td></tr><tr><td>Maintainability</td><td>Can the team understand, change, and operate it safely?</td><td>Change failure rate, rollback, runbooks</td></tr></tbody></table></div><p>In a simplified repairable-system model, availability is often expressed as:</p><div class="equation"><p><strong>Availability ≈ MTBF ÷ (MTBF + MTTR)</strong> — MTBF focuses on the interval between failures; MTTR focuses on recovery speed. The value of this approximation is not the tidy number. It is the reminder that preventing failure and accelerating recovery both matter.</p></div><p>Google’s SRE practice also makes a more important point: reliability is not a race to 100%. Different user journeys carry different costs of failure, so investment should follow risk and user experience rather than an abstract contest for more nines. In partially available distributed systems, request success rate can also describe user experience better than whole-site downtime alone. <sup class="ref"><a href="#ref-1">[1]</a></sup></p><h2 id="Failure-is-an-input-not-an-exception"><span class="section-no">03</span><a href="#Failure-is-an-input-not-an-exception" class="headerlink" title="Failure is an input, not an exception"></a>Failure is an input, not an exception</h2><p>Murphy’s Law endures in engineering because it forces us to reason about scale. An event can be unlikely per operation and still become routine when enough components run for long enough.</p><p>Disks fail. Processes crash. Certificates expire. Networks become unstable. Cloud services suffer outages. External APIs change behavior. Human operations cannot be perfect either. Reliability design does not attempt to remove these facts from the world. It decides what the system will do after they arrive.</p><div class="pullquote"><p>A mature system is not one without failure. It is one in which failure still produces a designed outcome.</p></div><p>That changes the question from “How do we prevent every failure?” to: What must keep working? What can pause? How far can an error spread? Which state can be rebuilt? Who owns the recovery decision? The Azure Well-Architected Framework similarly places business requirements, resilience, recovery, operations, and simplicity in one reliability model. It explicitly distinguishes critical paths from degradable components and asks teams to analyze blast radius instead of protecting every component equally. <sup class="ref"><a href="#ref-2">[2]</a></sup></p><p class="part-label">Part II · Spend reliability where it matters</p><h2 id="Find-the-promises-the-business-cannot-lose"><span class="section-no">04</span><a href="#Find-the-promises-the-business-cannot-lose" class="headerlink" title="Find the promises the business cannot lose"></a>Find the promises the business cannot lose</h2><p>Not every component deserves the same protection. Product recommendations can disappear temporarily while customers continue to place orders. An order submitted twice can trigger duplicate charges, inventory errors, and support work. A report may be ten minutes late; a settlement record may create financial and compliance exposure if it vanishes.</p><p>The 80/20 rule of reliability is not about finding exactly 20% of the code. It is about identifying a small set of business promises that cannot be violated:</p><div class="principles"><div class="principle"><strong>Money</strong> — Which failures can duplicate charges, misstate balances, or break reconciliation?</div><div class="principle"><strong>Trust</strong> — Which failures leave customers unable to tell what the system actually did?</div><div class="principle"><strong>Compliance</strong> — Which records must remain complete, auditable, and traceable?</div><div class="principle"><strong>Data</strong> — Which state cannot be reconstructed from another source of truth?</div><div class="principle"><strong>Recovery</strong> — Which services must return within a defined window, and which may wait or degrade?</div></div><p>Only then do redundancy, audit trails, reconciliation, compensating workflows, multi-zone deployment, and enhanced monitoring have a cost model. Google SRE uses different classes of data to make the same point: privacy-critical data and optional experience-enhancing data should not receive identical storage guarantees. <sup class="ref"><a href="#ref-1">[1]</a></sup></p><figure class="article-figure"><img src="/assets/articles/reliability-by-design/figure-01-critical-path.webp?v=ca35af683a507aef" width="1672" height="941" loading="lazy" alt="In a modular software city, a brick-red critical business path crosses reinforced bridges, buffers, and redundant nodes while optional routes can disconnect safely"><figcaption><p><strong>Figure 1 · Protect promises, not components equally.</strong> The brick-red route is the business outcome that must survive. Buffers, isolation, and redundancy are arranged around it; peripheral capabilities are allowed to degrade deliberately.</p></figcaption></figure><h2 id="Simplicity-dependencies-and-fault-boundaries"><span class="section-no">05</span><a href="#Simplicity-dependencies-and-fault-boundaries" class="headerlink" title="Simplicity, dependencies, and fault boundaries"></a>Simplicity, dependencies, and fault boundaries</h2><p>AI-generated architecture can mistake “using more patterns” for “thinking more completely.” Event-driven design, CQRS, distributed workflows, layered caches, and a service mesh may all be justified. Every additional moving part also adds state, contracts, monitoring, and recovery work.</p><p>Simplicity does not mean forcing everything into one process. It means introducing complexity only for constraints that already exist, keeping the critical path short, and making failure modes enumerable and testable. Azure’s reliability guidance names simplicity as a design principle while correctly warning that oversimplification can create single points of failure. <sup class="ref"><a href="#ref-2">[2]</a></sup></p><p>A dependency, meanwhile, must be treated as a fault boundary rather than merely an integration endpoint. For every database, queue, identity provider, payment gateway, or AI API, ask:</p><ul><li>How long will we wait before giving up?</li><li>On failure, do we degrade, queue, serve cached data, or reject the request?</li><li>Which layer retries, how many times, and with what backoff and jitter?</li><li>Does repeating the operation cause side effects, and how long does an idempotency key live?</li><li>When latency rises, what isolates connection pools, threads, queues, and upstream traffic?</li><li>If the dependency remains unavailable, is there an alternative path or a recoverable backlog?</li></ul><div class="callout"><p><strong>Retries are not free reliability.</strong> Unbounded retries, retries without backoff, and retries at multiple layers can turn a brief fault into sustained overload. Amazon’s guidance treats timeouts, bounded retries, exponential backoff, and random jitter as one design problem. Calls with side effects also need explicit idempotency semantics first. <sup class="ref"><a href="#ref-3">[3]</a></sup><sup class="ref"><a href="#ref-4">[4]</a></sup></p></div><p>Stripe’s API provides a concrete example: clients attach an idempotency key to create or update operations, making it safe to retry after an ambiguous connection failure while the server returns the result of the first execution for the same key. <sup class="ref"><a href="#ref-5">[5]</a></sup> The lesson is not to copy a header. It is to turn “we do not know whether it succeeded” from an ad hoc exception into a state the protocol understands.</p><p>Redundancy must be equally specific. Two instances that share a power source, network path, or bad configuration are not independent protection. Useful redundancy states which failure it covers, how the primary failure is detected, how traffic or leadership moves, how data remains consistent, and how the system returns after the incident.</p><h2 id="Reliability-is-also-about-people"><span class="section-no">06</span><a href="#Reliability-is-also-about-people" class="headerlink" title="Reliability is also about people"></a>Reliability is also about people</h2><p>Severe incidents do not come only from code defects. Bad configuration, accidental deletion, oversized permissions, skipped deployment steps, and unsafe recovery commands can all expand a local problem into a business outage. Calling the operator careless usually avoids the better question: Why could an ordinary mistake cause extraordinary damage?</p><p>Good operational interfaces and release systems deliberately reduce the error surface:</p><ul><li>Clear names, typed configuration, and validation reject invalid states early.</li><li>Safe defaults make risky operations require explicit elevation.</li><li>Destructive changes show their real impact instead of a generic confirmation dialog.</li><li>Releases enter production in stages with observable stop conditions.</li><li>Rollback, recovery, and audit are routine paths rather than improvised incident work.</li></ul><p>The goal is not to remove people from the system. It is to reserve human judgment for places that require judgment. Automation should eliminate error-prone repetition while preserving clear authority, evidence, and an undo path.</p><p class="part-label">Part III · Move from architecture into operations</p><h2 id="Reliability-is-a-loop-not-a-diagram"><span class="section-no">07</span><a href="#Reliability-is-a-loop-not-a-diagram" class="headerlink" title="Reliability is a loop, not a diagram"></a>Reliability is a loop, not a diagram</h2><p>An architecture diagram can show redundancy and dependencies. It cannot prove that a team can detect and recover from failure. A mature reliability lifecycle needs at least the following loop:</p><dl class="timeline"><dt>Prevent</dt><dd>Identify critical paths, failure modes, and high-risk changes.</dd><dt>Detect</dt><dd>Observe user outcomes instead of waiting for customer reports.</dd><dt>Analyze</dt><dd>Establish impact, current state, and likely triggers.</dd><dt>Contain</dt><dd>Shed load, open a circuit, degrade, or stop a rollout before the fault spreads.</dd><dt>Recover</dt><dd>Roll back, fail over, replay, compensate, or restore to a known state.</dd><dt>Repair</dt><dd>Remove both the trigger and the conditions that amplified it.</dd><dt>Learn</dt><dd>Feed postmortems, drills, and verifiable action items back into the system.</dd></dl><p>Missing any link can leave reliability on paper. Without detection, recovery starts late. Without containment, a local fault expands while people investigate. Without drills, a runbook may be only an untested wish. Without action items, a postmortem preserves a story without changing the next outcome.</p><p>Google’s incident-response practice emphasizes predefined command roles, a working record of diagnosis and mitigation, and regular exercises. Its postmortem guidance asks teams to explain impact, recovery, and causes with evidence, then assign action items to clear owners with measurable end states. <sup class="ref"><a href="#ref-6">[6]</a></sup><sup class="ref"><a href="#ref-7">[7]</a></sup></p><figure class="article-figure"><img src="/assets/articles/reliability-by-design/figure-02-recovery-loop.webp?v=ef432c55d2d3c342" width="1672" height="941" loading="lazy" alt="An engineering team closes a loop around a damaged software module using observability instruments, isolation gates, a bypass, a repair bench, and an updated blueprint"><figcaption><p><strong>Figure 2 · The reliability loop.</strong> Detection is only the beginning. Loss is reduced by the complete path from signal to containment and from recovery to learning. AI can assist at every stage, but the team must define the control objective and the evidence of success.</p></figcaption></figure><h2 id="Observability-and-recovery-are-product-features"><span class="section-no">08</span><a href="#Observability-and-recovery-are-product-features" class="headerlink" title="Observability and recovery are product features"></a>Observability and recovery are product features</h2><p>Teams often fund feature implementation generously and postpone logs, metrics, alerts, recovery scripts, and drills until “after launch.” The predictable result is a system that has already failed while its operators infer customer impact from fragments. Backups may run every day without ever proving that they can restore complete data within the required window.</p><p>Reliability requirements should be testable like API behavior. For every critical user journey, write down:</p><div class="diagnostic"><h3>Reliability acceptance for a critical path</h3><ol><li>What user outcome defines success, failure, and degraded performance?</li><li>Which signals reveal deviation before customers report it?</li><li>Who receives the alert, and what is the first action they take?</li><li>What is the maximum blast radius of one instance, zone, dependency, or bad configuration?</li><li>What does degraded mode still guarantee, and what does it explicitly drop?</li><li>Which data, permissions, tools, and human decisions does recovery require?</li><li>Have RTO and RPO been demonstrated by a real exercise rather than stated in a document?</li><li>Can a release stop and roll back safely, with old and new versions briefly coexisting?</li></ol></div><p>Answering those questions is the difference between owning an operable service and possessing a deployable program.</p><p class="part-label">Part IV · Teach AI to reason about failure</p><h2 id="Turn-a-feature-prompt-into-a-production-contract"><span class="section-no">09</span><a href="#Turn-a-feature-prompt-into-a-production-contract" class="headerlink" title="Turn a feature prompt into a production contract"></a>Turn a feature prompt into a production contract</h2><p>Coding assistants usually seek the shortest path from a requirement to a working implementation. If the input says only “build an order processing service,” then controllers, services, persistence, validation, and unit tests are natural outputs. Timeouts, idempotency, containment, and recovery may be absent not because the model has never encountered them, but because the assignment never made them part of done.</p><p>A failure contract is more effective than a vague instruction to “consider reliability”:</p><figure class="highlight text"><div class="table-wrap"><table><tbody><tr><td class="code"><pre><span class="line">Implement an order processing service. Functional correctness is only part</span><br><span class="line">of acceptance.</span><br><span class="line"></span><br><span class="line">First identify the critical business promises and external dependencies.</span><br><span class="line">For every material failure mode, specify:</span><br><span class="line">1. Trigger and business impact;</span><br><span class="line">2. Detection signal and alert condition;</span><br><span class="line">3. Timeout, load-shedding, isolation, or degradation behavior;</span><br><span class="line">4. Retry owner, limit, backoff, and idempotency semantics;</span><br><span class="line">5. Data consistency, compensation, and human-intervention boundary;</span><br><span class="line">6. Recovery steps, RTO/RPO, and rollback path;</span><br><span class="line">7. The test or drill that proves the mechanism works.</span><br><span class="line"></span><br><span class="line">Deliver the implementation, risk register, observability, fault-injection</span><br><span class="line">tests, deployment and rollback plan, and an executable recovery runbook.</span><br><span class="line">List unresolved decisions explicitly instead of inventing assumptions.</span><br></pre></td></tr></tbody></table></div></figure><p>The value of this prompt is not the number of reliability terms. It forces every mechanism to connect to a failure scenario, a business consequence, and evidence. Otherwise, “add a circuit breaker” becomes decorative architecture and “add monitoring” becomes a pile of signals that nobody can act on.</p><div class="callout"><p><strong>Ask AI for evidence, not only code.</strong> Require results for duplicate requests, downstream timeouts, partial rollouts, dependency overload, and recovery exercises. A guarantee that cannot be demonstrated should be marked unknown, not filled with architecture vocabulary.</p></div><h2 id="AI-cannot-own-the-consequences-of-failure"><span class="section-no">10</span><a href="#AI-cannot-own-the-consequences-of-failure" class="headerlink" title="AI cannot own the consequences of failure"></a>AI cannot own the consequences of failure</h2><p>AI can help enumerate failure modes, generate fault-injection tests, inspect configuration, draft runbooks, and—in tightly constrained systems—even execute parts of recovery. It is particularly good at expanding a team’s capacity to search for counterexamples and repeat verification.</p><p>The model does not know the true cost of a delayed settlement to this company. It cannot independently decide among privacy, money, and customer trust. It sees requirements, code, and available context; engineers face promises, organizational capability, and consequences.</p><p>Our role therefore moves beyond implementing every line by hand. We must build the control plane for reliability: define what cannot be lost, choose a risk budget, bound automation privileges, review fault boundaries, demand verification evidence, and ensure someone can restore the service at 3 a.m.</p><h2 id="Reliable-from-the-beginning"><span class="section-no">11</span><a href="#Reliable-from-the-beginning" class="headerlink" title="Reliable from the beginning"></a>Reliable from the beginning</h2><p>The software industry has spent decades optimizing how code is written. AI has pushed that process to a new speed. The physical and organizational facts of production have not changed: servers fail, networks fail, people make mistakes, and dependencies change at inconvenient moments.</p><p>Building functionality is becoming rapidly automated. Anticipating failure, choosing the boundary of loss, and accepting responsibility for recovery are becoming more valuable as a result.</p><p>“Reliable by design” does not mean infinite redundancy in the first release, or a system that never breaks. It means the success path and the failure path are equally real from the first requirement. From the first deployment, detection, containment, recovery, and learning are treated as part of the product.</p><div class="pullquote"><p>Reliability begins when we stop asking only, “Can the system work?” and ask instead, “When it cannot, which promises must still hold?”</p></div><section class="references" id="references"><h2 data-no-number="true">References and further reading</h2><p class="note">These public engineering sources ground the discussion of reliability, retries, idempotency, and incident response. A production design still requires trade-offs based on business impact, cost, and team capability.</p><ol><li id="ref-1">Alvidrez, Marc. “<a href="https://sre.google/sre-book/embracing-risk/">Embracing Risk</a>.” <em>Site Reliability Engineering</em>, Google, 2016.</li><li id="ref-2">Microsoft. “<a href="https://learn.microsoft.com/en-us/azure/well-architected/reliability/principles">Reliability Design Principles</a>.” <em>Azure Well-Architected Framework</em>.</li><li id="ref-3">Brooker, Marc. “<a href="https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/">Timeouts, Retries, and Backoff with Jitter</a>.” <em>Amazon Builders’ Library</em>.</li><li id="ref-4">Featonby, Malcolm. “<a href="https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/">Making Retries Safe with Idempotent APIs</a>.” <em>Amazon Builders’ Library</em>.</li><li id="ref-5">Stripe. “<a href="https://docs.stripe.com/api/idempotent_requests">Idempotent Requests</a>.” <em>Stripe API Reference</em>.</li><li id="ref-6">Jones, Stephen, et al. “<a href="https://sre.google/workbook/incident-response/">Incident Response</a>.” <em>The Site Reliability Workbook</em>, Google, 2018.</li><li id="ref-7">Rogers, Daniel, et al. “<a href="https://sre.google/workbook/postmortem-culture/">Postmortem Culture: Learning from Failure</a>.” <em>The Site Reliability Workbook</em>, Google, 2018.</li></ol></section>]]>
    </content>
    <id>https://ryu.xin/posts/reliability-by-design/</id>
    <link href="https://ryu.xin/posts/reliability-by-design/"/>
    <published>2026-06-20T16:00:00.000Z</published>
    <summary>AI can generate complete features quickly, but it rarely designs the failure path by default. A practical framework for critical flows, fault boundaries, idempotency, observability, and recovery.</summary>
    <title>Reliability by Design: What AI Still Misses in Production Systems</title>
    <updated>2026-07-31T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Rocky Yu</name>
    </author>
    <category term="Software Engineering" scheme="https://ryu.xin/categories/software-engineering/"/>
    <category term="AI" scheme="https://ryu.xin/tags/AI/"/>
    <category term="Software Engineering" scheme="https://ryu.xin/tags/Software-Engineering/"/>
    <category term="DFX" scheme="https://ryu.xin/tags/DFX/"/>
    <content>
      <![CDATA[<header class="abstract"><h2 data-no-number="true">Abstract</h2><p>Over the past few months, I have been using AI to write more and more product code. My feelings are mixed. AI is fast, practical, and sometimes surprisingly good at implementing a feature. But a feature that works is not automatically a system that is well designed.</p><p>The problem is rarely that AI cannot write code. It is that we usually give it functional requirements and leave the engineering constraints implicit. DFX, or Design for X, brings reliability, maintainability, observability, testability, security, operability, and cost into the definition of done. As code generation becomes cheaper, these constraints become more important, not less.</p></header><p class="thesis">AI coding should not be about producing more code faster. It should be about producing better code under clearer constraints.</p><p class="part-label">Part I · The feature works. What about the system?</p><h2 id="The-feature-is-done-but-the-system-is-getting-harder-to-touch"><span class="section-no">01</span><a href="#The-feature-is-done-but-the-system-is-getting-harder-to-touch" class="headerlink" title="The feature is done, but the system is getting harder to touch"></a>The feature is done, but the system is getting harder to touch</h2><p class="lead dropcap">Over the past few months, I have been using AI to write more and more code. My feeling is a bit mixed. On the surface, AI coding is already very impressive. Ask it to build a page, write an API, add a scheduled job, connect to a database, or fix a small bug, and it can usually do the job well. In many cases, the result is not merely usable. It is fast, practical, and sometimes surprisingly good.</p><p>But after using it on real product code for a while, I started to notice another problem: AI is very good at implementing features, but it does not automatically produce a well-designed system.</p><p>At the beginning, everything looks fine. The feature works. The API returns the right data. The UI is connected. The task runs. The logs show no obvious errors. Then another requirement arrives, followed by another and another. After several rounds, the code slowly turns into something familiar: business logic scattered across layers, unclear module boundaries, duplicated checks, hidden state transitions, inconsistent exception handling, and configuration logic mixed with execution logic.</p><p>In other words, the feature is done, but the system is becoming harder and harder to touch.</p><p>This is not simply an “AI writes bad code” problem. Human engineers can produce exactly the same result. The difference is that AI can produce it much faster. It accelerates good decisions, but it also accelerates missing boundaries, vague requirements, and expedient patches.</p><p>The 2025 DORA report describes AI’s primary organizational role as an amplifier: it magnifies existing strengths and weaknesses rather than replacing the system around the work. <sup class="ref"><a href="#ref-1">[1]</a></sup> That finding is broader than code design, but it matches what I have seen in a codebase. If the engineering discipline is strong, AI helps it travel faster. If the design is already drifting, AI gives the drift more throughput.</p><p>The real issue is that most of the time, we give AI only functional requirements. We explain what the system should do, but not how it should behave when things go wrong, how it should be maintained, how it should be observed, how it should be extended, or how it should protect people from costly mistakes.</p><p>That is why I think DFX becomes even more important in the AI coding era.</p><h2 id="Functional-requirements-are-not-enough"><span class="section-no">02</span><a href="#Functional-requirements-are-not-enough" class="headerlink" title="Functional requirements are not enough"></a>Functional requirements are not enough</h2><p>In software design, we usually talk about two broad kinds of requirements.</p><p>Functional requirements describe what the system should do: user login, order creation, task scheduling, report generation, payment processing, notification delivery, or trade execution. They are easy to see from the outside. A button exists or it does not. An API works or it does not. A workflow completes or it fails.</p><p>But a real system is not judged only by whether one feature can run once under ideal conditions. It also needs to be reliable, maintainable, observable, testable, secure, scalable, and operable. These qualities are often called non-functional requirements, although the name makes them sound secondary. In practice, they can shape the architecture more deeply than the visible feature itself.</p><p>Fred Brooks made a useful distinction in <em>No Silver Bullet</em>. Software work contains accidental difficulty in representing a solution, but its essential difficulty lies in specifying, designing, and testing a complex conceptual structure. <sup class="ref"><a href="#ref-2">[2]</a></sup> The paper predates AI coding by decades, so applying it here is an inference. AI can remove a remarkable amount of representational friction. It does not remove the need to decide what the system means, where its boundaries are, or what must remain true after failure.</p><p>Take a simple task execution system. If we only care about the feature, the implementation is straightforward:</p><ol><li>Read a task from the database.</li><li>Execute it.</li><li>Update its status.</li><li>Return the result.</li></ol><p>AI can write that code very quickly. Reliability makes the design more interesting.</p><p>What happens if the process crashes halfway through? What if two workers pick up the same task? What if an external API times out after the operation has partially succeeded? What if the business action succeeds but the database update fails? Should the task be retried? Is the operation idempotent? Can the user safely click the button again? Which state must be persisted, and which state can be recalculated?</p><p>These are not small implementation details. In production systems, they are often exactly where the real failures happen.</p><div class="callout"><p><strong>A useful test:</strong> functional acceptance proves that the happy path can complete. Engineering acceptance defines what remains true when that path is interrupted, repeated, delayed, changed, or operated incorrectly.</p></div><p class="part-label">Part II · What DFX changes in the design conversation</p><h2 id="What-DFX-means-in-practice"><span class="section-no">03</span><a href="#What-DFX-means-in-practice" class="headerlink" title="What DFX means in practice"></a>What DFX means in practice</h2><p>DFX means <em>Design for X</em>. The X can represent many different quality goals:</p><div class="principles"><div class="principle"><strong>Design for Reliability and Availability</strong>: expect failures, contain them, and recover without losing critical promises.</div><div class="principle"><strong>Design for Maintainability and Extensibility</strong>: keep boundaries and state transitions clear enough for the next change.</div><div class="principle"><strong>Design for Testability</strong>: make important behavior controllable and observable under success and failure.</div><div class="principle"><strong>Design for Observability</strong>: expose signals that explain user impact, system state, and recovery progress.</div><div class="principle"><strong>Design for Security</strong>: constrain authority, validate inputs, and make dangerous actions explicit.</div><div class="principle"><strong>Design for Operations</strong>: support deployment, rollback, diagnosis, intervention, and audit as normal workflows.</div><div class="principle"><strong>Design for Scalability and Cost</strong>: state load assumptions and decide what the system may spend to keep its promises.</div></div><p>The classification below comes from a broader product-design context. It groups DFX into product delivery, product evolution, and product operation, then includes concerns ranging from procurement and deployment to reliability, serviceability, security, compatibility, and reuse. <sup class="ref"><a href="#ref-3">[3]</a></sup> Software teams may use different labels, but the central idea holds: the product must be designed for a life beyond the moment a feature is completed.</p><figure class="article-figure"><img src="/assets/articles/ai-coding-dfx/figure-01-dfx-taxonomy.webp?v=0346f30fa9764978" width="1200" height="675" loading="lazy" alt="A DFX taxonomy grouping quality goals under product delivery, product evolution, and product operation"><figcaption><p><strong>Figure 1 · DFX spans delivery, evolution, and operation.</strong> A feature is only one moment in that lifecycle. The diagram helps move quality concerns into the design conversation before implementation begins.</p></figcaption></figure><p>These topics do not sound as exciting as shipping a new feature, but they decide whether the system can survive after the feature is shipped. A feature can be implemented in one afternoon. A bad architecture can punish a team for the next two years.</p><p>This is especially true when working with AI. Code generation is cheap, so accidental complexity is cheap too. You can keep asking it to “just add this condition,” “just support this new case,” “just fix this one bug,” or “just reuse the existing logic.” Each instruction looks reasonable in isolation while the overall design gets steadily worse.</p><p>Eventually, nobody knows where the real business boundary is. Nobody knows which state is authoritative. Nobody knows whether a retry is safe, whether a deletion is reversible, or whether a failure is expected, ignored, or dangerous.</p><p>That is the moment when code stops being an asset and starts becoming a liability.</p><h2 id="Why-AI-tends-to-create-spaghetti-code"><span class="section-no">04</span><a href="#Why-AI-tends-to-create-spaghetti-code" class="headerlink" title="Why AI tends to create spaghetti code"></a>Why AI tends to create spaghetti code</h2><p>I do not think AI creates spaghetti code because it does not understand programming. In many cases, it understands syntax, frameworks, common patterns, and even architectural concepts quite well. The problem is that its default objective is usually too narrow.</p><p>If you ask AI to “implement this feature,” it will optimize for completing the feature. It chooses the most direct path that makes the current requirement work. For a small script or a disposable prototype, that may be exactly right. In a product expected to evolve, the shortest path to today’s behavior is not always the shortest path to a maintainable system.</p><p>The deterioration is rarely dramatic:</p><dl class="timeline"><dt>The first change</dt><dd>puts business logic in the controller because that is convenient.</dd><dt>The second change</dt><dd>adds several conditions to the same service because introducing a boundary feels slower.</dd><dt>The third change</dt><dd>squeezes a new state into an old field because changing the model seems expensive.</dd><dt>The fourth change</dt><dd>catches and ignores an exception because the request was simply to “make it work.”</dd></dl><p>None of these decisions looks disastrous by itself. Together, they create a system that is difficult to reason about.</p><figure class="article-figure"><img src="/assets/articles/ai-coding-dfx/figure-02-accidental-complexity.webp?v=c8c27e8d472017b8" width="1672" height="941" loading="lazy" alt="A clean mechanism receives one reasonable patch after another until it still runs but is buried under tangled wires and duplicated controls"><figcaption><p><strong>Figure 2 · “Just one more change” is how accidental complexity compounds.</strong> The green light is still on: the feature works. The cost has moved into the next change, the next incident, and the engineer who must explain which wire is authoritative.</p></figcaption></figure><p>Martin Fowler’s “Design Stamina Hypothesis” describes the same curve. Neglecting design may produce features faster at first, but the degrading codebase makes each later change slower; sound design helps a project “go faster for longer.” Fowler is careful to call this a hypothesis rather than a proven law, and the point at which design pays off depends on context. <sup class="ref"><a href="#ref-4">[4]</a></sup> AI does not invalidate that curve. It makes us reach the consequential part of it sooner because more changes can arrive in less time.</p><p>This does not mean asking AI to build a grand architecture before it writes one line of code. AI can over-engineer too: too many layers, too many helper classes, too much configuration, or an elegant abstraction that solves a problem the product does not have. Complexity is not free, whether it comes from patches or patterns.</p><p>The better question is not “Can AI write code?” Of course it can. The better question is: can we give AI the right engineering constraints before it starts writing?</p><p class="part-label">Part III · Design for failure and for people</p><h2 id="Reliability-stop-designing-only-for-the-happy-path"><span class="section-no">05</span><a href="#Reliability-stop-designing-only-for-the-happy-path" class="headerlink" title="Reliability: stop designing only for the happy path"></a>Reliability: stop designing only for the happy path</h2><p>Reliability is one of the most useful DFX perspectives to bring into AI coding. A reliable system is not a system that never fails. That is unrealistic. It is a system that expects failures, limits their blast radius, makes them visible, and gives the team a way to recover.</p><p>The principle is simple: assume failures will happen. Processes crash. Networks become unstable. Disks fill up. Third-party APIs time out. Users click the wrong button. Developers deploy the wrong configuration. A system that works only when everything goes well is not reliable. It is lucky.</p><p>Before asking AI to write the code, I now prefer to ask questions like these:</p><div class="diagnostic"><h3>DFX questions before implementation</h3><ol><li>Where can this workflow fail?</li><li>What state will the system be in after each failure?</li><li>Which operations must be idempotent?</li><li>Which failures should be retried, and which layer owns the retry?</li><li>Which failures should trigger alerts or require human intervention?</li><li>What must be logged and measured so the incident can be understood later?</li><li>What must be persisted so the system can recover after a crash?</li><li>What evidence will prove that recovery is complete?</li></ol></div><p>After AI answers those questions, the implementation usually looks different. State transitions become more explicit. Retry ownership becomes clearer. Important failures are no longer silently hidden. Recovery becomes part of the design instead of an afterthought.</p><p>The task runner’s timeout problem has a close analogue in AWS. Malcolm Featonby describes an EC2 request whose response is lost after the service may already have created the resource. Blindly retrying could create a second instance. AWS addresses this by making intent explicit with a caller-provided request identifier, allowing retries to be recognized and handled idempotently. <sup class="ref"><a href="#ref-5">[5]</a></sup> The important lesson is not “always add an idempotency key.” It is that retry behavior belongs in the API contract, not in a random catch block added after an incident.</p><p>Reliability also does not mean protecting every path equally. Google SRE frames reliability as risk management: align the service’s reliability target with the risk the business is willing to bear, rather than maximizing uptime at any cost. <sup class="ref"><a href="#ref-6">[6]</a></sup> That is a useful correction to DFX checklists. A delayed analytics report, a duplicate payment, and a lost audit record do not deserve identical mechanisms or budgets.</p><p>Another principle is to keep the system simple. A simple design that solves the real problem is often better than a clever design that creates five new ones. At the same time, simplicity should not hide a single point of failure. If a critical workflow depends on one service, one job, one configuration, one external system, or one manual step, that dependency should be explicit. AI will not always point it out unless the design review asks for it.</p><h2 id="Human-mistakes-are-also-part-of-system-design"><span class="section-no">06</span><a href="#Human-mistakes-are-also-part-of-system-design" class="headerlink" title="Human mistakes are also part of system design"></a>Human mistakes are also part of system design</h2><p>Many production incidents are not caused by machines failing on their own. They happen when people use a system in ways the design did not anticipate or protect against.</p><p>Someone deletes the wrong data. Someone publishes to the wrong environment. Someone changes a configuration without understanding its impact. Someone clicks a dangerous button too quickly. Someone starts an operation twice because there is no progress feedback.</p><p>It is easy to blame the user, but good system design should reduce the probability and cost of these mistakes. Don Norman makes this point directly in “Human Error? No, Bad Design”: blaming the final human action often prevents teams from finding the equipment or procedure that made the error likely. <sup class="ref"><a href="#ref-7">[7]</a></sup></p><p>For software, that principle has concrete consequences:</p><ul><li>A dangerous operation should show its real impact, not only a generic “Are you sure?” dialog. It may require a second confirmation, dry-run, approval, or rollback path.</li><li>A complex configuration should be checked for conflicts, missing dependencies, invalid ranges, and risky combinations before it goes live.</li><li>A delete operation should not always mean immediate permanent deletion. Soft delete, a recycle bin, a recovery window, or delayed execution may be safer.</li><li>A long-running operation should expose progress, current status, logs, retry behavior, and cancellation semantics instead of leaving the user guessing.</li></ul><p>These are not decorations around the feature. They are part of reliability and operability. Yet many AI coding prompts ask only how the user completes the desired action. They rarely ask how the user might perform the wrong action, lose context, repeat an operation, or need to reverse it.</p><p class="part-label">Part IV · A better contract with AI</p><h2 id="A-better-way-to-use-AI-for-coding"><span class="section-no">07</span><a href="#A-better-way-to-use-AI-for-coding" class="headerlink" title="A better way to use AI for coding"></a>A better way to use AI for coding</h2><p>For any feature larger than a small isolated task, I no longer think the best first step is asking AI to write code. A better first step is asking it to analyze the requirement through a DFX lens.</p><p>For example:</p><figure class="highlight text"><div class="table-wrap"><table><tbody><tr><td class="code"><pre><span class="line">Before writing code, analyze this requirement from the perspective of DFX.</span><br><span class="line">Cover reliability, maintainability, observability, testability, security,</span><br><span class="line">and operational safety.</span><br><span class="line"></span><br><span class="line">Identify the main failure scenarios, state boundaries, idempotency</span><br><span class="line">requirements, retry behavior, recovery strategy, logging and metrics,</span><br><span class="line">configuration validation, human-error risks, and the parts of the design</span><br><span class="line">most likely to change in the future.</span><br><span class="line"></span><br><span class="line">Then propose the module structure, implementation plan, and verification</span><br><span class="line">evidence. List unresolved business decisions explicitly instead of</span><br><span class="line">inventing assumptions.</span><br></pre></td></tr></tbody></table></div></figure><p>This sounds slower, but in practice it saves time. Once AI understands the quality goals, it stops behaving like a simple code generator and starts acting more like an engineering assistant. The code is usually better structured, and the trade-offs become easier to review.</p><p>The prompt is not magic. You still need to challenge its assumptions, review the design, understand the system, and decide which risks are worth paying for. The useful change is that quality goals are no longer hidden in the reviewer’s head. They become part of the assignment.</p><p>For an implementation plan to be useful, I now expect it to produce evidence in six areas:</p><div class="table-wrap"><table><caption>A practical DFX review for AI-generated changes</caption><thead><tr><th>Lens</th><th>Questions the plan must answer</th><th>Evidence before release</th></tr></thead><tbody><tr><td>Reliability</td><td>Where can it fail, repeat, or partially succeed?</td><td>Failure tests, idempotency semantics, recovery steps</td></tr><tr><td>Maintainability</td><td>Which boundary owns the rule and likely change?</td><td>Module map, state model, explicit contracts</td></tr><tr><td>Observability</td><td>How will we know the user outcome and system state?</td><td>Structured logs, metrics, traces, actionable alerts</td></tr><tr><td>Testability</td><td>Can important states and dependencies be controlled?</td><td>Deterministic tests for success, failure, and retry</td></tr><tr><td>Security and operations</td><td>Who may act, how is impact limited, how is it reversed?</td><td>Permission checks, validation, dry-run, rollback, audit</td></tr><tr><td>Scalability and cost</td><td>What load and budget assumptions does the design make?</td><td>Limits, capacity tests, degradation behavior, cost signals</td></tr></tbody></table></div><p>AI coding should not be about producing more code faster. It should be about producing better code under clearer constraints.</p><h2 id="Architecture-matters-more-when-code-becomes-cheaper"><span class="section-no">08</span><a href="#Architecture-matters-more-when-code-becomes-cheaper" class="headerlink" title="Architecture matters more when code becomes cheaper"></a>Architecture matters more when code becomes cheaper</h2><p>Some people believe AI will make architecture less important because code is becoming easier to generate. I think the opposite is happening.</p><p>When writing code becomes cheaper, deciding what should be written becomes more valuable. When implementation becomes faster, design mistakes become easier to amplify. When almost anyone can generate a working feature, the meaningful difference is whether the system can still be understood, changed, operated, and trusted after many such features have been added.</p><p>AI can write code, but it needs a clear target.</p><p>AI can refactor code, but it needs to know what quality goal the refactoring serves.</p><p>AI can fix bugs, but it needs to understand which behavior is correct.</p><p>AI can generate abstractions, but it does not always know whether an abstraction is worth its cost.</p><p>That is why DFX is not an old architecture topic. It may become one of the most practical ways to use AI coding well.</p><p>The future of AI coding should not stop at this question:</p><blockquote><p>How do I implement this feature?</p></blockquote><p>It should continue with another:</p><blockquote><p>Under what quality constraints should this feature be implemented?</p></blockquote><p>If we skip that question, AI may help us move faster in the short term while creating a system that becomes harder to change, harder to operate, and harder to trust. The code may still run, the green light may still be on, and the engineering debt may already be compounding.</p><section class="references" id="references"><h2 data-no-number="true">References and further reading</h2><ol><li id="ref-1">DORA. “<a href="https://dora.dev/research/2025/dora-report/">State of AI-assisted Software Development 2025</a>.” Google Cloud, 2025.</li><li id="ref-2">Brooks, Frederick P., Jr. “<a href="https://www.cs.unc.edu/techreports/86-020.pdf">No Silver Bullet: Essence and Accidents of Software Engineering</a>.” University of North Carolina at Chapel Hill, 1986.</li><li id="ref-3">“<a href="https://pbs.twimg.com/media/HLEAGnuaEAAgbFU.jpg">Original DFX taxonomy image</a>.” Image supplied with the June 18 article.</li><li id="ref-4">Fowler, Martin. “<a href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html">Design Stamina Hypothesis</a>.” 2007.</li><li id="ref-5">Featonby, Malcolm. “<a href="https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/">Making Retries Safe with Idempotent APIs</a>.” <em>Amazon Builders’ Library</em>.</li><li id="ref-6">Alvidrez, Marc. “<a href="https://sre.google/sre-book/embracing-risk/">Embracing Risk</a>.” <em>Site Reliability Engineering</em>, Google, 2016.</li><li id="ref-7">Norman, Don. “<a href="https://jnd.org/human-error-no-bad-design/">Human Error? No, Bad Design</a>.” 2014.</li></ol></section>]]>
    </content>
    <id>https://ryu.xin/posts/ai-coding-dfx/</id>
    <link href="https://ryu.xin/posts/ai-coding-dfx/"/>
    <published>2026-06-18T16:00:00.000Z</published>
    <summary>AI can implement features remarkably well, but it does not automatically produce a system that is reliable, maintainable, observable, secure, and safe to operate. DFX turns those qualities into explicit design constraints.</summary>
    <title>AI Coding Makes DFX More Important, Not Less</title>
    <updated>2026-08-09T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Rocky Yu</name>
    </author>
    <category term="Software Engineering" scheme="https://ryu.xin/categories/software-engineering/"/>
    <category term="Software Engineering" scheme="https://ryu.xin/tags/Software-Engineering/"/>
    <category term="Lattice" scheme="https://ryu.xin/tags/Lattice/"/>
    <category term="Architecture" scheme="https://ryu.xin/tags/Architecture/"/>
    <category term="Clean Architecture" scheme="https://ryu.xin/tags/Clean-Architecture/"/>
    <content>
      <![CDATA[<header class="abstract"><h2 data-no-number="true">Abstract</h2><p>When I joined Company A in early 2015, its transaction platform was already living with a contradiction. The system had been divided into ever smaller services, and the platform exposed more APIs and extension points than ever, yet delivering a business change had not become easier. Teams were short-handed, schedules were long, and delays were common. Every Thursday, dozens of branches converged on the fixed release window, and a change for one business could force many unrelated businesses through another round of regression testing.</p><p>The deeper problem was not merely an excess of <code>if/else</code>, nor an SPI mechanism that lacked flexibility. The platform could not answer a more important set of questions: Who owns a customization, and whom should it affect? How does one business scenario remain whole across many applications? How should several rules compose when they apply at once? Can business code evolve and ship without requiring a platform release? Lattice emerged as an open-source business extension framework built around those questions. It separates business code from platform code, one business from another, and logical business architecture from physical application topology. Business identity, Ability, Use Case, vertical and horizontal composition, and Reduce then turn “modify the platform everywhere” into “assemble a business within an explicit boundary.” The essay closes by showing how I turned those judgments into an architecture Skill that reviews design, module placement, and generated code during AI-assisted development.</p></header><p class="thesis">The decisive quality of a highly customizable platform is not the number of extension points it exposes. It is whether every change has a clear owner, scope, composition rule, and delivery boundary. Lattice is less about inserting business code than about keeping each business change from spilling across the entire platform.</p><p class="part-label">Part I · When the platform can no longer keep up</p><h2 id="In-2015-the-problem-I-saw-was-not-merely-technical"><span class="section-no">01</span><a href="#In-2015-the-problem-I-saw-was-not-merely-technical" class="headerlink" title="In 2015, the problem I saw was not merely technical"></a>In 2015, the problem I saw was not merely technical</h2><p class="lead dropcap">During my first six months at Company A in 2015, I spent a great deal of time watching the transaction platform absorb new businesses. What stood out was not one poorly designed interface, but a system under persistent strain: too few people, punishing overtime, long lead times, and projects that routinely slipped. Platform and business teams worked through a co-development model, but every additional participant made coordination more expensive. Everyone was working hard, and the system contained no shortage of sophisticated mechanisms. Still, each new business became harder to deliver.</p><p>Distributed architecture was not itself a mistake. Company A’s early commerce business was relatively homogeneous, and a single system could contain product listing, cart, order creation, and fulfillment. As traffic, businesses, and teams grew, splitting that monolith into cohesive user, product, transaction, and shop systems was both necessary and successful. Each system could make local design decisions, own its requirements, and release independently. For a time, development speed and reliability improved.</p><p>Every architectural advantage, however, has a scale at which its costs become visible. As the business expanded across industries and the number of applications and services reached into the thousands, the decomposition that had reduced local complexity began producing a different kind of complexity: one coherent business intent was scattered across many applications and teams.</p><p>A single request might require several teams to analyze, design, build, integrate, and release changes in a particular order. Worse, nobody could confidently enumerate every system it touched. The main path was usually visible; edge cases and side paths accumulated over years tended to surface late. Missing one could mean reopening the design, reworking the implementation, and delaying the release again.</p><p>We had decoupled applications without reassembling business intent.</p><div class="pullquote"><p>A system may be split into a thousand services, but the user still asks for one coherent outcome. The more technical boundaries we create, the more we need a way to restore the unity of business intent.</p></div><h2 id="From-open-APIs-to-business-co-development"><span class="section-no">02</span><a href="#From-open-APIs-to-business-co-development" class="headerlink" title="From open APIs to business co-development"></a>From open APIs to business co-development</h2><p>APIs were the platform’s earliest and most important way of exposing capabilities. Stable service interfaces let business systems reuse product, transaction, marketing, and other functions. APIs described stable behavior well, but they could not anticipate every difference among industries.</p><p>As those differences accumulated, <code>Map</code> parameters appeared. Callers could inject context the platform model had never anticipated, but a platform that did not understand those parameters could hardly understand their business meaning. Java SPI came next: the platform defined an interface, and a business team implemented it so that specialized logic could run inside the platform’s execution path. This co-development model made business teams far more productive.</p><p>Its limits gradually became just as clear. The platform did not provide a strong separation between business and platform code, so both continued to accumulate in the same repositories. A customization could not ship independently; it had to join the shared release train. I remember the fixed release window every Thursday, when forty or fifty branches had to be merged. Each branch made sense in isolation. Together they created an enormous system-wide regression effort: when Business A went live, Business B had to wonder whether its behavior had changed too.</p><p>Isolation and quality depended mainly on developers being careful rather than on a structure that could be verified. Experience and code review may be enough when the organization is small. At scale, “everyone should be more careful” is not an architecture.</p><h2 id="How-an-inventory-decrement-method-decays"><span class="section-no">03</span><a href="#How-an-inventory-decrement-method-decays" class="headerlink" title="How an inventory-decrement method decays"></a>How an inventory-decrement method decays</h2><p>Inventory decrement is a small but representative example. The following code is illustrative and is unrelated to any production source.</p><p>The platform initially reduced stock when an order was placed. Large appliances were expensive and scarce, however, and unpaid orders could lock inventory. That business needed stock to be reduced only after payment:</p><figure class="highlight java"><div class="table-wrap"><table><tbody><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> ReduceType <span class="title function_">getInventoryReducePolicy</span><span class="params">(OrderLine orderLine)</span> {</span><br><span class="line">    <span class="keyword">if</span> (orderLine.getProduct().hasTag(<span class="number">9527</span>)) {</span><br><span class="line">        <span class="keyword">return</span> ReduceType.AFTER_PAYMENT;</span><br><span class="line">    }</span><br><span class="line">    <span class="keyword">return</span> ReduceType.BEFORE_PAYMENT;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></div></figure><p>When digital goods arrived, some required no inventory decrement at all, so another condition appeared before the first. Large appliances later gained in-store pickup: customers received a digital collection code, yet the physical inventory still had to be decremented. “Digital goods do not decrement inventory” now intersected with “large appliances decrement inventory after payment,” and evaluation order began changing outcomes.</p><p>Eventually, large appliances were no longer uniform either. Items above a price threshold reduced stock after payment; cheaper ones still reduced it at order placement. A simple default policy had become a branching tree over product type, industry tag, delivery mode, and price.</p><p>No single bad programmer created this decay. On the contrary, every change answered a real request, and every local condition may have been the cheapest reasonable choice at the time. Years later, a method could span thousands of lines. The next developer would search cautiously for a plausible insertion point, add another branch, and hope they had not changed another business’s behavior.</p><p>This history changed how I understand legacy code. Often it suffers not from a lack of refactoring, but from a missing ownership model for business change. The code does not know which rule belongs to which business, nor whether two rules should be isolated, overridden, or combined. Execution order ends up making an organizational decision.</p><h2 id="SPI-made-the-code-cleaner-not-the-businesses-independent"><span class="section-no">04</span><a href="#SPI-made-the-code-cleaner-not-the-businesses-independent" class="headerlink" title="SPI made the code cleaner, not the businesses independent"></a>SPI made the code cleaner, not the businesses independent</h2><p>The natural response is to extract those branches into SPI implementations. Each implementation supplies a <code>filter</code> and an <code>execute</code> method; the platform iterates over the list and runs the first matching strategy.</p><figure class="highlight java"><div class="table-wrap"><table><tbody><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">InventoryReducePolicySpi</span> {</span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">filter</span><span class="params">(ReducePolicyRequest request)</span>;</span><br><span class="line">    ReduceType <span class="title function_">execute</span><span class="params">(ReducePolicyRequest request)</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></div></figure><p>With a small number of implementations, this works well. A thousand-line method becomes several more cohesive classes, improving local readability and testability. At larger scale, however, the same difficulty reappears in another form:</p><ul><li>Should a new requirement modify an existing implementation or register another one?</li><li>Where in the list can it sit without being intercepted by an earlier rule?</li><li>Does its <code>filter</code> overlap with any of the dozens already present?</li><li>Which businesses silently change when the order is adjusted?</li></ul><p>In harder cases, a <code>filter</code> calls a rule engine or remote service. Reading the code is then insufficient to determine statically when an implementation will apply. I have seen complex platforms accumulate nearly a thousand SPI contracts, with dozens of implementations behind a single interface. Global traversal plus “first match wins” turns every business into a participant in one invisible decision tree.</p><p>The platform appears to have removed <code>if/else</code>; in reality, the conditions moved into registration order and filter logic. The coupling remains and is harder to see.</p><div class="diagnostic"><h3></h3><ul><li><strong>Symptom</strong> — Core methods accumulate branches, and nobody can state the impact of a change with confidence.</li><li><strong>Initial fix</strong> — Extract branches into SPI implementations, selected by list order and <code>filter</code>.</li><li><strong>New failure</strong> — Conditions and ordering form a global decision tree in which businesses still compete.</li><li><strong>Root cause</strong> — The extension model has no business identity, scope, composition semantics, or independent delivery boundary.</li></ul></div><figure class="article-figure"><img src="/assets/articles/lattice-clean-architecture-practice/figure-01-platform-coupling.webp?v=a40fb0605e895ded" width="1672" height="941" loading="lazy" alt="Many applications, business branches, and release paths tangled around a shared platform, allowing local changes to spread through invisible dependencies"><figcaption><p><strong>Figure 1 · An extension mechanism without scope.</strong> Service decomposition reduced the complexity of each application, but did not preserve coherent business intent. Global SPIs, shared repositories, and a common release window coupled those scattered changes together again.</p></figcaption></figure><h2 id="An-application-view-is-not-a-business-view"><span class="section-no">05</span><a href="#An-application-view-is-not-a-business-view" class="headerlink" title="An application view is not a business view"></a>An application view is not a business view</h2><p>A subtler problem was that the platform exposed extension points by application, while business teams reasoned in scenarios.</p><p>At Company A’s scale, business capabilities had already been divided among more than 2,000 microservices. The number mattered not as a measure of prestige, but because the system landscape had grown beyond what any one person could remember, assess, or control as a whole. No individual could reconstruct the complete dependency graph from experience alone. At the start of a request, nobody could confidently say which applications it would traverse, which teams it would involve, which extension points it would change, or which entrances outside the main path might be missed.</p><p>This does not mean that one requirement modified 2,000 services, nor that microservice decomposition was itself a mistake. The problem was that after one business intent had been scattered across so many technical boundaries, impact analysis still depended on people discovering and reconnecting the pieces by hand. Analysis became repeated rounds of assembling teams, tracing paths, and confirming assumptions. Missing one system or side entrance could invalidate the result.</p><p>Suppose one business does not allow products to be bought through a shopping cart. In business language, there is one rule: “This business does not support cart purchases.” In an application view, the team may need a string of scattered customizations: hide the Add to Cart button on the product page; reject API calls that bypass the page; prevent the order service from accepting requests falsely marked as cart orders; and repeat the same check at every side entrance.</p><p>Each application may offer a perfectly reasonable extension point in isolation, but responsibility for completeness has been transferred to the delivery team. Developers must understand not only their industry, but also which small subset of more than 2,000 microservices matters to the scenario, what each service exposes, how the services interact, and whether any critical entrance has been overlooked. Finer decomposition clarifies the responsibility of each system while making end-to-end business analysis harder.</p><p>The real challenge, then, was not to invent a stronger SPI. It was to move the organizing unit of extension upward—from applications and technical processing points back to businesses and scenarios. The platform should let developers see the outcome of a complete business scenario first, then let that scenario organize the capabilities it needs. Every delivery team should not have to rediscover the application map from scratch.</p><p class="part-label">Part II · Define the problem before designing the framework</p><h2 id="Six-questions-the-architecture-had-to-answer"><span class="section-no">06</span><a href="#Six-questions-the-architecture-had-to-answer" class="headerlink" title="Six questions the architecture had to answer"></a>Six questions the architecture had to answer</h2><p>During several design workshops, I asked the team not to begin with class diagrams or framework choices. Instead, we completed one sentence: “If the platform could …, then we could ….” This kept us anchored in actual friction rather than technical preference.</p><p>The answers were concrete. A team should be able to package the contracting and fulfillment model of a particular business, then keep that package independent of both the platform and other businesses. It should be able to select and compose existing capabilities along real business flows. Product managers and developers should be able to see both what the platform offers and what a business has adopted. No business should have to wait for a shared platform release, and the same logical architecture should work across different deployment models.</p><p>Condensed further, those wishes became six questions the framework had to answer explicitly:</p><div class="table-wrap"><table><caption>From platform symptoms to architectural questions</caption><thead><tr><th>Platform symptom</th><th>Question the architecture must answer</th></tr></thead><tbody><tr><td>Business code mixed into platform repositories</td><td>Who owns the change, and where is its code boundary?</td></tr><tr><td>A change for Business A can alter Business B</td><td>How is the scope of a rule determined?</td></tr><tr><td>One requirement is scattered across applications</td><td>How can capabilities be organized and reused as a complete scenario?</td></tr><tr><td>Extension points are buried inside physical applications</td><td>How can the platform expose one business view independent of deployment topology?</td></tr><tr><td>Several SPI implementations match at once</td><td>How do rules compose, and who resolves a conflict?</td></tr><tr><td>Dozens of branches share one release</td><td>Can a business be developed, tested, and delivered independently?</td></tr></tbody></table></div><p>These six questions determined the shape of Lattice. Its annotations, interfaces, and runtime are implementation devices. Forget the questions and Lattice can easily be reduced to yet another SPI toolkit.</p><h2 id="Rereading-Clean-Architecture-the-circles-are-not-the-point"><span class="section-no">07</span><a href="#Rereading-Clean-Architecture-the-circles-are-not-the-point" class="headerlink" title="Rereading Clean Architecture: the circles are not the point"></a>Rereading <em>Clean Architecture</em>: the circles are not the point</h2><p>When I returned to Robert C. Martin’s <em>Clean Architecture</em>, its most useful lesson was not which project directory should contain Entities, Use Cases, Interface Adapters, and Frameworks. It was the direction in which change is allowed to travel.</p><p>The book’s best-known principle is the Dependency Rule: source-code dependencies point inward. The outer layers contain volatile mechanisms; the inner layers hold more stable policies closer to business purpose. Web frameworks, databases, and delivery mechanisms serve business rules, not the other way around. A use case coordinates entities toward an application goal and exchanges data with external systems through boundaries, while dependencies across those boundaries still point inward. <sup class="ref"><a href="#ref-1">[1]</a></sup><sup class="ref"><a href="#ref-2">[2]</a></sup></p><p>For a large business platform, however, making a database depend on a domain interface is not enough. <strong>Business customization is itself an external source of change.</strong> The inventory policy of one industry, the purchasing limit of one promotion, or the redemption requirements of one fulfillment model should not leak back into the core shared by every business.</p><p>That led me to a more concrete reading of the Dependency Rule. Architectural “inside” and “outside” are separated not only by technical layer but also by policy scope. Shared entity rules, scenario rules, vertical-industry rules, and horizontal capability rules differ in stability and reach. They need explicit boundaries through which to collaborate, rather than a single global list in which they all compete.</p><p><em>Clean Architecture</em> also emphasizes independent development and deployment, plugin boundaries, and an architecture that reveals the system’s purpose before the frameworks it uses. <sup class="ref"><a href="#ref-1">[1]</a></sup> Those ideas gave me better language for conclusions that practice had already forced upon us:</p><ul><li>Separating business from platform code controls the direction of change; it is not merely tidier code.</li><li>Separating the logical business view from physical application topology restores coherent business intent; it is not merely a search convenience.</li><li>Organizing extensions around use cases makes the architecture speak business language; it is not merely a directory change.</li><li>Delivering plugins independently turns a logical boundary into a real one; it is not merely release acceleration.</li><li>Letting the runtime execute an already determined composition makes hidden conflicts into explicit policy; it is not merely a performance optimization.</li></ul><div class="callout"><p><strong>What I took from the book:</strong> Clean does not mean fewer lines, more layers, or more interfaces. It means that high-level business policy is not dragged around by low-level mechanisms and local customization. When change arrives, we know the boundary at which it should stop.</p></div><p class="part-label">Part III · How Lattice answers the problems</p><h2 id="Why-the-name-Lattice"><span class="section-no">08</span><a href="#Why-the-name-Lattice" class="headerlink" title="Why the name Lattice"></a>Why the name Lattice</h2><p>A lattice is a grid. When we looked at a business platform, we saw two interwoven dimensions: isolated vertical businesses and horizontal capabilities that could be selected and overlaid. Their intersections looked like a lattice. There was also a less solemn reason: programmers are famously fond of plaid shirts.</p><p>That is why we named the business extension framework Lattice. It was not an attempt to give conventional SPI a new label, but to make business identity and capability composition first-class concepts. The source is available at <a href="https://github.com/hiforce/lattice">hiforce/lattice</a>; at this essay’s most recent update, the main branch version was <code>1.0.21</code>. <sup class="ref"><a href="#ref-3">[3]</a></sup></p><h2 id="Lattice-begins-with-three-separations"><span class="section-no">09</span><a href="#Lattice-begins-with-three-separations" class="headerlink" title="Lattice begins with three separations"></a>Lattice begins with three separations</h2><p>The failures described above look varied, but all three fundamental boundaries had collapsed. Business code had entered the platform core; implementations for different businesses competed in one global decision space; and physical applications had fragmented the view of an end-to-end business process. Lattice does not begin by adding more hooks. It begins by restoring those three separations.</p><div class="table-wrap"><table><caption>The three separations in Lattice</caption><thead><tr><th>Separation</th><th>What must be kept apart</th><th>Boundary mechanism</th><th>Immediate effect</th></tr></thead><tbody><tr><td>Business from platform</td><td>Stable platform capabilities and business-specific policy</td><td>Stable contracts, business plugins, separate repositories</td><td>Customization stays out of the platform core</td></tr><tr><td>Business from business</td><td>Rules and implementations owned by different businesses</td><td>Business identity, targeted loading, call-chain context</td><td>One business’s change does not enter another by default</td></tr><tr><td>Logical from physical architecture</td><td>Business flows and application or service topology</td><td>Annotation metadata, unified reporting, management view</td><td>Designers discover capabilities by scenario rather than application map</td></tr></tbody></table></div><p>These are not three unrelated features. The first determines where code belongs. The second determines which rule space a request may enter. The third determines what people see when they design a change. Omit any one and the others weaken: plugins without identity can still match the wrong business; identity without a code boundary still ties every business to the platform build; runtime isolation without a logical view still leaves impact analysis wandering through more than two thousand services.</p><figure class="article-figure"><img src="/assets/articles/lattice-clean-architecture-practice/figure-02-three-separations.webp?v=e7db09c1f97bfcaa" width="1672" height="941" loading="lazy" alt="A platform core connected to external business plugins through contracts, isolated lanes for separate business identities, and one logical business flow above a fragmented physical service topology"><figcaption><p><strong>Figure 2 · The three separations in Lattice.</strong> On the left, business change stays outside the platform core. In the middle, identity selects one isolated rule space before execution. On the right, capabilities scattered across physical applications are restored to a logical view that people can design and assess.</p></figcaption></figure><h2 id="First-separation-business-code-from-platform-code"><span class="section-no">10</span><a href="#First-separation-business-code-from-platform-code" class="headerlink" title="First separation: business code from platform code"></a>First separation: business code from platform code</h2><p>The old co-development model asked the platform to define an SPI and business teams to submit implementations directly into the platform project. It worked well at first because a new business could enter the main flow quickly. At scale, however, stable platform mechanisms and local business policies accumulated in the same repository. Platform changes had to account for business implementations; business changes inherited the platform’s branching, regression, and release cycle. Each side became embedded in the other.</p><p>Lattice keeps only stable entities, use cases, abilities, extension contracts, and default behavior in the platform repository. Concrete business rules live in separately owned plugin packages and repositories. Registration and plugin loading connect the two at runtime: the platform declares what may vary, while the plugin declares how one business behaves at that point. Dependencies point toward stable platform contracts; the platform core does not depend on a particular business. <sup class="ref"><a href="#ref-3">[3]</a></sup></p><p>Three boundaries can then align:</p><ul><li><strong>Code boundary</strong> — Customization does not enter the platform core repository.</li><li><strong>Test boundary</strong> — A plugin can verify its own rules and selected capabilities.</li><li><strong>Release boundary</strong> — A business change is no longer inherently tied to a platform version or a regression cycle for every other business.</li></ul><p>Plugins do not guarantee independent delivery. Shared data, contract compatibility, runtime containers, and organizational process can still couple releases. They do, however, remove the most dangerous reverse dependency from the source tree and make independent build, verification, and delivery an option the architecture genuinely supports.</p><h2 id="Second-separation-one-business-from-another"><span class="section-no">11</span><a href="#Second-separation-one-business-from-another" class="headerlink" title="Second separation: one business from another"></a>Second separation: one business from another</h2><p>A conventional SPI asks, “Which implementation’s filter matches this request?” Lattice first asks, “Which business does this request belong to?”</p><p>The questions sound similar but produce very different systems. In a conventional SPI, every implementation uses a <code>filter</code> to guess whether it applies to the current request, so implementations owned by every business share one candidate set. Miss one constraint, cover one channel too broadly, or let two conditions overlap, and a rule written for Business A may execute for Business B. Correctness is distributed across every implementation; as businesses and combinations grow, proving that all filters remain mutually exclusive becomes unrealistic.</p><p>Lattice reverses the order: <strong>the first action at every business-scenario entry point is to establish business identity.</strong> Once identity is known, the runtime has an explicit coordinate. It loads only the plugin packages and realizations associated with that identity; code owned by other businesses never enters the candidate set. Isolation is no longer a fragile convention that every developer must preserve in every filter. It becomes part of the execution model.</p><figure class="highlight java"><div class="table-wrap"><table><tbody><tr><td class="code"><pre><span class="line"><span class="meta">@Business(code = "business.a", name = "Business A")</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BusinessA</span> <span class="keyword">extends</span> <span class="title class_">BusinessTemplate</span> {</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Realization(codes = "business.a")</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BusinessAExt</span> <span class="keyword">extends</span> <span class="title class_">BlankOrderLinePriceExt</span> {</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Long <span class="title function_">getCustomUnitPrice</span><span class="params">(OrderLine orderLine)</span> {</span><br><span class="line">        <span class="keyword">return</span> <span class="number">2000L</span>;</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></div></figure><p><code>@Business</code> declares the business; <code>@Realization</code> declares which business owns the implementation. The call chain carries a unified business code, and the runtime locates plugins and realizations by that identity. The annotation syntax is incidental. The important shift is from ownership inferred through conditions to ownership declared explicitly: establish who I am first, then discover which rules are mine.</p><p>The identity must survive the entire call chain. If an entry point knows the business but loses that identity when it calls a downstream service, isolation ends at the process boundary. Lattice treats the business code as a core piece of extension context, keeping one business’s rules coherent across capability calls.</p><p>The first two separations now establish code ownership and runtime scope. The third requires a vocabulary that can lift platform capabilities out of scattered interfaces and organize them into complete use cases. Ability, the two business axes, Reduce, and Use Case provide the language from which that logical business view can be built.</p><h2 id="Ability-makes-platform-capabilities-discoverable-and-callable"><span class="section-no">12</span><a href="#Ability-makes-platform-capabilities-discoverable-and-callable" class="headerlink" title="Ability makes platform capabilities discoverable and callable"></a>Ability makes platform capabilities discoverable and callable</h2><p>Business identity answers “whose rule?” An Ability answers “what can the platform do for this business object?”</p><p>In Lattice, an ability groups extensible behavior around a particular business object. An order line may be that object, pricing the ability, and “custom item unit price” one extension point. The ability loads realizations for the current business and combines their results according to explicit reduction semantics; the business implements only the behavior it needs to change.</p><figure class="highlight java"><div class="table-wrap"><table><tbody><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">OrderLinePriceExt</span> <span class="keyword">extends</span> <span class="title class_">IBusinessExt</span> {</span><br><span class="line">    <span class="type">String</span> <span class="variable">EXT_ORDER_LINE_CUSTOM_UNIT_PRICE</span> <span class="operator">=</span></span><br><span class="line">        <span class="string">"OrderLinePriceExt.EXT_ORDER_LINE_CUSTOM_UNIT_PRICE"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Extension(</span></span><br><span class="line"><span class="meta">        code = EXT_ORDER_LINE_CUSTOM_UNIT_PRICE,</span></span><br><span class="line"><span class="meta">        name = "Custom the Item's unit price of OrderLine",</span></span><br><span class="line"><span class="meta">        reduceType = ReduceType.FIRST</span></span><br><span class="line"><span class="meta">    )</span></span><br><span class="line">    Long <span class="title function_">getCustomUnitPrice</span><span class="params">(OrderLine orderLine)</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Ability(name = "OrderLine's Price Ability")</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderLinePriceAbility</span></span><br><span class="line">        <span class="keyword">extends</span> <span class="title class_">BaseLatticeAbility</span>&lt;OrderLinePriceExt&gt; {</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">OrderLinePriceAbility</span><span class="params">(OrderLine orderLine)</span> {</span><br><span class="line">        <span class="built_in">super</span>(orderLine);</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Long <span class="title function_">getCustomUnitPrice</span><span class="params">(OrderLine orderLine)</span> {</span><br><span class="line">        <span class="keyword">return</span> Optional.ofNullable(reduceExecute(</span><br><span class="line">                ext -&gt; ext.getCustomUnitPrice(orderLine),</span><br><span class="line">                Reducers.firstOf(Objects::nonNull)))</span><br><span class="line">            .orElse(orderLine.getUnitPrice());</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> BlankOrderLinePriceExt <span class="title function_">getDefaultRealization</span><span class="params">()</span> {</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">BlankOrderLinePriceExt</span>();</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></div></figure><p>This changes three things. First, platform capabilities become discoverable; developers no longer search thousands of applications for scattered SPIs. Second, the platform still supplies default behavior, so a business with no customization falls back naturally. Third, the meaning of multiple results is defined by the ability rather than by accidental registration order.</p><p>Restraint matters here. Ability is not a new word for wrapping every method. Only behavior with stable business meaning—and for which different businesses genuinely need different choices—deserves to become an ability or extension point. More interfaces do not automatically create a more flexible platform. They may simply create another surface that must be maintained.</p><h2 id="Before-the-two-axes-what-counts-as-a-business"><span class="section-no">13</span><a href="#Before-the-two-axes-what-counts-as-a-business" class="headerlink" title="Before the two axes, what counts as a business?"></a>Before the two axes, what counts as a business?</h2><p>“Business” is one of those words that can expand to mean almost anything. People often call whatever they happen to own “the business,” or equate a business with a box on the organization chart. For the model to be useful in code, I need a more operational definition: <strong>a business is a sustained set of activities, decisions, and rules that delivers a product or service and produces an economic outcome through revenue growth or lower cost.</strong></p><p>That definition includes both sides of the ledger. Companies often organize teams as profit centers and cost centers. Profit centers focus more heavily on markets, products, operating models, and supply chains that create revenue. Cost centers focus more heavily on shared platforms, process improvement, and efficiency. Their immediate concerns differ, but both ultimately answer the same operating question: how can the company keep creating value while preserving healthy room between revenue and cost?</p><p>On a software platform, those operating changes consistently produce two kinds of rules. One kind usually belongs to a particular industry and describes how that industry prices, transacts, fulfills, and manages risk. Together, those rules form a coherent operating model. The other kind comes from an industry-agnostic play or platform capability. It changes one part of the transaction in a way that can add revenue, efficiency, or customer value across many industries. The first kind needs autonomy; the second needs reuse. One answers “which industry’s rules are these?” The other answers “which reusable plays has this industry chosen?”</p><p>That is where the vertical and horizontal axes come from. They were not invented to make an architecture diagram look tidy. They are the rule-level projection of two realities: who owns an operating outcome, and how a platform reuses capabilities across owners.</p><h2 id="Why-business-rules-fall-along-vertical-and-horizontal-axes"><span class="section-no">14</span><a href="#Why-business-rules-fall-along-vertical-and-horizontal-axes" class="headerlink" title="Why business rules fall along vertical and horizontal axes"></a>Why business rules fall along vertical and horizontal axes</h2><p>A <strong>vertical business is usually an industry.</strong> It is a business space with end-to-end operating responsibility: auto finance, on-demand delivery, or movie tickets. It owns more than a few configuration differences. It is accountable for the industry’s customers, revenue, fulfillment, risk, and final operating result. Its rules therefore need isolation. Auto finance rules for qualification, preauthorization timeout, and non-logistics fulfillment should not leak into on-demand delivery. Delivery pricing, service radius, and SLA rules should not become defaults for movie tickets.</p><p>Even when two vertical businesses happen to use the same ten-minute payment timeout today, each should declare that value in its own business space. They may reuse the payment-timeout capability and its implementation, but they should not share one business’s ten-minute decision. If one changes the value to fifteen minutes tomorrow, the other should not change without taking part in that decision. <strong>The vertical axis establishes ownership and isolation: similar code does not turn one operator’s policy into another operator’s policy.</strong></p><p>In the Lattice model, a <strong>horizontal business is usually an industry-agnostic play or platform.</strong> We might also call it a platform business or cross-cutting capability. It does not own a complete industry operating model. Instead, it packages a reusable way of creating value and modifies a slice of the vertical baseline. The core of electronic vouchers is code issuance, redemption, and refunds; it does not matter whether the adopter sells movie tickets, attraction tickets, or car-care services. A campaign may change the purchase entry point, price, and sales-counting rules across industries. Cash on delivery changes when payment occurs, how checkout behaves, and how small cash amounts are rounded, regardless of the vertical.</p><p>A horizontal business is defined independently of any one vertical, but many verticals may choose to adopt it. Movie tickets and car-care services can both use electronic vouchers while choosing different redemption counts. One business can install vouchers and presales together, then add a campaign as well. A vertical adopts those changes because a horizontal capability can expand what is sellable, improve conversion, lower cost, or improve the customer experience. <strong>The horizontal axis provides reuse and controlled variation: it does not replace the vertical business, but supplies optional changes to its baseline.</strong></p><p>The two kinds of business also differ in a way that matters enormously to the architecture: <strong>vertical industries are relatively enumerable and stable; horizontal plays are open-ended, effectively impossible to enumerate in advance, and change frequently.</strong> I do not mean “countable” and “uncountable” in the set-theoretic sense. This is an engineering distinction. A company can usually list the industries it operates today. Entering a new industry is an explicit, relatively infrequent strategic decision, so an industry can carry a durable business identity. There is no equivalent final list of horizontal plays. New campaign mechanics, fulfillment methods, payment options, membership benefits, and risk controls keep appearing—and keep combining with one another.</p><p>If every “industry × set of horizontal plays” became a new business type, then with <code>|V|</code> verticals and <code>|H|</code> independently selectable horizontal capabilities, the theoretical number of combinations would approach <code>|V| × 2^|H|</code>. Each new horizontal capability could double the combination space. Encoding those combinations as subclasses, business codes, or global SPI conditions would make the type system and the decision tree explode together.</p><p>Lattice models the problem in the opposite direction. A relatively small, stable set of vertical industries provides the coordinate system and the business identities. Each identity then selects <code>N</code> horizontal businesses from an open-ended set. Each request is first anchored to one vertical identity, acquiring that vertical’s defaults and ownership boundary. The runtime then resolves the horizontal capabilities and realizations selected for that identity. Adding a horizontal play is like adding a new optional column; it does not require redefining every vertical. Changing one vertical’s selection does not rewrite another vertical’s baseline. <strong>A stable identity carries an open-ended composition, which is what keeps high-frequency customization from destabilizing the platform.</strong></p><p>Two boundaries follow. A workflow that crosses industries should coordinate several explicitly identified business contexts, not make one request belong to several vertical spaces at once. And within each vertical baseline, the platform may select zero, one, or many horizontal capabilities. <code>N</code> may be zero, and it may keep growing as the business innovates.</p><p>The effective rule set for a business can therefore be expressed as:</p><div class="equation"><p>Complete business rules = 1 vertical baseline + N horizontal increments (N ≥ 0)</p></div><p>The “1” establishes a single, stable owner and a set of defaults. The “N” represents open-ended, reusable, composable enhancements. This is not class inheritance, nor is it a blind concatenation of configuration files. It is a sparse, scoped composition—each vertical selects only the horizontal capabilities it needs—with explicit ordering and reduction semantics. Conventional SPI offers one flat global list of implementations. Lattice first resolves the vertical business space, then the horizontal capabilities selected in that space, and finally the way their rules combine at each extension point.</p><figure class="article-figure"><img src="/assets/articles/lattice-clean-architecture-practice/figure-03-business-lattice.webp?v=f8d92ca9286a3192" width="1672" height="941" loading="lazy" alt="Isolated vertical businesses intersect reusable horizontal capabilities, with each intersection representing an explicit selection or customization"><figcaption><p><strong>Figure 3 · The two business dimensions in Lattice.</strong> Vertical businesses preserve ownership and isolation; horizontal capabilities provide reuse across industries. An intersection is not a global condition that happened to match, but an explicit choice by one vertical business to adopt one horizontal capability.</p></figcaption></figure><h2 id="Reduce-does-not-make-the-policy-decision-it-makes-conflict-explicit"><span class="section-no">15</span><a href="#Reduce-does-not-make-the-policy-decision-it-makes-conflict-explicit" class="headerlink" title="Reduce does not make the policy decision; it makes conflict explicit"></a>Reduce does not make the policy decision; it makes conflict explicit</h2><p>Once the complete rule set is defined as one vertical baseline plus <code>N</code> horizontal increments, conflict is no longer an edge case. It is a question the composition model must answer directly. Several horizontal capabilities may modify the same business decision, and the vertical baseline may already have a policy of its own. The framework must do more than find those rules: it must state whether they can coexist and, if they can, how they produce one result.</p><p>Some rules are reducible. Consider purchase quantity. The vertical business says it cannot exceed available stock. An electronic-voucher capability allows at most 250 units per purchase. A campaign limits the order to 10. These are upper bounds from different sources, not attempts to override one another. Taking the minimum satisfies all three, so a reducer such as <code>MIN</code> has clear business meaning.</p><p>Other rules are mutually exclusive. A campaign may exclude a sale from volume statistics by default, while a particular vertical business—after agreement between the two owners—requires its own sales-counting policy to prevail. Two Boolean answers cannot be reconciled by taking a minimum or merging a collection. The composition needs an explicit priority rule stating whether the vertical or horizontal policy has final authority.</p><p>Lattice therefore treats composition as two separate questions: <strong>a Reduce algorithm answers “how can several results be combined?”; conflict priority answers “who decides when they cannot be combined?”</strong> A reducer may select the first non-null value, merge collections, take a minimum, or apply another algorithm with clear business semantics. Priority must be agreed and declared by the relevant business owners. A framework cannot make that policy decision for them, but it can require the decision to be explicit instead of hiding it in registration order.</p><div class="equation"><p>Effective business rule = Reduce(vertical baseline, horizontal increments 1…N, conflict priority)</p></div><div class="table-wrap"><table><caption>From conventional SPI to Lattice extension invocation</caption><thead><tr><th>Dimension</th><th>Conventional SPI</th><th>Lattice</th></tr></thead><tbody><tr><td>Ownership</td><td>Inferred indirectly through <code>filter</code></td><td>Declared through business identity</td></tr><tr><td>Candidate scope</td><td>Global implementation list</td><td>Current business and its selected capabilities</td></tr><tr><td>Multiple matches</td><td>Registration order or first match</td><td>Reduce and explicit conflict priority</td></tr><tr><td>Business reuse</td><td>Copy implementations or share hidden conditions</td><td>Compose horizontal capabilities by business</td></tr><tr><td>Impact analysis</td><td>Read every filter</td><td>Inspect the business space and composition</td></tr></tbody></table></div><h2 id="Use-cases-let-architecture-speak-business-language-again"><span class="section-no">16</span><a href="#Use-cases-let-architecture-speak-business-language-again" class="headerlink" title="Use cases let architecture speak business language again"></a>Use cases let architecture speak business language again</h2><p>Abilities organize extensible behavior, but business stakeholders rarely frame a problem as a method on an entity. They talk about scenarios such as “buyer places order,” “seller fulfills,” or “buyer requests refund.” <em>Clean Architecture</em> places use cases outside entities: a use case guides data through entities and coordinates them toward a particular application goal. <sup class="ref"><a href="#ref-2">[2]</a></sup></p><p>That distinction matters in a transaction platform. An electronic-voucher scenario spans orders, voucher issuance, notifications, redemption, and several systems. Entity-level SPIs alone still leave the business team to assemble the end-to-end process. Lattice therefore supports reusable assets at the use-case layer and scenario SDKs organized around business activities.</p><p>For electronic vouchers, the platform can provide the end-to-end capabilities for generating, issuing, redeeming, and refunding vouchers, while opening only policies where real differences exist:</p><figure class="highlight java"><div class="table-wrap"><table><tbody><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">ETicketTradeSDK</span> <span class="keyword">extends</span> <span class="title class_">IBusinessExt</span> {</span><br><span class="line">    <span class="meta">@Extension(reduceType = ReduceType.NONE)</span></span><br><span class="line">    Boolean <span class="title function_">isVoucherSupportMultiWriteOff</span><span class="params">()</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></div></figure><p>A movie-ticket business can allow a single redemption; a car-care package containing twelve washes can allow multiple redemptions. The business developer sees the policy “does this voucher support multiple redemptions?” They do not need to know which K/V attribute an order uses to store the answer, or search each application for a technical hook.</p><p>The scenario layer maps a meaningful rule onto lower-level entities. During order persistence, for example, the voucher use case can translate “multiple redemption allowed” into an order attribute. The entity knows how to save attributes reliably; it need not know about movie tickets, wash packages, or a future industry. The scenario depends on the entity, while the entity does not depend on a specific scenario—an instance of the Dependency Rule applied to business extension.</p><p>Most importantly, scenario assets can compose. A movie-ticket business can install both electronic voucher and presale capabilities: vouchers decide redemption behavior, while presale determines the deposit ratio. The business does not inherit an ever-growing “movie ticket platform.” It installs two relatively independent scenario capabilities inside its own business space.</p><h2 id="Third-separation-logical-business-architecture-from-physical-application-architecture"><span class="section-no">17</span><a href="#Third-separation-logical-business-architecture-from-physical-application-architecture" class="headerlink" title="Third separation: logical business architecture from physical application architecture"></a>Third separation: logical business architecture from physical application architecture</h2><p>The first two separations determine where code belongs and which rule space a request enters. Ability and Use Case then provide a vocabulary for capabilities and complete scenarios. On that foundation, the third separation determines how people understand the platform. Traditional platforms expose extensions through physical applications: the product service has one set of SPIs, while cart, transaction, and fulfillment services each expose another. That catalog faithfully describes deployment, but it does not explain how a business scenario works end to end. Once the estate exceeds two thousand microservices, asking any person to master the application topology before designing a business change is asking for impossible impact analysis.</p><p>Lattice uses annotations such as <code>@Ability</code> and <code>@Extension</code> to declare capabilities, extension points, defaults, and reduction semantics. <code>@Business</code> and <code>@Realization</code> declare businesses and implementation ownership. A runtime can discover this metadata and report it into a common business-management plane. The resulting organizing unit is no longer “a Java interface in application X.” It is a business flow—ordering, fulfillment, refunds, redemption—and the business policies that may vary along that flow.</p><p>Business stakeholders and designers can therefore begin with the logical view. They can follow an end-to-end process, see which capabilities the platform already provides, which horizontal plays the current business has installed, which extension points already have realizations, and which Reduce policy governs a collision. Existing pieces can be selected and composed. Anything that still appears to be missing becomes a concrete gap list for discussion with platform designers. The conversation changes from “I think some system may need a change” to “this business step lacks a reusable policy.” Platform evolution becomes more deliberate as a result.</p><p>The management view must be more than a flat extension registry. To support design and impact analysis, each extension point needs business meaning, scenario placement, inputs and outputs, default behavior, Reduce policy, owner, compatibility information, and current adopters. The platform should also preserve traceability from each logical node to its physical applications, interfaces, and runtime instances. <strong>Separating logical from physical architecture does not hide the physical system. It stops making deployment topology the starting point for business design.</strong></p><p>Annotations do not create a sound business model by themselves. Reporting every low-level method would merely replace a map of two thousand services with an equally unmanageable interface catalog. Platform designers must still identify stable business semantics, organize use cases and abilities, and own contract evolution. Lattice provides a loop from code declaration to unified reporting, business design, and runtime execution; it does not replace modeling.</p><p>This also reflects my reading of “frameworks are details.” Lattice belongs in its proper place. It resolves identity, invokes extensions, loads realizations, discovers metadata, and reduces results, but the business rules that matter still belong to businesses and use cases.</p><figure class="article-figure"><img src="/assets/articles/lattice-clean-architecture-practice/figure-04-clean-boundaries.webp?v=b8bb1efb1d824116" width="1672" height="941" loading="lazy" alt="Stable entities and use cases at the center, with business plugins and external infrastructure beyond explicit boundaries and all dependencies pointing inward"><figcaption><p><strong>Figure 4 · Where Lattice sits in a clean architecture.</strong> Lattice lets external business plugins participate through stable contracts while dependencies still point toward entities and use cases. The framework, database, and plugins are mechanisms; none should become the center of business policy.</p></figcaption></figure><h2 id="Do-not-make-the-runtime-rediscover-decisions-we-can-make-up-front"><span class="section-no">18</span><a href="#Do-not-make-the-runtime-rediscover-decisions-we-can-make-up-front" class="headerlink" title="Do not make the runtime rediscover decisions we can make up front"></a>Do not make the runtime rediscover decisions we can make up front</h2><p>Much of the risk in conventional SPI comes from dynamic guessing: iterate over every implementation and run an arbitrary <code>filter</code> until something matches. The answer may depend on current data, a remote call, or implementation order, making the blast radius impossible to state in advance.</p><p>Lattice favors determining which capabilities a business uses, how rules compose, and how conflicts are resolved during management and configuration. Runtime then executes the established rule set and conflict policies. The official repository likewise identifies separation of management and runtime domains as a core design. <sup class="ref"><a href="#ref-3">[3]</a></sup></p><p>This does not mean runtime behavior has no dynamic conditions. It means distinguishing two kinds of information. <strong>Which rules belong to this business</strong> should be as static, visible, and auditable as possible. What those rules do with this particular order depends on runtime data. The former should not be rediscovered on every request.</p><p>Once composition can be inspected before execution, product managers and developers can perform impact analysis together: which scenarios are installed, which extension points they cover, how many realizations target the same point, and which Reduce policy applies. Architecture no longer exists only in a code reader’s head; it becomes a manageable business model.</p><p class="part-label">Part IV · A minimal example, then a complete composition</p><h2 id="Business-A-customizes-price-Business-B-keeps-the-default"><span class="section-no">19</span><a href="#Business-A-customizes-price-Business-B-keeps-the-default" class="headerlink" title="Business A customizes price; Business B keeps the default"></a>Business A customizes price; Business B keeps the default</h2><p>The smallest end-to-end Lattice example is straightforward. The platform defines an extension for customizing an order line’s unit price, along with a pricing ability. Business A declares its identity and implements that extension to return <code>2000L</code>; Business B makes no customization. Both orders start with a default unit price of <code>1000L</code>.</p><figure class="highlight java"><div class="table-wrap"><table><tbody><tr><td class="code"><pre><span class="line"><span class="type">OrderLine</span> <span class="variable">orderLine</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">OrderLine</span>();</span><br><span class="line">orderLine.setUnitPrice(<span class="number">1000L</span>);</span><br><span class="line">orderLine.setBizCode(<span class="string">"business.a"</span>);</span><br><span class="line"></span><br><span class="line"><span class="type">OrderLinePriceAbility</span> <span class="variable">ability</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">OrderLinePriceAbility</span>(orderLine);</span><br><span class="line"><span class="type">Long</span> <span class="variable">unitPrice</span> <span class="operator">=</span> ability.getCustomUnitPrice(orderLine);</span><br></pre></td></tr></tbody></table></div></figure><p>The result for Business A is <code>2000L</code>; Business B still receives <code>1000L</code>. Superficially this resembles the Strategy pattern. The difference is that business identity locates the realization, the ability owns the default, and the extension contract defines result reduction. The complete Quick Start and more realistic compositions are available in <a href="https://github.com/hiforce/lattice-sample">lattice-sample</a>. <sup class="ref"><a href="#ref-4">[4]</a></sup></p><p>At this essay’s latest update, the sample repository’s main branch still pinned Lattice at <code>1.0.19</code>. I temporarily changed it to <code>1.0.21</code> and rebuilt both the Quick Start and Use Case modules; both passed. The console output in the next section also came from an actual <code>1.0.21</code> run. This is modest verification, but it keeps the code in an architecture essay from being merely plausible.</p><p>As the number of realizations grows from two to hundreds or thousands, the value of these extra concepts becomes clear. They restore the information that old implementations lacked: which business owns the change, which capability it extends, how it composes, and what happens when no realization exists.</p><h2 id="Electronic-vouchers-and-presales-in-one-business"><span class="section-no">20</span><a href="#Electronic-vouchers-and-presales-in-one-business" class="headerlink" title="Electronic vouchers and presales in one business"></a>Electronic vouchers and presales in one business</h2><p>Consider a combination closer to a real business. The movie-ticket business installs the electronic-voucher scenario and declares that a voucher may be redeemed only once. It also installs a presale scenario with a 40 percent deposit. The ordering use case invokes both scenario abilities and maps the business data that must be persisted onto the order entity.</p><figure class="highlight text"><div class="table-wrap"><table><tbody><tr><td class="code"><pre><span class="line">[UseCase]PreSaleTrade load custom down payment ratio: .40</span><br><span class="line">[UseCase]ETicketTrade is support multiple write-off: false</span><br><span class="line">Save OrderLine id: 1, bizCode: hi.movie</span><br><span class="line">-- Total Pay Price: 4000</span><br><span class="line">-- Order Attributes: [e_multi_write_off:0]</span><br></pre></td></tr></tbody></table></div></figure><p>Four responsibilities remain distinct behind this output. The business plugin declares what differs for movie tickets. The presale and electronic-voucher use cases encapsulate reusable scenarios. The order entity owns stable data and lifecycle. The Lattice runtime connects realizations by business identity and reduces extension results.</p><p>If a car-care business is added later, it can reuse the same voucher scenario while allowing multiple redemptions. If it also uses presales, its deposit ratio can be configured independently. The movie-ticket rules do not change, and the new business does not enter a global SPI ordering contest.</p><h2 id="A-complete-mapping-from-problems-to-mechanisms"><span class="section-no">21</span><a href="#A-complete-mapping-from-problems-to-mechanisms" class="headerlink" title="A complete mapping from problems to mechanisms"></a>A complete mapping from problems to mechanisms</h2><div class="table-wrap"><table><caption>How Lattice answers each platform challenge</caption><thead><tr><th>Original challenge</th><th>Lattice mechanism</th><th>Immediate change</th></tr></thead><tbody><tr><td>Business and platform code intertwined</td><td>Business plugins and separate code boundaries</td><td>Customization stays outside platform core</td></tr><tr><td>Businesses influence one another</td><td>Unified business identity</td><td>Realizations are isolated by business space first</td></tr><tr><td>Extension points scattered across applications</td><td>Ability and scenario-level SDKs</td><td>Extension contracts are expressed in business terms</td></tr><tr><td>Business flows fragmented by physical topology</td><td>Annotation metadata, unified reporting, and a management view</td><td>Capabilities are discovered by scenario and missing policies become explicit</td></tr><tr><td>Horizontal capabilities are hard to reuse</td><td>Vertical businesses plus horizontal composition</td><td>Scenario assets can be selected and overlaid</td></tr><tr><td>Implementation order determines results</td><td>Reduce and conflict priority</td><td>Composition semantics become contractual</td></tr><tr><td>Runtime filters hide impact</td><td>Management decisions separated from execution</td><td>Compositions can be inspected in advance</td></tr><tr><td>One release and system-wide regression</td><td>Plugin loading and delivery boundaries</td><td>Independent business delivery becomes possible</td></tr></tbody></table></div><p>This table captures the point I most want readers to retain. A framework should not be evaluated first by the number of annotations and extension strategies it offers. Each mechanism should answer a real problem that appears repeatedly.</p><p class="part-label">Part V · Rereading the book made the limits matter more</p><h2 id="Lattice-does-not-eliminate-business-complexity"><span class="section-no">22</span><a href="#Lattice-does-not-eliminate-business-complexity" class="headerlink" title="Lattice does not eliminate business complexity"></a>Lattice does not eliminate business complexity</h2><p><em>Clean Architecture</em> is easy to misread as a promise that correct layering keeps a system clean by itself. Extension frameworks invite a similar mistake: once code is plugin-based, any business can supposedly customize at no cost. I now prefer the opposite emphasis. Lattice does not remove business complexity; it tries to put each kind of complexity where it belongs.</p><p>Whether two vertical businesses should be isolated is a modeling decision. Whether a horizontal capability is genuinely reusable requires evidence from real scenarios. When two rules conflict, an owner still has to decide which wins. If an extension point is too fine-grained or too technical, business teams will still drown in implementation detail. A framework can make decisions explicit, but it cannot make the right decisions for us.</p><p>Several misuses deserve particular caution:</p><ul><li><strong>Opening every method as an extension point.</strong> This exposes platform internals and lets contract count grow without control.</li><li><strong>Using a business code as a substitute for domain modeling.</strong> <code>bizCode</code> defines scope; it does not explain the business.</li><li><strong>Treating Reduce as an escape hatch.</strong> A reducer without business semantics only conceals a contradiction.</li><li><strong>Building a runtime without a management view.</strong> If nobody can inspect the active composition, impact analysis remains difficult.</li><li><strong>Separating plugin code while coupling all data.</strong> A code boundary does not solve shared-data ownership or interface evolution.</li></ul><p>Before adding Lattice, I would ask three questions. Is this a stable, nameable point of business variation? Are its owner and scope clear? If two realizations apply, is there an explainable composition rule? If I cannot answer all three, adding another extension point usually postpones the modeling problem rather than solving it.</p><h2 id="Seven-engineering-judgments-I-took-from-rereading-Clean-Architecture"><span class="section-no">23</span><a href="#Seven-engineering-judgments-I-took-from-rereading-Clean-Architecture" class="headerlink" title="Seven engineering judgments I took from rereading Clean Architecture"></a>Seven engineering judgments I took from rereading <em>Clean Architecture</em></h2><p>Years later, I no longer read the book mainly as advice about which directory should contain entities, use cases, and adapters. Circles, module names, and interfaces are representations. The real test is the cost of change: how many unrelated teams a new business must involve, how many existing businesses need regression testing, whether a fault stays inside a known scope, and whether the system preserves the option to replace mechanisms and deployment forms later.</p><p>Combined with the Lattice experience, that reading produced seven engineering judgments. They are not a second summary bolted onto the essay. They compress business identity, use cases, Reduce, plugin boundaries, and the management view into one design-review checklist.</p><div class="principles"><div class="principle"><strong>01 · Judge architecture by the total cost of change</strong> — Layers and interface counts prove little; ask who a change disturbs, what must be retested, and whether a failure can be contained.</div><div class="principle"><strong>02 · Establish scope before extension</strong> — State which business owns a rule; do not let a global filter stand in for ownership.</div><div class="principle"><strong>03 · Speak business language before defining technical interfaces</strong> — Organize code around use cases and stable policy rather than exposing physical application steps as contracts.</div><div class="principle"><strong>04 · Composition needs semantics</strong> — When several realizations apply, Reduce, ordering, and conflict priority belong in the contract.</div><div class="principle"><strong>05 · Give logical boundaries physical support</strong> — Repositories, plugins, tests, and delivery should align; independent build and verification are pressure tests for whether a boundary is real.</div><div class="principle"><strong>06 · Begin with business design, and settle management decisions before runtime</strong> — Discover and audit capabilities along the flow before tracing them to applications; do not make every request rediscover a composition that could have been declared earlier.</div><div class="principle"><strong>07 · Keep the framework a detail and preserve future options</strong> — Lattice serves business rules. Stable policy belongs at the center; mechanisms, plugins, and deployment forms remain replaceable outside it.</div></div><p>The first judgment states what architecture ultimately optimizes. Judgments two through six describe the boundaries through which change should travel. The seventh prevents the solution itself from taking control of the business model. At this point, however, people still have to remember to apply them. In the age of AI-assisted programming, the next step is to turn those judgments into a workflow that a coding agent must execute before it touches the code.</p><h2 id="From-the-transaction-platform-to-Spark-turn-architecture-into-a-Skill-for-AI-coding"><span class="section-no">24</span><a href="#From-the-transaction-platform-to-Spark-turn-architecture-into-a-Skill-for-AI-coding" class="headerlink" title="From the transaction platform to Spark: turn architecture into a Skill for AI coding"></a>From the transaction platform to Spark: turn architecture into a Skill for AI coding</h2><p>The transaction-platform experience taught me why boundaries matter. Spark introduced a more immediate problem. An AI agent can generate changes across several modules in minutes, but it usually sees the current task and nearby files—not the dependency direction, ownership decisions, and expensive failures that shaped the repository over years. “Please follow clean architecture” is far too weak a prompt. It still tends to produce locally reasonable code that crosses system-wide boundaries.</p><p>I began organizing architectural knowledge into four layers. <code>docs/principle/01.clean_architect_with_lattice.md</code> preserves the narrative and explains why the boundaries exist. <code>docs/principle/02.ai-clean-architecture-lattice-guidelines.md</code> reduces that history to checkable placement rules, Session Scope rules, and Process / Activity / Result rules. The repository-level <code>AGENTS.md</code> states which kinds of work must load those rules first. An architecture Skill then turns reading, reviewing, designing, coding, and auditing into a workflow the AI is required to follow.</p><div class="table-wrap"><table><caption>From architectural knowledge to AI coding constraints</caption><thead><tr><th>Layer</th><th>Purpose</th><th>Question it answers</th></tr></thead><tbody><tr><td>Background principles</td><td>Preserve cases, reasoning, and trade-offs</td><td>Why is the system designed this way?</td></tr><tr><td>Executable rules</td><td>State allowed placements, prohibitions, and checks</td><td>What code may go where?</td></tr><tr><td>Repository triggers</td><td>Require the AI to load specific principles for specific work</td><td>When is an architecture review mandatory?</td></tr><tr><td>Architecture Skill</td><td>Fix the review sequence and required output</td><td>What must the AI do before and after coding?</td></tr></tbody></table></div><p>The Skill is not the sole copy of architectural truth. Durable rules stay in the repository so Codex, Claude, and human engineers can all read the same source. The Skill is an execution adapter: it loads those facts at the right moment and prevents the agent from skipping directly to code generation. A shortened version derived from Spark’s actual rules looks like this:</p><figure class="highlight markdown"><div class="table-wrap"><table><tbody><tr><td class="code"><pre><span class="line">---</span><br><span class="line">name: spark-clean-architecture-review</span><br><span class="line"><span class="section">description: Review Spark backend design, module changes, and Lattice extensions before coding.</span></span><br><span class="line"><span class="section">---</span></span><br><span class="line"></span><br><span class="line"><span class="section"># Workflow</span></span><br><span class="line"><span class="bullet">1.</span> Classify the change as Entity, Use Case, Adapter, or Plugin.</span><br><span class="line"><span class="bullet">2.</span> Declare modules, packages, and dependency direction; never put DOs, repositories, or plugin clients in an SDK.</span><br><span class="line"><span class="bullet">3.</span> If the platform path branches on cluster, language, or cloud provider, replace the branch with a stable business identity and plugin realization.</span><br><span class="line"><span class="bullet">4.</span> Open one Session Scope at the scenario boundary; propagate that identity through Process and Activity code.</span><br><span class="line"><span class="bullet">5.</span> Give a complex Use Case one Request and one Result; gather side effects at the end of the Process.</span><br><span class="line"></span><br><span class="line"><span class="section"># Required output</span></span><br><span class="line"><span class="bullet">-</span> Business identity and scope entry point</span><br><span class="line"><span class="bullet">-</span> Module placement and dependency direction</span><br><span class="line"><span class="bullet">-</span> Ability / Extension / Reduce design</span><br><span class="line"><span class="bullet">-</span> Use Case / Process / Activity / Result design</span><br><span class="line"><span class="bullet">-</span> Existing violations and verification plan</span><br></pre></td></tr></tbody></table></div></figure><p>In practice, I do not begin by asking the AI to “implement the feature.” I make the Skill force an architectural answer first. Suppose Spark needs Python builds on Kubernetes. The conversation might look like this:</p><blockquote><p><strong>Me:</strong> Add Kubernetes-based Python builds to Spark Flow. Run the architecture Skill first and do not write code yet. Show the business identity, module boundaries, dependency direction, extension contract, and verification plan.</p><p><strong>AI:</strong> Use the identity <code>build.k8s.python</code>. Stable Context, Result, Extension, Ability, and default behavior belong in <code>spark-console-sdk</code>; orchestration remains in <code>spark-pipeline</code>; the Kubernetes-specific Python implementation belongs in <code>spark-k8s-plugin</code>. The plugin receives source material, build parameters, and credential references prepared by the platform, then returns image, log, and status observations. It does not read platform business tables. The scenario entry point opens one Session Scope, and Pipeline does not add a new <code>PYTHON</code> branch.</p><p><strong>Me:</strong> Check that design against the dependency rules. If it passes, implement one module at a time and report the governing rule and test evidence after each layer.</p><p><strong>AI:</strong> I will implement the leaf extension contract and safe default, then the Ability, plugin <code>@Realization</code>, platform invocation, and tests. Before handoff I will check that the platform does not depend on the plugin, the SDK contains no implementation objects, and no internal helper rediscovers business identity.</p></blockquote><p>The module names are not the important part of that exchange. What matters is that the AI exposes its architecture model before generating thousands of lines. Identity, placement, and dependency direction can be corrected while the cost is still low. The same Skill audits the result afterward: Did a Controller quietly acquire orchestration? Did a database object enter the SDK? Did a plugin bypass Context and read a platform table? Did an inner helper open another Session Scope? Did individual Activities write the database and search index on their own?</p><p>For complex operations such as creating, transitioning, or bulk-updating tasks, the Skill also requires one Request and one Result before code generation. A Process orchestrates several Activities; each Activity adds validation, authorization, assignment, persistence plans, and event plans to the same Result. Database, index, and event side effects occur together at the end. The AI therefore generates more than a set of classes that happen to run. It generates a use case whose conceptual integrity remains visible.</p><figure class="article-figure"><img src="/assets/articles/lattice-clean-architecture-practice/figure-05-executable-principles.webp?v=404ea1f6087c6aef" width="1672" height="941" loading="lazy" alt="An architecture Skill reviewing business identity, module boundaries, and dependency direction before guiding an AI to compose one use case around a shared result and controlled side effects"><figcaption><p><strong>Figure 5 · Architecture principles as executable rules for AI coding.</strong> Narrative documentation preserves the reasons, executable guidelines state the constraints, and the Skill produces a design before coding and audits violations afterward. Identity is established at the entrance, Activities share one Result, plugins exchange material through contracts, and side effects gather at the end of the Process.</p></figcaption></figure><p>This changed my view of architecture documentation. It used to explain code after the fact. In AI-assisted development, it is both knowledge and control input. It must carry reasons, permissions, prohibitions, triggers, and evidence of verification. AI does not automatically produce clean architecture, but it gives us an opportunity to turn judgments once passed down by senior engineers into a repeatable review performed on every design and implementation.</p><p>Seen this way, Lattice is more than a runtime mechanism for locating an extension implementation. Business identity, Context, Result, Ability, and plugin contracts form a change protocol that people and AI can both understand: who may alter what, where the code belongs, what material crosses the boundary, what evidence comes back, and where the effect should stop.</p><h2 id="Conclusion-let-change-stop-where-it-belongs"><span class="section-no">25</span><a href="#Conclusion-let-change-stop-where-it-belongs" class="headerlink" title="Conclusion: let change stop where it belongs"></a>Conclusion: let change stop where it belongs</h2><p>The transaction platform I encountered in 2015 did not lack APIs, services, or extension mechanisms. What it lacked were boundaries: between business and platform, between one business and another, between logical business flows and physical application topology, and between management decisions and runtime execution.</p><p>Without those boundaries, adding APIs creates more context parameters, adding SPIs creates a larger global implementation tree, and splitting more applications creates more coordination. Each locally reasonable technology shifts its cost somewhere else as scale grows.</p><p>Lattice began by making those displaced and hidden costs explicit in the architecture. Business plugins separate business from platform. Business identity separates one business from another. Annotation reporting and a management view separate logical architecture from physical topology. Ability then organizes extensible behavior; vertical and horizontal dimensions express isolation and reuse; Reduce states how rules compose; and use cases restore the language of complete business scenarios. The three separations establish the boundaries, while the remaining mechanisms make those boundaries designable, executable, and verifiable.</p><p>Rereading <em>Clean Architecture</em> has made me more certain that the value lies not in the number of concepts invented. Good architecture does not promise that business will cease to be complex. It lets us say, when a new change arrives, where it belongs, what it depends on, whom it affects, and where it should stop.</p><p>Now that AI participates in design and implementation, those boundaries cannot remain private experience held by a few senior engineers. They must exist at once as repository knowledge, executable Skill steps, and verification evidence at handoff—so that faster code generation does not erase the intended direction of change.</p><p>That is what “clean” means to me now: not an absence of change, but change that no longer spills everywhere.</p><section class="references" id="references"><h2 data-no-number="true">References and further reading</h2><ol><li id="ref-1">Robert C. Martin. <a href="https://www.informit.com/store/clean-architecture-a-craftsmans-guide-to-software-structure-9780134494319"><em>Clean Architecture: A Craftsman’s Guide to Software Structure and Design</em></a>. Pearson / Addison-Wesley, 2017.</li><li id="ref-2">Robert C. Martin. “<a href="https://www.informit.com/articles/article.aspx?p=2832399">The Clean Architecture Dependency Rule</a>.” <em>InformIT</em>, 2017.</li><li id="ref-3">HiForce. “<a href="https://github.com/hiforce/lattice">Lattice Framework</a>.” GitHub. At this essay’s latest update, the main-branch <code>pom.xml</code> declared version <code>1.0.21</code>.</li><li id="ref-4">HiForce. “<a href="https://github.com/hiforce/lattice-sample">Lattice Sample</a>.” GitHub. Includes Quick Start, Use Case, and multi-capability composition samples.</li><li id="ref-5">HiForce. “<a href="https://github.com/hiforce/lattice-clean-arch-practice-sample">Lattice Clean Architecture Practice Sample</a>.” GitHub. Demonstrates project organization across entities, use cases, interface adapters, and business plugins.</li></ol></section>]]>
    </content>
    <id>https://ryu.xin/posts/lattice-clean-architecture-practice/</id>
    <link href="https://ryu.xin/posts/lattice-clean-architecture-practice/"/>
    <published>2026-03-15T16:00:00.000Z</published>
    <summary>How Lattice contains business change at scale, and how its architecture principles became an executable Skill for AI-assisted development.</summary>
    <title>Accelerating Business Innovation: Lattice and Clean Architecture in Practice</title>
    <updated>2026-08-01T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Rocky Yu</name>
    </author>
    <category term="Organizations" scheme="https://ryu.xin/categories/organizations/"/>
    <category term="Software Engineering" scheme="https://ryu.xin/tags/Software-Engineering/"/>
    <category term="Career" scheme="https://ryu.xin/tags/Career/"/>
    <category term="Leadership" scheme="https://ryu.xin/tags/Leadership/"/>
    <content>
      <![CDATA[<header class="abstract"><h2 data-no-number="true">A note on this edition</h2><p>I first wrote this essay in April 2018, while leading an engineering team at Alibaba and conducting annual performance conversations. Several colleagues asked about promotion, technical influence, and what should come next in their careers. Beneath those questions was a harder one: how can an engineer tell whether a year has amounted to real growth?</p><p>Eight years is enough time for a once-fashionable stack to become a historical footnote—and for confident career advice to develop compatibility issues of its own. The career stages, Java reading list, and organizational assumptions in this essay plainly belong to 2018. In revisiting it, I have preserved that point of view while making the prose more natural, clarifying the structure, and removing dead links. This is not an attempt to make the past sound as though it knew the future.</p><p>Now that AI is becoming part of everyday software development, the same question deserves a new answer. Once this older essay has been properly settled, I plan to return to it with what I know now.</p></header><p class="thesis">A promotion is an organizational outcome, not the sole measure of professional growth. What is worth measuring over time is the range of problems you can take on, the people who do better work because of you, the team outcomes you help make possible, and the judgment you develop under complexity and uncertainty.</p><p class="part-label">Part I · We need a measure beyond promotion</p><h2 id="What-people-were-really-asking-in-a-performance-conversation"><span class="section-no">01</span><a href="#What-people-were-really-asking-in-a-performance-conversation" class="headerlink" title="What people were really asking in a performance conversation"></a>What people were really asking in a performance conversation</h2><p class="lead dropcap">The musical <em>Rent</em> asks how a year in a human life should be measured: in time, in journeys, or in moments that matter. At work, we tend to offer a more practical answer—salary, level, and promotion.</p><p>During performance conversations in 2018, several people on my team raised questions about career development. One wanted to deepen his technical expertise. Another was considering management. Others wanted their technical decisions to carry more influence across the team.</p><p>Their aspirations were different, but the anxiety underneath them was similar: how do I know I am progressing? If I am not promoted this year, was the year unsuccessful?</p><p>I responded with questions of my own:</p><ul><li>What exactly do you want to become better at, and what should you be able to do a year from now that you cannot do today?</li><li>If you want technical influence, where should that influence come from? Does it require a title first?</li><li>If you are not promoted but learn to solve problems that used to defeat you, does that count as growth?</li><li>If you are promoted but continue repeating the same familiar work, does that count as success?</li></ul><p>The room became quiet. The problem was not a lack of ambition. It was that few people had built a way to observe growth other than promotion.</p><h2 id="Promotion-is-a-lagging-signal-not-a-daily-yardstick"><span class="section-no">02</span><a href="#Promotion-is-a-lagging-signal-not-a-daily-yardstick" class="headerlink" title="Promotion is a lagging signal, not a daily yardstick"></a>Promotion is a lagging signal, not a daily yardstick</h2><p>Promotion matters. It brings recognition, compensation, responsibility, and opportunity. But it is also the outcome of many conditions: available roles, team structure, business timing, and whether a person’s capability has remained visible long enough. It arrives late, and it is never entirely under individual control.</p><p>If our sense of accomplishment depends on that single outcome, professional life becomes a long wait. The work in between seems not to count; only the day of the announcement feels real.</p><p>A more durable approach is to treat promotion as a lagging signal. It can confirm a period of growth, but it does not create that growth. The daily evidence lies elsewhere: clarifying an ambiguous requirement, handling a production incident independently, designing something the team can understand and maintain, or recognizing that your own plan was wrong and leading the correction.</p><div class="callout"><p><strong>A more honest record of accomplishment.</strong> Did I expand the range of problems I can solve? Did I leave behind reusable code, knowledge, or methods? Did I help someone else make a better decision? Did I take responsibility for an outcome rather than merely finish an assigned task?</p></div><p class="part-label">Part II · Become a professional others can rely on</p><h2 id="In-the-first-three-to-five-years-growth-is-loud"><span class="section-no">03</span><a href="#In-the-first-three-to-five-years-growth-is-loud" class="headerlink" title="In the first three to five years, growth is loud"></a>In the first three to five years, growth is loud</h2><p>Early in a Java developer’s career, progress is easy to hear. Yesterday’s baffling stack trace becomes today’s obvious clue. You deploy to production for the first time, investigate a slow database query, and discover that code that runs is not necessarily good code.</p><p>The transition from graduate to trusted professional usually takes several years of study and real project experience. In 2018, I called the first three to five years Phase I. Its purpose was not the quickest possible title, but a sufficiently strong foundation.</p><div class="table-wrap"><table><caption>Four layers of the early-career foundation</caption><thead><tr><th>Layer</th><th>The question it answers</th><th>Typical 2018 entry points</th></tr></thead><tbody><tr><td>Language and code</td><td>Can you write correct, clear, changeable software?</td><td>Java, Effective Java, refactoring, code quality</td></tr><tr><td>Frameworks and data</td><td>Do you understand how the application actually runs?</td><td>Spring, Hibernate, databases, caches, NoSQL, logging</td></tr><tr><td>Design and algorithms</td><td>Can you see structure beyond the local implementation?</td><td>Patterns, object-oriented analysis, UML, algorithms</td></tr><tr><td>Engineering habits</td><td>Can you deliver repeatedly rather than occasionally?</td><td>Debugging, testing, review, documentation, retrospectives</td></tr></tbody></table></div><p>The list clearly belongs to 2018, when the SSH stack remained common and we moved between official documentation, technical blogs, and Stack Overflow. The deeper point is less dependent on a particular technology: a craft has to be practiced until it works under real conditions, not only in tutorials.</p><h2 id="The-first-resource-you-learn-to-manage-is-yourself"><span class="section-no">04</span><a href="#The-first-resource-you-learn-to-manage-is-yourself" class="headerlink" title="The first resource you learn to manage is yourself"></a>The first resource you learn to manage is yourself</h2><p>At this stage, differences in early opportunity are often less permanent than they appear. A gifted engineer might take on senior work in three years; another may need five or six. Across a long career, that gap can often be narrowed through deliberate learning, difficult projects, and honest reflection.</p><p>What matters is not who memorized a framework first, but who learned to manage their own work reliably: keeping commitments, studying when the problem is unfamiliar, retaining lessons after a project, and refusing to repeat the same mistake indefinitely.</p><p>Some people follow strict study plans. Some are pulled early into painful but important projects. Others advance quietly by making every delivery more dependable than the last. Their routes differ, but they do not wait passively for the organization to manufacture their capability.</p><figure class="article-figure"><img src="/assets/articles/measuring-a-programmers-year/figure-01-building-the-craft.webp?v=bb54fd7424a36396" width="1672" height="941" loading="lazy" alt="A young engineer assembles software modules at a quiet workbench as scattered pieces become a stable structure surrounded by books, tools, and testing instruments"><figcaption><p><strong>Figure 1 · Practice until the craft becomes dependable.</strong> Early growth is a repeated loop of learning, attempting, failing, correcting, and turning an occasional success into reliable delivery.</p></figcaption></figure><div class="pullquote"><p>Early in a career, leverage rarely comes from managing more people. It comes from learning to manage your own attention, time, commitments, and growth.</p></div><p class="part-label">Part III · From personal output to team outcomes</p><h2 id="Ten-years-of-experience-does-not-compound-by-itself"><span class="section-no">05</span><a href="#Ten-years-of-experience-does-not-compound-by-itself" class="headerlink" title="Ten years of experience does not compound by itself"></a>Ten years of experience does not compound by itself</h2><p>Between five and ten years after graduation, the anxiety often changes shape. Technology continues to move, younger colleagues arrive, and fluency alone no longer feels sufficient. What looks like anxiety about age is often a change in what organizations expect from experienced professionals.</p><p>A newcomer first has to prove that they can complete work. An experienced engineer faces different questions: Can you define the work? Can you make tradeoffs with incomplete information? Can you notice when the team is solving the wrong problem? When the result is poor, can you take responsibility and organize a correction?</p><p>Time gives us more experience, but it does not automatically turn experience into judgment. Ten years spent confronting different problems can look much like one familiar year repeated ten times on a résumé, yet produce a very different kind of capability.</p><h2 id="Influence-does-not-begin-with-a-title"><span class="section-no">06</span><a href="#Influence-does-not-begin-with-a-title" class="headerlink" title="Influence does not begin with a title"></a>Influence does not begin with a title</h2><p>Someone on my team once said he wanted to make technical decisions and influence more people. I asked whether he had to become an architect or technical lead before influence was possible.</p><p>A position grants authority, but not credibility. Durable technical influence grows from simpler evidence: seeing a risk early, explaining complexity clearly, proposing designs that survive contact with production, and correcting your own mistakes when they do not. People listen because your earlier judgments have earned their trust.</p><p>Influence is also more than persuading others to accept your design. Its mature form helps a group make better shared decisions: writing down hidden knowledge, explaining principles, making disagreement safe, and helping younger engineers understand why—not only how.</p><h2 id="A-technical-leader-has-to-see-beyond-the-code"><span class="section-no">07</span><a href="#A-technical-leader-has-to-see-beyond-the-code" class="headerlink" title="A technical leader has to see beyond the code"></a>A technical leader has to see beyond the code</h2><p>In the original essay, I called the second-stage professional a “team contributor.” This might be a people manager, architect, or senior individual contributor. The common shift is that value no longer equals the amount of code personally produced. It includes making it easier for a group to achieve the right outcome.</p><div class="table-wrap"><table><caption>From personal contribution to a team outcome</caption><thead><tr><th>Direction</th><th>Question</th><th>Capability</th></tr></thead><tbody><tr><td>Business and market</td><td>How is the domain changing, and what constrains it?</td><td>Insight, tradeoffs, planning</td></tr><tr><td>Customer and user</td><td>Who uses the result, and what hurts?</td><td>Discovery, empathy, problem framing</td></tr><tr><td>Team and organization</td><td>How can different roles understand and finish the same work?</td><td>Communication, coordination, resourcing, development</td></tr><tr><td>Technology and delivery</td><td>How does intent become an evolvable running system?</td><td>Modeling, architecture, project management, quality</td></tr></tbody></table></div><p>You may need to explain an uncertain direction to a manager or investor, secure people and funding, and translate market change into a model that product and engineering can share. After business design come architecture, interfaces, implementation, testing, and release. Anything left unclear at one layer returns later as rework, conflict, or incidents.</p><p>Managers should understand whether a team is creating value worth the organization’s investment. Yet people are not line items, and value does not exist only inside a quarter. The difficult responsibility is to protect short-term outcomes, long-term capability, and team health at once.</p><figure class="article-figure"><img src="/assets/articles/measuring-a-programmers-year/figure-02-expanding-responsibility.webp?v=e50bb5276b8d1650" width="1672" height="941" loading="lazy" alt="An experienced engineer stands at a shared design table connecting customer settings, a collaborative team space, and a city-like software architecture"><figcaption><p><strong>Figure 2 · As responsibility expands, the center of the work moves.</strong> Contributing to team outcomes means connecting customer, organization, and system—not merely accepting a larger pile of tasks.</p></figcaption></figure><p class="part-label">Part IV · Capabilities you cannot cram for</p><h2 id="Books-are-maps-practice-gives-you-a-feel-for-the-terrain"><span class="section-no">08</span><a href="#Books-are-maps-practice-gives-you-a-feel-for-the-terrain" class="headerlink" title="Books are maps; practice gives you a feel for the terrain"></a>Books are maps; practice gives you a feel for the terrain</h2><div class="note"><p><strong>A note from 2026.</strong> The original article contained a very long reading list. It was sincere advice, but it also revealed a familiar engineering instinct: faced with a complicated problem, we go looking for a complete syllabus, as though capability might install itself once we finish the books in order.</p><p>The problem was not the books. Many of them remain worth reading. What needs correcting is the tidy sequence in which I once arranged professional growth: learn Java, then frameworks, then design, architecture, and management—as though anyone who reached the end of the list would naturally emerge as a mature technical leader. Real careers are rarely so orderly. More often, a project hands us the problem first. Only after it hurts do we go looking for the book we actually need.</p></div><p>To preserve the 2018 essay as a record of its time, here is the full reading list I included then. The old retailer links, internal images, and expired web pages have been omitted.</p><h3 id="The-original-2018-reading-list"><a href="#The-original-2018-reading-list" class="headerlink" title="The original 2018 reading list"></a>The original 2018 reading list</h3><ol><li><strong>Java and programming fundamentals:</strong> Bruce Eckel, <em>Thinking in Java</em>; Joshua Bloch, <em>Effective Java</em>.</li><li><strong>Code quality:</strong> Martin Fowler, <em>Refactoring: Improving the Design of Existing Code</em>; Steve McConnell, <em>Code Complete</em>; Jon Bentley, <em>Programming Pearls</em>.</li><li><strong>Application frameworks and data:</strong> <em>Spring in Action</em>, <em>Spring Boot in Action</em>, and <em>Java Persistence with Hibernate</em>; along with database tuning, caching, NoSQL databases, logging systems, and related topics.</li><li><strong>Systems design and algorithms:</strong> <em>Systems Analysis and Design Methods</em>, <em>Design Patterns</em>, <em>Requirements Analysis and System Design</em>, <em>Object-Oriented Analysis and Design with Applications</em>, <em>The Unified Modeling Language User Guide</em>, and <em>Introduction to Algorithms</em>.</li><li><strong>Problem discovery and technical leadership:</strong> Gerald M. Weinberg, <em>The Secrets of Consulting</em>, <em>Exploring Requirements</em>, <em>An Introduction to General Systems Thinking</em>, and <em>Becoming a Technical Leader</em>.</li><li><strong>Business, communication, and influence:</strong> frameworks such as TOGAF, NGOSS, and ITIL; Barbara Minto, <em>The Pyramid Principle</em>; Drew Fudenberg and Jean Tirole, <em>Game Theory</em>; Robert B. Cialdini, <em>Influence</em>.</li><li><strong>Domain modeling and architecture:</strong> Eric Evans, <em>Domain-Driven Design</em>; Vaughn Vernon, <em>Implementing Domain-Driven Design</em>; Martin Fowler, <em>Patterns of Enterprise Application Architecture</em>; George Fairbanks, <em>Just Enough Software Architecture</em>.</li><li><strong>Projects, teams, and the human side of software:</strong> <em>A Guide to the Project Management Body of Knowledge (PMBOK Guide)</em> and <em>Agile Software Development</em>; Frederick P. Brooks Jr., <em>The Mythical Man-Month</em>; Gerald M. Weinberg, <em>The Psychology of Computer Programming</em>.</li></ol><p>Books matter. Weinberg’s work on consulting, requirements, and systems helps us understand problems before rushing to solve them. <em>The Pyramid Principle</em> and <em>Influence</em> sharpen communication. Domain-driven design and architecture books help a team turn business ideas into structure. <em>The Mythical Man-Month</em>, agile literature, and <em>The Psychology of Computer Programming</em> remind us that software has never been only about code.</p><p>Reprinting this list is not my way of assigning eight sets of homework to younger engineers. A better approach is to start with a problem you genuinely own. If the code has become painful to change, return to <em>Refactoring</em>. If the team cannot agree on the meaning of its core business concepts, study domain modeling. If projects keep slipping, reread <em>The Mythical Man-Month</em>. When you read with a live problem in mind, ideas are less likely to remain polished vocabulary.</p><p>Books can give us concepts. Real capability is built in practice: trying to persuade someone and discovering a hole in the argument; building an elegant architecture that the team cannot maintain six months later; assuming customers want more features when what they really want is one fewer opportunity to make a mistake. Reading gives us language. Practice teaches us when that language holds and when it does not. Return to the same book later, and a sentence you once skimmed may suddenly look like a contour marker that only makes sense after you have crossed that piece of terrain yourself.</p><h2 id="Health-setbacks-and-the-experiences-omitted-from-success-stories"><span class="section-no">09</span><a href="#Health-setbacks-and-the-experiences-omitted-from-success-stories" class="headerlink" title="Health, setbacks, and the experiences omitted from success stories"></a>Health, setbacks, and the experiences omitted from success stories</h2><p>Career plans easily omit the person who has to carry them out. By the mid-thirties, the body offers feedback more directly than a performance system. Sleep loss, inactivity, and sustained pressure do not pause because the project matters.</p><p>I used to promise myself I would exercise after the busy period. There was always another busy period. The busier the work becomes, the more deliberately we have to preserve recovery, because clarity, patience, and emotional stability are part of judgment.</p><p>A decade at work also leaves us with experiences that rarely make it into polished success stories: team conflict, technical disputes, platform-versus-business tradeoffs, low morale, personal lows, and a decision you defended fiercely before evidence proved it wrong.</p><p>Experience creates value only when reviewed. What happened? Which signal did I ignore? What would I notice sooner next time? Through that work, failure slowly becomes judgment. When others need direction, they do not expect you never to have struggled. They expect you to have something more useful than panic when the struggle returns.</p><h2 id="Planning-ahead-should-not-mean-borrowing-anxiety-from-the-future"><span class="section-no">10</span><a href="#Planning-ahead-should-not-mean-borrowing-anxiety-from-the-future" class="headerlink" title="Planning ahead should not mean borrowing anxiety from the future"></a>Planning ahead should not mean borrowing anxiety from the future</h2><p>Some colleagues began practicing the responsibilities they expected at year ten by year seven. They sought difficult projects, learned to lead and communicate, and some even tried entrepreneurship to understand resources and accountability firsthand.</p><p>By year ten, those “advanced” capabilities had already been practiced for three years. The difference was not a few more books, but several more complete loops of judgment, action, and feedback. That gap is difficult to close in the months before a promotion review.</p><p>Preparation should not turn a career into a suffocating countdown. Its purpose is to reserve space for growth that matters before it becomes urgent: learning to listen before managing, understanding customers before owning a business outcome, and caring for health before the body forces the issue.</p><p class="part-label">Part V · Return to the measure of a year</p><h2 id="If-promotion-is-not-the-measure-what-did-the-year-leave-behind"><span class="section-no">11</span><a href="#If-promotion-is-not-the-measure-what-did-the-year-leave-behind" class="headerlink" title="If promotion is not the measure, what did the year leave behind?"></a>If promotion is not the measure, what did the year leave behind?</h2><p>So how should a programmer measure a year?</p><p>My 2018 answer did not deny the practical meaning of level and compensation. They shape opportunity and life. But if the year is reduced to one performance outcome, much of what matters disappears.</p><p>At the end of the year, it may be worth taking one quiet afternoon to ask:</p><ul><li><strong>Problems:</strong> Can I handle problems that are more complex and more real than a year ago?</li><li><strong>Craft:</strong> Is my work more dependable, more maintainable, and built to last?</li><li><strong>Influence:</strong> Did anyone do better work because of my explanation, support, or example?</li><li><strong>Judgment:</strong> Did a failure change a later decision, or merely become another story?</li><li><strong>Life:</strong> Can I continue with health and clarity, without burning myself out?</li></ul><p>These questions do not produce a universal score, and they may not all fit into a promotion case. They make growth observable before a distant verdict arrives. When you can see where you are growing and what is still missing, feedback from managers and peers becomes a signal for calibration rather than a final judgment of personal worth.</p><div class="callout"><p><strong>A note from 2026.</strong> The software world has changed too much for me to draw this career path in exactly the same way today. AI in particular has altered code production, learning, and teamwork. For now, this answer can remain in its own time. A new answer deserves its own essay.</p></div><p>A year cannot be measured completely by a table. It exists in the difficulties you can finally carry, the detour you help someone avoid, the reliable delivery, the honest correction, and the effort you sustain without exhausting yourself.</p><p>Promotion records part of that. The rest is ours to notice.</p><section class="references" id="references"><h2 data-no-number="true">Edition note</h2><ol><li id="ref-1">Rocky Yu, “Thoughts and Suggestions on Career Planning for Technical Professionals,” first published April 30, 2018; this edition was restructured, rewritten, and reillustrated in July 2026.</li></ol></section>]]>
    </content>
    <id>https://ryu.xin/posts/measuring-a-programmers-year/</id>
    <link href="https://ryu.xin/posts/measuring-a-programmers-year/"/>
    <published>2018-04-30T22:49:20.000Z</published>
    <summary>An essay first written in April 2018 about measuring an engineer’s growth beyond promotion—through craft, influence, judgment, responsibility, and sustained learning.</summary>
    <title>How Should a Programmer Measure a Year?</title>
    <updated>2026-07-31T16:00:00.000Z</updated>
  </entry>
</feed>
