Is Code Really Cheap?
Juggling balls are cheap. So why stop at three?
In my first article on specification-driven development (SDD), I called code “the cheap, replaceable artifact.” In hindsight, that was a shallow way of looking at it. I had underestimated what code preserves and assumed too much about what a specification would do better.
The argument was straightforward: AI makes code cheaper, so the specification becomes the thing worth keeping. Preserve the intent, let the implementation change. I still think specifications can be useful. But that explanation skipped two questions: what exactly became cheap, and why would that make a specification more valuable?
Generating it was the inexpensive part
I occasionally help review changes for applications built largely through AI generation. One has roughly 100,000 lines of Laravel code, with changes that can span hundreds of files. Before I can judge a change, there is a lot of existing behavior to understand.
An agent helps, but its investigation has a cost too. My rough impression is that these reviews consume around ten times the tokens I spend reviewing one of my own applications. That is not a controlled comparison; it is what I notice while watching my credits disappear before the agent has even worked out what the change affects.
More code gives me more software to understand, test, and maintain. Good structure can keep each change manageable, but cheap generation does not provide that structure by itself. I had treated cheaper generation as though it also made the resulting software cheaper to own.
Calling it a specification does not make it useful
“Specification” can mean requirements, a document, behavioral tests, or statements in a formal language. Code also specifies behavior in an executable form. My earlier article acknowledged tests, but leaned on the prose sense of “specification” while contrasting it with code.
I previously wrote that code had stopped telling me which parts it did on purpose. That was too broad. Well-written code can make intended behavior clear, just as poorly written prose can obscure it.
Working code already expresses a great deal of intent, and I can run it to examine that intent in action. A prose specification has to make clear what it provides beyond that.
Where prose can help is in choosing the level of detail. “A cancelled subscription keeps access until the paid period ends” lets me discuss a product rule without tracing how the application checks dates and permissions. The code that grants access through that date expresses the product rule too. Code can offer abstractions, but the implementation must ultimately supply the details needed to execute. A short explanation can let a reader step back from those details; code and tests can specify behavior more precisely where those details matter.
That is a reason to keep several views of a system. Someone who misunderstands a rule can encode that misunderstanding in prose as readily as in code. Writing a useful high-level account takes judgment about what to leave out as well as what to preserve.
The first article already said that a specification’s existence was not the goal. That still holds: a document nobody has read or checked can have “Specification” at the top while leaving important decisions unclear. What I am correcting is the assumption that prose would preserve intent better than the code it describes.
A specification helps with a rewrite. It does not perform one.
Suppose I ask an agent to rebuild an application on a different stack. Its high-level specification may describe what the application should do while leaving out constraints the implementation must respect. For example, it might name an external integration without repeating the provider’s limit on how often it can be called. That requirement lives in the provider’s documentation. The implementation still has to respect it, so the code spaces out requests or holds them until capacity is available. If the replacement uses the same provider, it must respect that limit too.
Other constraints may change with the deployment environment. Suppose a new server instance takes ten seconds to become ready in the current system and ten milliseconds in the replacement. Code that starts instances early or keeps spare capacity ready may reflect that delay. The new environment gives me reason to reconsider those choices; copying them blindly can be as mistaken as discarding them.
These decisions can be necessary for the system to work without belonging in its high-level behavioral specification. During a rewrite, I have to recover the constraints behind them and decide which still apply. A detailed migration plan can record those decisions, but writing it requires that investigation first.
Regeneration may be sensible for a small, self-contained application. A complex system still requires discovery, adaptation, and checking. My earlier article did not promise a one-command migration, but “cheap, replaceable artifact” made replacement sound like a consequence of cheap generation. That does not follow.
SDD has to improve on a reasonable plan
If the alternative is generating an entire application in one pass and accepting whatever appears, working through a prose specification first is a clear improvement (so is pretty much every other approach). But compare that with a workflow that already includes a reviewed plan, small, manageable changes, a testing strategy, static checks, automated quality gates, and code reviews. What does keeping a separate account of the system add to that?
Part of the appeal of SDD is the expectation that writing a specification will make the application clearer. It can, if the process exposes ambiguities and someone works through them. But the workflow cannot supply the judgment needed to recognize a missing requirement or question a plausible assumption. That work also happens when an experienced engineer reviews a plan.
SDD might help someone recognize questions they would otherwise miss, or help a team discover that they disagree about what the software should do. The useful comparison is whether it helps the people involved find and resolve those problems earlier than their existing process, and whether that benefit justifies the additional work.
Saving the plan preserves reasoning that might otherwise disappear with the conversation. But a plan describes a proposed change; a lasting account of the resulting system needs further work.
That account can save someone from reconstructing a rule or help a reviewer catch a mistake. Those benefits have to justify the effort of keeping it accurate and finding the relevant information.
The useful claim survives without the cheap code
I still agree with the first article’s test: a specification earns its keep when it makes software easier to change. AI may also make good documentation easier to maintain and consult, which is an argument I want to explore separately.
Perhaps another useful role for SDD is teaching people to think like engineers. A workflow that asks someone to explain expected behavior, identify constraints, and examine tradeoffs can give them practice in making those decisions. That possibility interests me. But that learning depends on the person doing the thinking. Someone who asks an agent to write a specification and approves it without questioning its assumptions or understanding its decisions is outsourcing the thinking to an agent. Having a specification does not mean they have practised the reasoning that produced it.
That leaves me with a narrower claim than the one I started with:
Generating code cheaply does not make it cheap to own. Keeping a prose specification does not make the code disposable.
Is Code Really Cheap?
// Juggling balls are cheap. So why stop at three?
In my first article on specification-driven development (SDD), I called code “the cheap, replaceable artifact.” In hindsight, that was a shallow way of looking at it. I had underestimated what code preserves and assumed too much about what a specification would do better.
The argument was straightforward: AI makes code cheaper, so the specification becomes the thing worth keeping. Preserve the intent, let the implementation change. I still think specifications can be useful. But that explanation skipped two questions: what exactly became cheap, and why would that make a specification more valuable?
Generating it was the inexpensive part
I occasionally help review changes for applications built largely through AI generation. One has roughly 100,000 lines of Laravel code, with changes that can span hundreds of files. Before I can judge a change, there is a lot of existing behavior to understand.
An agent helps, but its investigation has a cost too. My rough impression is that these reviews consume around ten times the tokens I spend reviewing one of my own applications. That is not a controlled comparison; it is what I notice while watching my credits disappear before the agent has even worked out what the change affects.
More code gives me more software to understand, test, and maintain. Good structure can keep each change manageable, but cheap generation does not provide that structure by itself. I had treated cheaper generation as though it also made the resulting software cheaper to own.
Calling it a specification does not make it useful
“Specification” can mean requirements, a document, behavioral tests, or statements in a formal language. Code also specifies behavior in an executable form. My earlier article acknowledged tests, but leaned on the prose sense of “specification” while contrasting it with code.
I previously wrote that code had stopped telling me which parts it did on purpose. That was too broad. Well-written code can make intended behavior clear, just as poorly written prose can obscure it.
Working code already expresses a great deal of intent, and I can run it to examine that intent in action. A prose specification has to make clear what it provides beyond that.
Where prose can help is in choosing the level of detail. “A cancelled subscription keeps access until the paid period ends” lets me discuss a product rule without tracing how the application checks dates and permissions. The code that grants access through that date expresses the product rule too. Code can offer abstractions, but the implementation must ultimately supply the details needed to execute. A short explanation can let a reader step back from those details; code and tests can specify behavior more precisely where those details matter.
That is a reason to keep several views of a system. Someone who misunderstands a rule can encode that misunderstanding in prose as readily as in code. Writing a useful high-level account takes judgment about what to leave out as well as what to preserve.
The first article already said that a specification’s existence was not the goal. That still holds: a document nobody has read or checked can have “Specification” at the top while leaving important decisions unclear. What I am correcting is the assumption that prose would preserve intent better than the code it describes.
A specification helps with a rewrite. It does not perform one.
Suppose I ask an agent to rebuild an application on a different stack. Its high-level specification may describe what the application should do while leaving out constraints the implementation must respect. For example, it might name an external integration without repeating the provider’s limit on how often it can be called. That requirement lives in the provider’s documentation. The implementation still has to respect it, so the code spaces out requests or holds them until capacity is available. If the replacement uses the same provider, it must respect that limit too.
Other constraints may change with the deployment environment. Suppose a new server instance takes ten seconds to become ready in the current system and ten milliseconds in the replacement. Code that starts instances early or keeps spare capacity ready may reflect that delay. The new environment gives me reason to reconsider those choices; copying them blindly can be as mistaken as discarding them.
These decisions can be necessary for the system to work without belonging in its high-level behavioral specification. During a rewrite, I have to recover the constraints behind them and decide which still apply. A detailed migration plan can record those decisions, but writing it requires that investigation first.
Regeneration may be sensible for a small, self-contained application. A complex system still requires discovery, adaptation, and checking. My earlier article did not promise a one-command migration, but “cheap, replaceable artifact” made replacement sound like a consequence of cheap generation. That does not follow.
SDD has to improve on a reasonable plan
If the alternative is generating an entire application in one pass and accepting whatever appears, working through a prose specification first is a clear improvement (so is pretty much every other approach). But compare that with a workflow that already includes a reviewed plan, small, manageable changes, a testing strategy, static checks, automated quality gates, and code reviews. What does keeping a separate account of the system add to that?
Part of the appeal of SDD is the expectation that writing a specification will make the application clearer. It can, if the process exposes ambiguities and someone works through them. But the workflow cannot supply the judgment needed to recognize a missing requirement or question a plausible assumption. That work also happens when an experienced engineer reviews a plan.
SDD might help someone recognize questions they would otherwise miss, or help a team discover that they disagree about what the software should do. The useful comparison is whether it helps the people involved find and resolve those problems earlier than their existing process, and whether that benefit justifies the additional work.
Saving the plan preserves reasoning that might otherwise disappear with the conversation. But a plan describes a proposed change; a lasting account of the resulting system needs further work.
That account can save someone from reconstructing a rule or help a reviewer catch a mistake. Those benefits have to justify the effort of keeping it accurate and finding the relevant information.
The useful claim survives without the cheap code
I still agree with the first article’s test: a specification earns its keep when it makes software easier to change. AI may also make good documentation easier to maintain and consult, which is an argument I want to explore separately.
Perhaps another useful role for SDD is teaching people to think like engineers. A workflow that asks someone to explain expected behavior, identify constraints, and examine tradeoffs can give them practice in making those decisions. That possibility interests me. But that learning depends on the person doing the thinking. Someone who asks an agent to write a specification and approves it without questioning its assumptions or understanding its decisions is outsourcing the thinking to an agent. Having a specification does not mean they have practised the reasoning that produced it.
That leaves me with a narrower claim than the one I started with:
Generating code cheaply does not make it cheap to own. Keeping a prose specification does not make the code disposable.
Is Code Really Cheap?
Juggling balls are cheap. So why stop at three?
In my first article on specification-driven development (SDD), I called code “the cheap, replaceable artifact.” In hindsight, that was a shallow way of looking at it. I had underestimated what code preserves and assumed too much about what a specification would do better.
The argument was straightforward: AI makes code cheaper, so the specification becomes the thing worth keeping. Preserve the intent, let the implementation change. I still think specifications can be useful. But that explanation skipped two questions: what exactly became cheap, and why would that make a specification more valuable?
Generating it was the inexpensive part
I occasionally help review changes for applications built largely through AI generation. One has roughly 100,000 lines of Laravel code, with changes that can span hundreds of files. Before I can judge a change, there is a lot of existing behavior to understand.
An agent helps, but its investigation has a cost too. My rough impression is that these reviews consume around ten times the tokens I spend reviewing one of my own applications. That is not a controlled comparison; it is what I notice while watching my credits disappear before the agent has even worked out what the change affects.
More code gives me more software to understand, test, and maintain. Good structure can keep each change manageable, but cheap generation does not provide that structure by itself. I had treated cheaper generation as though it also made the resulting software cheaper to own.
Calling it a specification does not make it useful
“Specification” can mean requirements, a document, behavioral tests, or statements in a formal language. Code also specifies behavior in an executable form. My earlier article acknowledged tests, but leaned on the prose sense of “specification” while contrasting it with code.
I previously wrote that code had stopped telling me which parts it did on purpose. That was too broad. Well-written code can make intended behavior clear, just as poorly written prose can obscure it.
Working code already expresses a great deal of intent, and I can run it to examine that intent in action. A prose specification has to make clear what it provides beyond that.
Where prose can help is in choosing the level of detail. “A cancelled subscription keeps access until the paid period ends” lets me discuss a product rule without tracing how the application checks dates and permissions. The code that grants access through that date expresses the product rule too. Code can offer abstractions, but the implementation must ultimately supply the details needed to execute. A short explanation can let a reader step back from those details; code and tests can specify behavior more precisely where those details matter.
That is a reason to keep several views of a system. Someone who misunderstands a rule can encode that misunderstanding in prose as readily as in code. Writing a useful high-level account takes judgment about what to leave out as well as what to preserve.
The first article already said that a specification’s existence was not the goal. That still holds: a document nobody has read or checked can have “Specification” at the top while leaving important decisions unclear. What I am correcting is the assumption that prose would preserve intent better than the code it describes.
A specification helps with a rewrite. It does not perform one.
Suppose I ask an agent to rebuild an application on a different stack. Its high-level specification may describe what the application should do while leaving out constraints the implementation must respect. For example, it might name an external integration without repeating the provider’s limit on how often it can be called. That requirement lives in the provider’s documentation. The implementation still has to respect it, so the code spaces out requests or holds them until capacity is available. If the replacement uses the same provider, it must respect that limit too.
Other constraints may change with the deployment environment. Suppose a new server instance takes ten seconds to become ready in the current system and ten milliseconds in the replacement. Code that starts instances early or keeps spare capacity ready may reflect that delay. The new environment gives me reason to reconsider those choices; copying them blindly can be as mistaken as discarding them.
These decisions can be necessary for the system to work without belonging in its high-level behavioral specification. During a rewrite, I have to recover the constraints behind them and decide which still apply. A detailed migration plan can record those decisions, but writing it requires that investigation first.
Regeneration may be sensible for a small, self-contained application. A complex system still requires discovery, adaptation, and checking. My earlier article did not promise a one-command migration, but “cheap, replaceable artifact” made replacement sound like a consequence of cheap generation. That does not follow.
SDD has to improve on a reasonable plan
If the alternative is generating an entire application in one pass and accepting whatever appears, working through a prose specification first is a clear improvement (so is pretty much every other approach). But compare that with a workflow that already includes a reviewed plan, small, manageable changes, a testing strategy, static checks, automated quality gates, and code reviews. What does keeping a separate account of the system add to that?
Part of the appeal of SDD is the expectation that writing a specification will make the application clearer. It can, if the process exposes ambiguities and someone works through them. But the workflow cannot supply the judgment needed to recognize a missing requirement or question a plausible assumption. That work also happens when an experienced engineer reviews a plan.
SDD might help someone recognize questions they would otherwise miss, or help a team discover that they disagree about what the software should do. The useful comparison is whether it helps the people involved find and resolve those problems earlier than their existing process, and whether that benefit justifies the additional work.
Saving the plan preserves reasoning that might otherwise disappear with the conversation. But a plan describes a proposed change; a lasting account of the resulting system needs further work.
That account can save someone from reconstructing a rule or help a reviewer catch a mistake. Those benefits have to justify the effort of keeping it accurate and finding the relevant information.
The useful claim survives without the cheap code
I still agree with the first article’s test: a specification earns its keep when it makes software easier to change. AI may also make good documentation easier to maintain and consult, which is an argument I want to explore separately.
Perhaps another useful role for SDD is teaching people to think like engineers. A workflow that asks someone to explain expected behavior, identify constraints, and examine tradeoffs can give them practice in making those decisions. That possibility interests me. But that learning depends on the person doing the thinking. Someone who asks an agent to write a specification and approves it without questioning its assumptions or understanding its decisions is outsourcing the thinking to an agent. Having a specification does not mean they have practised the reasoning that produced it.
That leaves me with a narrower claim than the one I started with:
Generating code cheaply does not make it cheap to own. Keeping a prose specification does not make the code disposable.
In my first article on specification-driven development (SDD), I called code “the cheap, replaceable artifact.” In hindsight, that was a shallow way of looking at it. I had underestimated what code preserves and assumed too much about what a specification would do better.
The argument was straightforward: AI makes code cheaper, so the specification becomes the thing worth keeping. Preserve the intent, let the implementation change. I still think specifications can be useful. But that explanation skipped two questions: what exactly became cheap, and why would that make a specification more valuable?
Generating it was the inexpensive part
I occasionally help review changes for applications built largely through AI generation. One has roughly 100,000 lines of Laravel code, with changes that can span hundreds of files. Before I can judge a change, there is a lot of existing behavior to understand.
An agent helps, but its investigation has a cost too. My rough impression is that these reviews consume around ten times the tokens I spend reviewing one of my own applications. That is not a controlled comparison; it is what I notice while watching my credits disappear before the agent has even worked out what the change affects.
More code gives me more software to understand, test, and maintain. Good structure can keep each change manageable, but cheap generation does not provide that structure by itself. I had treated cheaper generation as though it also made the resulting software cheaper to own.
Calling it a specification does not make it useful
“Specification” can mean requirements, a document, behavioral tests, or statements in a formal language. Code also specifies behavior in an executable form. My earlier article acknowledged tests, but leaned on the prose sense of “specification” while contrasting it with code.
I previously wrote that code had stopped telling me which parts it did on purpose. That was too broad. Well-written code can make intended behavior clear, just as poorly written prose can obscure it.
Working code already expresses a great deal of intent, and I can run it to examine that intent in action. A prose specification has to make clear what it provides beyond that.
Where prose can help is in choosing the level of detail. “A cancelled subscription keeps access until the paid period ends” lets me discuss a product rule without tracing how the application checks dates and permissions. The code that grants access through that date expresses the product rule too. Code can offer abstractions, but the implementation must ultimately supply the details needed to execute. A short explanation can let a reader step back from those details; code and tests can specify behavior more precisely where those details matter.
That is a reason to keep several views of a system. Someone who misunderstands a rule can encode that misunderstanding in prose as readily as in code. Writing a useful high-level account takes judgment about what to leave out as well as what to preserve.
The first article already said that a specification’s existence was not the goal. That still holds: a document nobody has read or checked can have “Specification” at the top while leaving important decisions unclear. What I am correcting is the assumption that prose would preserve intent better than the code it describes.
A specification helps with a rewrite. It does not perform one.
Suppose I ask an agent to rebuild an application on a different stack. Its high-level specification may describe what the application should do while leaving out constraints the implementation must respect. For example, it might name an external integration without repeating the provider’s limit on how often it can be called. That requirement lives in the provider’s documentation. The implementation still has to respect it, so the code spaces out requests or holds them until capacity is available. If the replacement uses the same provider, it must respect that limit too.
Other constraints may change with the deployment environment. Suppose a new server instance takes ten seconds to become ready in the current system and ten milliseconds in the replacement. Code that starts instances early or keeps spare capacity ready may reflect that delay. The new environment gives me reason to reconsider those choices; copying them blindly can be as mistaken as discarding them.
These decisions can be necessary for the system to work without belonging in its high-level behavioral specification. During a rewrite, I have to recover the constraints behind them and decide which still apply. A detailed migration plan can record those decisions, but writing it requires that investigation first.
Regeneration may be sensible for a small, self-contained application. A complex system still requires discovery, adaptation, and checking. My earlier article did not promise a one-command migration, but “cheap, replaceable artifact” made replacement sound like a consequence of cheap generation. That does not follow.
SDD has to improve on a reasonable plan
If the alternative is generating an entire application in one pass and accepting whatever appears, working through a prose specification first is a clear improvement (so is pretty much every other approach). But compare that with a workflow that already includes a reviewed plan, small, manageable changes, a testing strategy, static checks, automated quality gates, and code reviews. What does keeping a separate account of the system add to that?
Part of the appeal of SDD is the expectation that writing a specification will make the application clearer. It can, if the process exposes ambiguities and someone works through them. But the workflow cannot supply the judgment needed to recognize a missing requirement or question a plausible assumption. That work also happens when an experienced engineer reviews a plan.
SDD might help someone recognize questions they would otherwise miss, or help a team discover that they disagree about what the software should do. The useful comparison is whether it helps the people involved find and resolve those problems earlier than their existing process, and whether that benefit justifies the additional work.
Saving the plan preserves reasoning that might otherwise disappear with the conversation. But a plan describes a proposed change; a lasting account of the resulting system needs further work.
That account can save someone from reconstructing a rule or help a reviewer catch a mistake. Those benefits have to justify the effort of keeping it accurate and finding the relevant information.
The useful claim survives without the cheap code
I still agree with the first article’s test: a specification earns its keep when it makes software easier to change. AI may also make good documentation easier to maintain and consult, which is an argument I want to explore separately.
Perhaps another useful role for SDD is teaching people to think like engineers. A workflow that asks someone to explain expected behavior, identify constraints, and examine tradeoffs can give them practice in making those decisions. That possibility interests me. But that learning depends on the person doing the thinking. Someone who asks an agent to write a specification and approves it without questioning its assumptions or understanding its decisions is outsourcing the thinking to an agent. Having a specification does not mean they have practised the reasoning that produced it.
That leaves me with a narrower claim than the one I started with:
Generating code cheaply does not make it cheap to own. Keeping a prose specification does not make the code disposable.
Is Code Really Cheap?
Juggling balls are cheap. So why stop at three?
In my first article on specification-driven development (SDD), I called code “the cheap, replaceable artifact.” In hindsight, that was a shallow way of looking at it. I had underestimated what code preserves and assumed too much about what a specification would do better.
The argument was straightforward: AI makes code cheaper, so the specification becomes the thing worth keeping. Preserve the intent, let the implementation change. I still think specifications can be useful. But that explanation skipped two questions: what exactly became cheap, and why would that make a specification more valuable?
Generating it was the inexpensive part
I occasionally help review changes for applications built largely through AI generation. One has roughly 100,000 lines of Laravel code, with changes that can span hundreds of files. Before I can judge a change, there is a lot of existing behavior to understand.
An agent helps, but its investigation has a cost too. My rough impression is that these reviews consume around ten times the tokens I spend reviewing one of my own applications. That is not a controlled comparison; it is what I notice while watching my credits disappear before the agent has even worked out what the change affects.
More code gives me more software to understand, test, and maintain. Good structure can keep each change manageable, but cheap generation does not provide that structure by itself. I had treated cheaper generation as though it also made the resulting software cheaper to own.
Calling it a specification does not make it useful
“Specification” can mean requirements, a document, behavioral tests, or statements in a formal language. Code also specifies behavior in an executable form. My earlier article acknowledged tests, but leaned on the prose sense of “specification” while contrasting it with code.
I previously wrote that code had stopped telling me which parts it did on purpose. That was too broad. Well-written code can make intended behavior clear, just as poorly written prose can obscure it.
Working code already expresses a great deal of intent, and I can run it to examine that intent in action. A prose specification has to make clear what it provides beyond that.
Where prose can help is in choosing the level of detail. “A cancelled subscription keeps access until the paid period ends” lets me discuss a product rule without tracing how the application checks dates and permissions. The code that grants access through that date expresses the product rule too. Code can offer abstractions, but the implementation must ultimately supply the details needed to execute. A short explanation can let a reader step back from those details; code and tests can specify behavior more precisely where those details matter.
That is a reason to keep several views of a system. Someone who misunderstands a rule can encode that misunderstanding in prose as readily as in code. Writing a useful high-level account takes judgment about what to leave out as well as what to preserve.
The first article already said that a specification’s existence was not the goal. That still holds: a document nobody has read or checked can have “Specification” at the top while leaving important decisions unclear. What I am correcting is the assumption that prose would preserve intent better than the code it describes.
A specification helps with a rewrite. It does not perform one.
Suppose I ask an agent to rebuild an application on a different stack. Its high-level specification may describe what the application should do while leaving out constraints the implementation must respect. For example, it might name an external integration without repeating the provider’s limit on how often it can be called. That requirement lives in the provider’s documentation. The implementation still has to respect it, so the code spaces out requests or holds them until capacity is available. If the replacement uses the same provider, it must respect that limit too.
Other constraints may change with the deployment environment. Suppose a new server instance takes ten seconds to become ready in the current system and ten milliseconds in the replacement. Code that starts instances early or keeps spare capacity ready may reflect that delay. The new environment gives me reason to reconsider those choices; copying them blindly can be as mistaken as discarding them.
These decisions can be necessary for the system to work without belonging in its high-level behavioral specification. During a rewrite, I have to recover the constraints behind them and decide which still apply. A detailed migration plan can record those decisions, but writing it requires that investigation first.
Regeneration may be sensible for a small, self-contained application. A complex system still requires discovery, adaptation, and checking. My earlier article did not promise a one-command migration, but “cheap, replaceable artifact” made replacement sound like a consequence of cheap generation. That does not follow.
SDD has to improve on a reasonable plan
If the alternative is generating an entire application in one pass and accepting whatever appears, working through a prose specification first is a clear improvement (so is pretty much every other approach). But compare that with a workflow that already includes a reviewed plan, small, manageable changes, a testing strategy, static checks, automated quality gates, and code reviews. What does keeping a separate account of the system add to that?
Part of the appeal of SDD is the expectation that writing a specification will make the application clearer. It can, if the process exposes ambiguities and someone works through them. But the workflow cannot supply the judgment needed to recognize a missing requirement or question a plausible assumption. That work also happens when an experienced engineer reviews a plan.
SDD might help someone recognize questions they would otherwise miss, or help a team discover that they disagree about what the software should do. The useful comparison is whether it helps the people involved find and resolve those problems earlier than their existing process, and whether that benefit justifies the additional work.
Saving the plan preserves reasoning that might otherwise disappear with the conversation. But a plan describes a proposed change; a lasting account of the resulting system needs further work.
That account can save someone from reconstructing a rule or help a reviewer catch a mistake. Those benefits have to justify the effort of keeping it accurate and finding the relevant information.
The useful claim survives without the cheap code
I still agree with the first article’s test: a specification earns its keep when it makes software easier to change. AI may also make good documentation easier to maintain and consult, which is an argument I want to explore separately.
Perhaps another useful role for SDD is teaching people to think like engineers. A workflow that asks someone to explain expected behavior, identify constraints, and examine tradeoffs can give them practice in making those decisions. That possibility interests me. But that learning depends on the person doing the thinking. Someone who asks an agent to write a specification and approves it without questioning its assumptions or understanding its decisions is outsourcing the thinking to an agent. Having a specification does not mean they have practised the reasoning that produced it.
That leaves me with a narrower claim than the one I started with:
Generating code cheaply does not make it cheap to own. Keeping a prose specification does not make the code disposable.