<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Omry Yadan Blog</title>
        <link>https://yadan.net/writing/</link>
        <description>Omry Yadan Blog</description>
        <lastBuildDate>Mon, 27 Jul 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[AI Doesn't Get Annoyed]]></title>
            <link>https://yadan.net/writing/ai-doesnt-get-annoyed/</link>
            <guid>https://yadan.net/writing/ai-doesnt-get-annoyed/</guid>
            <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Compilers exist because humans got tired of writing machine code. What shared concepts will remain implicit when AI can generate the implementation forever?]]></description>
            <content:encoded><![CDATA[
<p><em>Compilers exist because humans got tired of writing machine code. What shared
concepts will remain implicit when AI can generate the implementation forever?</em></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-next-compiler">The next compiler<a href="https://yadan.net/writing/ai-doesnt-get-annoyed/#the-next-compiler" class="hash-link" aria-label="Direct link to The next compiler" title="Direct link to The next compiler" translate="no">​</a></h2>
<p>Linus Torvalds made a comparison that I found useful. He objected to describing
AI-assisted code as "written by AI." Compilers already generate all the machine
code, but we do not ordinarily say that the compiler wrote the program. In his
analogy, AI is another tool that changes how the programmer creates software,
not necessarily who created it. <a href="https://lwn.net/Articles/1073761/" target="_blank" rel="noopener noreferrer" class="">His larger point was that the fundamentals
still matter even as the tools change.</a></p>
<p>Compilers did not eliminate creativity in programming. They eliminated most of
the need to be creative in machine code. Creativity moved upward, into
algorithms, data structures, languages, interfaces, and systems.</p>
<p>AI may do something similar. The analogy is operational, not mechanical: AI is
not a deterministic translator like a compiler, but it similarly lowers the
cost of turning an intention expressed at one level into an implementation at
another. It can make one person capable of acting across a much larger surface
area.</p>
<p>But there is an important difference.</p>
<p>A compiler generates low-level instructions only after the program has been
expressed in a higher-level formal language. The knowledge has already moved
upward into a durable representation. AI can often generate a lower-level
artifact directly from an informal request, without requiring a stable
language, model, or interface to exist first. It can remove the low-level work
while leaving the knowledge scattered across prompts, generated files, tests,
conventions, and human memory.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="annoyance-carries-information">Annoyance carries information<a href="https://yadan.net/writing/ai-doesnt-get-annoyed/#annoyance-carries-information" class="hash-link" aria-label="Direct link to Annoyance carries information" title="Direct link to Annoyance carries information" translate="no">​</a></h2>
<p>The best engineers are lazy in a particular way. They will spend a week
eliminating a task that costs them five minutes a day. The immediate economics
may be terrible. But the refusal to tolerate repeated friction is often how
better tools are born.</p>
<p>Sometimes that instinct leads nowhere. But sometimes annoyance is a
wrong-abstraction detector.</p>
<p>It can tell us that we are repeatedly restating durable information. That
several decisions from different layers have been collapsed into one operation.
That the same idea appears in many slightly different forms. That a component
is doing work which logically belongs somewhere else.</p>
<p>In those cases, the irritation is not just about effort. It is evidence that
the system lacks a useful concept.</p>
<p>AI changes this feedback loop. If a command is difficult to construct, an AI
can construct it. If a configuration file is tedious to write, an AI can write
it. If the same integration must be implemented differently in every system,
an AI can keep generating the variations.</p>
<p>The pain disappears, or at least moves out of sight. The complexity does not.</p>
<p>This is not an argument that AI cannot invent abstractions. It plainly can
recognize patterns, propose interfaces, and help design systems. The question
is what it is being asked to optimize. When AI is given a ticket-sized or
case-specific objective, another working implementation is usually a successful
outcome. The fact that humans would hate maintaining fifty such solutions may
never enter the task.</p>
<p>AI can identify maintenance burden, but in most current workflows that
accumulated cost sits outside the task it has been given. It does not spend six
months being interrupted by the fifth variation of the same idea. That
accumulated pressure usually enters through a human who notices the repetition
and decides that it deserves a shared model.</p>
<p>Software history contains many versions of this move. Build systems made
repeated command sequences explicit. Package managers made dependency graphs
explicit. Configuration management made machine state explicit. In each case,
the abstraction did more than save typing: it gave part of the system a durable
model.</p>
<p>The danger is not simply that AI will produce more code. It is that locally
successful implementations can multiply without forcing the shared concept
behind them to become explicit.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="long-command-lines-are-a-symptom">Long command lines are a symptom<a href="https://yadan.net/writing/ai-doesnt-get-annoyed/#long-command-lines-are-a-symptom" class="hash-link" aria-label="Direct link to Long command lines are a symptom" title="Direct link to Long command lines are a symptom" translate="no">​</a></h2>
<p>One place I have repeatedly felt this problem is in long command lines. A long
command often forces me to reconstruct a model that should already exist
elsewhere.</p>
<p>It may combine the identity of an application with its configuration, storage,
networking, security, environment, execution mode, and deployment details.
These are not all properties of the command. They describe different parts of a
durable system, but the command line flattens them into a sequence of strings to
retain, copy, or regenerate.</p>
<p>The problem is not character count. The problem is that structure has been
turned into an invocation.</p>
<p>Repeated, durable structure belongs in a model. The command line should express
an action, a selection, or a delta.</p>
<p>I had encountered this pattern long before generative AI. It was part of the
motivation behind <a href="https://hydra.cc/docs/intro/" target="_blank" rel="noopener noreferrer" class="">Hydra</a>, a configuration
framework I created for Python applications. Hydra moves durable configuration
into a hierarchical, composable model, while the command line selects
alternatives or states what is different. The model can then be inspected,
validated, saved, and shared instead of being reconstructed for every run.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="following-the-annoyance">Following the annoyance<a href="https://yadan.net/writing/ai-doesnt-get-annoyed/#following-the-annoyance" class="hash-link" aria-label="Direct link to Following the annoyance" title="Direct link to Following the annoyance" translate="no">​</a></h2>
<p>More recently, while developing a service, I wanted a user to be able to stage
it locally, configure and test it, and then install it permanently.</p>
<p>The apparent container workflow involved a bespoke Dockerfile and a long
command combining details from several layers. I could not be bothered to keep
either the command or its implicit model in my head. I hated it.</p>
<p>I was not a Docker expert, but I had used it enough to understand the ordinary
build-and-run workflow and to know what I disliked about it. An experienced
Docker user might have reached for Docker Compose or another established tool.
But my objection was not simply that I did not know the right command. The
lifecycle I wanted - stage an application, configure it, test it, and then
install it permanently - was being expressed through details from several
different layers.</p>
<p>My first solution was pragmatic. I embedded the staging and installation logic
directly into the service. It worked, but it required a substantial amount of
single-purpose code.</p>
<p>The awkwardness became obvious when I tried to document the installation
process. The user first had to install the Python service into a Python
environment. They would then use that service to create its own Docker
deployment, configure the deployed copy, test it there, and finally install it
as a persistent service. The service was being used to construct and install
another form of itself.</p>
<p>An AI given the ticket-sized task of making the service installable might
reasonably have produced the same workflow, run the tests, and declared success.
But staging and installation were not properties of this particular service.
They were operations on a portable description of an application, its
environment, and its lifecycle. The locally correct solution had the wrong
owner.</p>
<p>I extracted that logic into <a href="https://reploy.yadan.net/" target="_blank" rel="noopener noreferrer" class="">Reploy</a>, which is
unreleased and still evolving. I had previously used Puppet and Chef, so the
value of a durable, declarative infrastructure model was familiar to me.
Existing tools could encode parts of the workflow. Puppet and Chef, for example,
model the desired state of machines and nodes rather than presenting the
portable application lifecycle - stage, change, test, and install - as the
object being manipulated.</p>
<p>As I pulled the logic out, other uses gradually came into view: portable
development environments, repeatable build environments, AI-agent runtimes,
workflow execution, and perhaps remote execution.</p>
<p>This was not a single moment of insight. The local solution came first.
Repeated contact with the problem exposed the missing concept. As I internalized
that concept, more problems began to look like instances of it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cheap-code-and-expensive-meaning">Cheap code and expensive meaning<a href="https://yadan.net/writing/ai-doesnt-get-annoyed/#cheap-code-and-expensive-meaning" class="hash-link" aria-label="Direct link to Cheap code and expensive meaning" title="Direct link to Cheap code and expensive meaning" translate="no">​</a></h2>
<p>There is an obvious counterargument: perhaps AI is correctly making some
abstractions unnecessary.</p>
<p>Repeated implementations are no longer automatically expensive. A shared
abstraction introduces its own costs: coupling, compatibility constraints,
leaky boundaries, and the risk of freezing a generalization before the concept
is understood. Cheap, specialized generated code may sometimes be better than a
framework that costs more than the duplication it replaces.</p>
<p>One-off code is not a failure. Cheap, disposable glue may be exactly the right
answer to a genuinely isolated problem.</p>
<p>AI may therefore reduce the value of abstractions whose main purpose is to
avoid rewriting similar implementations. If the code is easy to regenerate,
compression through reuse is less valuable than it used to be.</p>
<p>But many abstractions do more than save implementation effort. They define what
an object means, who owns a behavior, which invariants must hold, how
compatibility is maintained, where security and failure are reasoned about, and
what users and other systems can rely on.</p>
<p>Generated code may reduce the cost of duplication, but it does not eliminate
the need for shared meaning.</p>
<p>That is why cheap code creates a paradox. It weakens the pressure to abstract,
while abundant code increases the need for trusted abstractions. A locally
correct implementation may be cheap to replace. The expectations accumulated
around a shared model are not.</p>
<p>Code can be regenerated from a prompt. The expectations surrounding it are not
regenerated with it. When AI produces a working solution, the question is
therefore not only whether the code should be reused. It is whether the solution
reveals a concept that needs a name, an owner, and a durable model.</p>
<p>AI systems may eventually be given enough scope and continuity to notice these
patterns for themselves. A system that observes years of maintenance, repeated
implementations, and failures across many projects may conclude that the next
piece of code is evidence of a missing abstraction.</p>
<p>But that is not how most AI-assisted work is framed today. Today, the model is
rewarded for making the next case work.</p>
<p>That is why annoyance still matters. It is the residue left when the
implementation succeeds but the design is wrong. It tells us that the code
works, yet the concept is missing.</p>
<p>If AI can make the wrong level of work feel effortless, what will force us to
invent the level above it?</p>]]></content:encoded>
            <category>engineering</category>
            <category>ai</category>
        </item>
    </channel>
</rss>