{"slug": "keeping-engineering-in-software-engineering", "title": "Keeping \"Engineering\" in \"Software Engineering\"", "summary": "Software engineer and developer advocate Simon Willison argues that prompting coding agents is not software engineering and proposes a workflow where developers maintain long-lived human-readable specification files that agents use to enforce design invariants across code changes. The approach, packaged as a plugin, aims to reduce bugs and inconsistencies that arise from imperative, incremental prompting of AI coding tools.", "body_md": "Most of the time, prompting coding agents is not practicing the art of software engineering. And that’s totally fine. Sometimes, you simply want to describe a feature in a few sentences and have the agent spit out the changes. But other times, you want real engineering, which involves applying well-reasoned consideration to the constraints, the current state of the code, and possible future states, and then combining these concepts into an elegant solution that minimally meets the requirements in a way that’s scalable and extensible.\n\nWe don’t engineer for engineering’s sake. We do it so future code changes can be made clearly and concisely, in a way that’s unlikely to introduce new bugs. And it’s this last part in particular, that bites unstructured agentic code bases in the proverbial ass. Over time, as the complexity of the application grows, numerous issues develop if care is not taken: inadvertent dependencies get added, invariants that guided the original design are forgotten, and the amount of bespoke state balloons. As a result, prompting the agent to change one piece of functionality frequently breaks another or leaves the application in an inconsistent state.\n\nAdditionally, prompting is *imperative* not *declarative*. We never lay out exactly what we want, instead opting to guide agents in small increments over and over again. Often, in between these steps, the agent will have forgotten something we said earlier.\n\nThat’s not to say we should stop prompting agents. We should continue to leverage them to speed up development. But we need higher-level primitives that allow us to specify the important parts of a design and have the agent enforce those across multiple changes and iterations.\n\nOver the last few weeks, I’ve been experimenting with ways of doing this, and I my current flow *kind of* works. It’s not perfect by any means, but overall trying to deal in higher level abstractions has been a breath of fresh air compared to dealing with prompt minutia.\n\nThe idea is to turn projects into long-lived specifications. These aren’t “plans” and they aren’t agent generated. The specifications are a human-digestible transcription of the core ideas and invariants of a design. If I want to update something about the engineering design, I simply update the spec to include the new information. Then, I ask my agent to look at what changed in the spec and to update the code so that the spec is accurate.\n\nHere’s how it works:\n\nNote: I packaged up everything below into a\n\n[plugin]. Feel free to use it. How it works is very simple, so you can leverage the basic principals without the plugin.\n\n### Step 1 - Define a spec file (Markdown is fine)\n\nThe spec file defines what you want to build. At first, it just contains your initial idea, but it will grow over time as your specify new functionality. This is the master plan of your application. **Do not slop it up**. This should be simple and human-digestible.\n\n### Step 2 - Update the spec\n\nDefine your new functionality, in a declarative way, leveraging composition with previous parts of the spec where applicable.\n\n### Step 3 - Kick of your agent\n\nRather than instruct your agent to implement the feature directly, you direct the agent to look at changes to your spec and figure out what should be done.\n\nTip: You can commit the changes to your spec and kick of the agent in a worktree so that you can continue specing out other functionality. If you’re using the\n\n[plugin], just run specling skill with your spec file to do this automatically.\n\nAnd that’s basically it.\n\n## Example\n\nWhat does a TODO app look like with declarative prompting?\n\n```\n# TODO app\n\nAn web application that shows a list of TODOs. A plus button at the top of the list \nadds a new TODO.\n\n## Data model\n\ntype Todo = string\n```\n\nThat leaves you with a standard looking TODO app\n\nThat looks ok, but we can’t mark them as done. Let’s update our data model:\n\n```\n> git diff\ndiff --git a/todo.spec.md b/todo.spec.md\nindex c50d17c..2f89f96 100644\n--- a/todo.spec.md\n+++ b/todo.spec.md\n@@ -5,4 +5,4 @@ adds a new TODO.\n \n ## Data model\n \n-type Todo = string\n+type Todo = { text: string; done: boolean }\n```\n\nA simple change to our data model lets the agent know what type of functionality we want.", "url": "https://wpnews.pro/news/keeping-engineering-in-software-engineering", "canonical_source": "https://blog.maxgale.co/p/keeping-engineering-in-software-engineering", "published_at": "2026-08-30 14:00:08+00:00", "updated_at": "2026-08-30 14:21:56.240757+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "ai-agents"], "entities": ["Simon Willison"], "alternates": {"html": "https://wpnews.pro/news/keeping-engineering-in-software-engineering", "markdown": "https://wpnews.pro/news/keeping-engineering-in-software-engineering.md", "text": "https://wpnews.pro/news/keeping-engineering-in-software-engineering.txt", "jsonld": "https://wpnews.pro/news/keeping-engineering-in-software-engineering.jsonld"}}