{"slug": "ai-doesn-t-get-annoyed", "title": "AI Doesn't Get Annoyed", "summary": "AI lowers the cost of generating implementations from informal requests, removing low-level work but potentially leaving complexity unabstracted, warns a new essay. The piece argues that human annoyance at repeated friction has historically driven the creation of better tools and abstractions, but AI optimized for ticket-sized objectives has little incentive to pay the upfront cost of a shared model. The author suggests that without the feedback loop of irritation, systems may accumulate hidden complexity that humans would otherwise have refactored.", "body_md": "# AI Doesn't Get Annoyed\n\n*Compilers exist because humans got tired of writing machine code. What shared\nconcepts will remain implicit when AI can keep generating implementations\nforever?*\n\n## The next compiler\n\nLinus Torvalds made a comparison that I found useful. He objected to describing\nAI-assisted code as \"written by AI.\" Compilers already generate all the machine\ncode, but we do not ordinarily say that the compiler wrote the program. In his\nanalogy, AI is another tool that changes how the programmer creates software,\nnot necessarily who created it. [His larger point was that the fundamentals\nstill matter even as the tools change.](https://lwn.net/Articles/1073761/)\n\nCompilers 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.\n\nAI 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.\n\nBut there is an important difference.\n\nA 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.\n\n## Annoyance carries information\n\nThe 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.\n\nSometimes that instinct leads nowhere. But sometimes annoyance is a wrong-abstraction detector.\n\nNecessity invents a solution. Annoyance invents a system.\n\nAnnoyance can tell us that we are repeatedly restating durable information.\nThat several decisions from different layers have been collapsed into one\noperation. That the same idea appears in many slightly different forms. That a\ncomponent is doing work which logically belongs somewhere else.\n\nIn those cases, the irritation is not just about effort. It is evidence that the system lacks a useful concept.\n\nAI 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.\n\nThe pain disappears, or at least moves out of sight. The complexity does not.\n\nThis is not an argument that AI cannot invent abstractions. It plainly can\nrecognize patterns, propose interfaces, and help design systems. The question\nis what it is being asked to optimize. When AI is given a ticket-sized or\ncase-specific objective, another working implementation is usually a successful\noutcome. The fact that humans would hate maintaining fifty such solutions may\nnever enter the task.\n\nThis is not primarily a limitation of model capability. Even an agent with\nperfect knowledge of the codebase, given a ticket-sized objective, has little\nreason to pay the upfront cost of an abstraction the task never asked for.\n\nAI 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.\n\nSoftware 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.\n\nThe 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.\n\n## Long command lines are a symptom\n\nOne 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.\n\nIt 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.\n\nThe problem is not character count. The problem is that structure has been turned into an invocation.\n\nRepeated, durable structure belongs in a model. The command line should express an action, a selection, or a delta.\n\nI had encountered this pattern long before generative AI. It was part of the\nmotivation behind [Hydra](https://hydra.cc/docs/intro/), a configuration\nframework I created for Python applications. Hydra moves durable configuration\ninto a hierarchical, composable model, while the command line selects\nalternatives or states what is different. The model can then be inspected,\nvalidated, saved, and shared instead of being reconstructed for every run.\n\n## Following the annoyance\n\nMore 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.\n\nThe 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.\n\nI 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.\n\nMy 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.\n\nThe 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.\n\nAn 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.\n\nI extracted that logic into [Reploy](https://reploy.yadan.net/), which is\nunreleased and still evolving. I had previously used Puppet and Chef, so the\nvalue of a durable, declarative infrastructure model was familiar to me.\nExisting tools could encode parts of the workflow. Puppet and Chef, for example,\nmodel the desired state of machines and nodes rather than presenting the\nportable application lifecycle - stage, change, test, and install - as the\nobject being manipulated.\n\nThe service no longer needed to know how to install itself; Reploy owned that\nlifecycle.\n\nAs 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.\n\nThis 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.\n\n## Cheap code and expensive meaning\n\nThere is an obvious counterargument: perhaps AI is correctly making some abstractions unnecessary.\n\nRepeated 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.\n\nOne-off code is not a failure. Cheap, disposable glue may be exactly the right answer to a genuinely isolated problem.\n\nAI 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.\n\nBut many abstractions do more than save implementation effort. They make shared concepts explicit: what an object means, who owns a behavior, which invariants must hold, how compatibility is maintained, how security and failure are handled, and what users and other systems can rely on.\n\nGenerated code may reduce the cost of duplication, but it does not eliminate the need for shared meaning.\n\nThat 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.\n\nCode 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 it solves the immediate problem. It is whether the solution has exposed a concept that should become explicit in the system - given a name, an owner, and an appropriate durable representation.\n\nAI does not eliminate annoyance. It moves it. The code may be effortless to\nregenerate, but the requirements must be restated, the results rechecked, and\nthe inconsistencies reconciled. That new friction is the same signal in another\nform: the system still lacks a shared concept.\n\nThat suggests a practical test. If only the implementation repeats,\nregeneration may be fine. But if the requirements, invariants, ownership, or\ncompatibility expectations must be reconstructed each time, the duplication is\ncarrying meaning. That meaning needs a shared model.\n\nCompilers did not make human creativity obsolete. AI will not either. It will give it unprecedented leverage. AI can generate working solutions endlessly, but creativity begins when someone sees beyond the answer, imagines a possibility that does not yet exist, decides that it matters, and brings it into the world.", "url": "https://wpnews.pro/news/ai-doesn-t-get-annoyed", "canonical_source": "https://yadan.net/writing/ai-doesnt-get-annoyed/", "published_at": "2026-07-28 17:58:48+00:00", "updated_at": "2026-07-28 18:22:54.240307+00:00", "lang": "en", "topics": ["artificial-intelligence", "developer-tools", "ai-tools"], "entities": ["Linus Torvalds"], "alternates": {"html": "https://wpnews.pro/news/ai-doesn-t-get-annoyed", "markdown": "https://wpnews.pro/news/ai-doesn-t-get-annoyed.md", "text": "https://wpnews.pro/news/ai-doesn-t-get-annoyed.txt", "jsonld": "https://wpnews.pro/news/ai-doesn-t-get-annoyed.jsonld"}}