<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Software Design on Peter Fulop</title><link>https://peterfulop.tech/tags/software-design/</link><description>Recent content in Software Design on Peter Fulop</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>Peter Fulop</copyright><lastBuildDate>Wed, 19 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://peterfulop.tech/tags/software-design/index.xml" rel="self" type="application/rss+xml"/><item><title>When code becomes cheap, design has to become easier to review</title><link>https://peterfulop.tech/p/when-code-becomes-cheap-design-has-to-become-easier-to-review/</link><pubDate>Wed, 19 Aug 2026 00:00:00 +0000</pubDate><guid>https://peterfulop.tech/p/when-code-becomes-cheap-design-has-to-become-easier-to-review/</guid><description>&lt;img src="https://peterfulop.tech/p/when-code-becomes-cheap-design-has-to-become-easier-to-review/when-code-becomes-cheap-design-has-to-become-easier-to-review.png" alt="Featured image of post When code becomes cheap, design has to become easier to review" /&gt;&lt;p&gt;In my previous post, &lt;a class="link" href="https://peterfulop.tech/p/software-solutions-do-not-start-with-code/" target="_blank" rel="noopener"
&gt;Software solutions do not start with code&lt;/a&gt;, I wrote about the work that comes before implementation: understanding the real problem, finding the constraints, and keeping a useful mental model of the solution alive.&lt;/p&gt;
&lt;p&gt;I have been thinking about what follows from that when code is much cheaper to produce.&lt;/p&gt;
&lt;p&gt;Listening to &lt;a class="link" href="https://newsletter.pragmaticengineer.com" target="_blank" rel="noopener"
&gt;Gergely Orosz&lt;/a&gt;&amp;rsquo;s conversation with &lt;a class="link" href="https://x.com/mipsytipsy" target="_blank" rel="noopener"
&gt;Charity Majors&lt;/a&gt;, I kept returning to one idea: as AI makes code cheaper to produce, &lt;strong&gt;code may become a less useful primary artifact for review.&lt;/strong&gt; Majors points toward lessons from operations and QA, where confidence comes from evidence that a system behaves correctly, not only from reading its implementation.&lt;/p&gt;
&lt;p&gt;That made me think about the work that needs to happen before a large diff appears.&lt;/p&gt;
&lt;p&gt;An agent can turn a short conversation into a large pull request. That is useful, but it changes where the bottleneck sits. The team may be able to generate more implementation than it can properly understand, review, and support.&lt;/p&gt;
&lt;p&gt;Code still matters. It is where the system becomes real. But &lt;strong&gt;a large diff is not always the best first artifact for a team to review.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="the-review-bottleneck-moves-upstream"&gt;The review bottleneck moves upstream
&lt;/h2&gt;&lt;p&gt;For a long time, writing code was expensive enough that the code itself carried much of the design conversation. A careful engineer spent days or weeks producing a change. By the time it appeared in a pull request, many of the decisions had already been made along the way.&lt;/p&gt;
&lt;p&gt;That was never ideal. Important assumptions could still stay hidden until late in the process. But the pace gave people time to discover them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI removes some of that delay.&lt;/strong&gt; It can generate a reasonable first implementation very quickly, sometimes before the engineer has fully tested their own understanding of the problem. The result may compile, look familiar, and include tests. It may still solve the wrong problem, preserve the wrong assumption, or add complexity that the next person will have to untangle.&lt;/p&gt;
&lt;p&gt;This is why I do not think the answer is to ask reviewers to read faster or to approve more code. The answer is to make the decisions behind the code easier to see earlier.&lt;/p&gt;
&lt;h2 id="a-shared-model-gives-the-team-something-better-to-discuss"&gt;A shared model gives the team something better to discuss
&lt;/h2&gt;&lt;p&gt;Before starting a meaningful change, I increasingly want a small, reviewable description of the solution. Not a heavyweight document and not an architecture diagram for its own sake. The useful form depends on the work.&lt;/p&gt;
&lt;p&gt;For one change, it might be a short note that answers a few questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What user or business problem are we solving?&lt;/li&gt;
&lt;li&gt;What must stay true when the change is complete?&lt;/li&gt;
&lt;li&gt;Which existing systems, contracts, or data are affected?&lt;/li&gt;
&lt;li&gt;Where are the risks or unknowns?&lt;/li&gt;
&lt;li&gt;What would make us change direction?&lt;/li&gt;
&lt;li&gt;How will we know, in production, that the change behaves as expected?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For another change, the right artifact might be a sequence diagram, an API contract, a migration plan, or a short prototype. The point is not the format. The point is that the people involved can look at the same model, challenge it, and improve it before an agent produces hundreds of lines around it.&lt;/p&gt;
&lt;p&gt;The same principle applies when directing an agent: the useful context is more than a prompt. It is the problem, constraints, relevant history, and checks the agent needs to work within. I explored that in &lt;a class="link" href="https://peterfulop.tech/p/in-agent-systems-context-matters-more-than-the-prompt/" target="_blank" rel="noopener"
&gt;In agent systems, context matters more than the prompt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This makes the questions in review better. Instead of only asking whether a particular class, condition, or query looks right, we can ask whether the proposed change protects an important invariant. We can ask whether a migration is reversible. We can ask whether the behaviour would still make sense when a dependency fails or a customer has unusual data.&lt;/p&gt;
&lt;p&gt;Those are the questions that shape the system. They are also much easier for a team to answer together when the intent is explicit.&lt;/p&gt;
&lt;h3 id="turning-assumptions-into-validation-points"&gt;Turning assumptions into validation points
&lt;/h3&gt;&lt;p&gt;My team took on a cross-team task: building a pipeline whose input came from the RAW layer of a layered data warehouse (RAW, CLEAN, CORE, and MART). Its output had to land in the CORE layer, where another team would use it to build further MART tables.&lt;/p&gt;
&lt;p&gt;Before we wrote code, we had to clarify many questions. That work may have taken more effort than the implementation itself.&lt;/p&gt;
&lt;p&gt;We had to work out which business process the pipeline supported, and what the source data actually represented: how the data was created, and what separated a valid record from an erroneous entry. Then how the output would be used, which systems it would affect, and which data contracts we had to honour.&lt;/p&gt;
&lt;p&gt;The pipeline implemented a data-science method. It communicated with an external LLM and an external predictive model. From the rest of the system&amp;rsquo;s perspective, it appeared as a black box, but its nodes and internal milestones still had to meet data-validation requirements.&lt;/p&gt;
&lt;p&gt;This was a greenfield development, so we could not predict its performance or scalability in advance. Before implementation, we agreed with stakeholders on the load it had to carry: 3 million input records per month, with peak days rising to between 200,000 and 300,000. The peak mattered more than the total. It is two to three times the daily average, and it was the number that shaped the design. From there we defined within the team what good performance meant, and what we would treat as unacceptable.&lt;/p&gt;
&lt;p&gt;Capturing these conditions gave us stable validation points once the code had been generated.&lt;/p&gt;
&lt;h2 id="code-review-still-matters-but-it-cannot-carry-everything"&gt;Code review still matters, but it cannot carry everything
&lt;/h2&gt;&lt;p&gt;I do not see this as a replacement for code review. The implementation can still introduce bugs, miss edge cases, or fail to follow the team&amp;rsquo;s conventions. Tests, static checks, and a careful review remain useful ways to catch those problems.&lt;/p&gt;
&lt;p&gt;But &lt;strong&gt;code review is already asked to do too many jobs.&lt;/strong&gt; It is expected to validate correctness, teach less experienced engineers, enforce conventions, catch security issues, confirm operational readiness, and make sure the change solves the original problem. More AI-generated code will make that pressure stronger.&lt;/p&gt;
&lt;p&gt;Some of those concerns are better handled by shared guidelines and automated checks. Others need a conversation before the implementation exists. The reviewer should not have to reconstruct the entire product and architecture decision from a diff.&lt;/p&gt;
&lt;p&gt;This is how I now understand the earlier idea that &lt;a class="link" href="https://peterfulop.tech/p/critical-thinking-ai-assisted-development/" target="_blank" rel="noopener"
&gt;judgment is the job&lt;/a&gt;: judgment should show up in the design, the checks, and the evidence behind a change, not only in a final read-through of the diff.&lt;/p&gt;
&lt;p&gt;This is also where a good engineer can help the whole team, not only the change at hand. When a recurring decision becomes visible in a design note, a test, an agent instruction, or a team convention, the next engineer starts with better context. The next review starts from a stronger position too.&lt;/p&gt;
&lt;h2 id="production-belongs-in-the-design-conversation"&gt;Production belongs in the design conversation
&lt;/h2&gt;&lt;p&gt;There is one question I want to see more often before implementation: &lt;strong&gt;how will we know that this works after release?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The answer is not always a dashboard. Sometimes it is an acceptance test, a log record, or a clear rollback condition. The important part is deciding it while we can still influence the design.&lt;/p&gt;
&lt;p&gt;This matters more with AI-assisted work. &lt;strong&gt;The faster we can produce changes, the easier it becomes to create more behaviour than we can hold in our heads.&lt;/strong&gt; Production feedback gives us a way to test the model we had when we wrote the change against the system customers actually use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I find this part of engineering increasingly interesting.&lt;/strong&gt; It connects the early work of understanding the problem with the later work of owning the result. It also gives AI a useful place in the process: it can help explore options and implement a chosen direction, while the team stays responsible for the model, the evidence, and the trade-offs.&lt;/p&gt;
&lt;p&gt;I am still working out what the smallest useful version of this practice looks like. &lt;strong&gt;I do not want every change to require a design ceremony.&lt;/strong&gt; I do want us to be more deliberate when the decision is expensive, difficult to reverse, or likely to affect people outside the team.&lt;/p&gt;
&lt;p&gt;When implementation becomes cheaper, clear design becomes more valuable. It gives us something meaningful to review before the code arrives.&lt;/p&gt;</description></item></channel></rss>