You're misunderstanding what I mean by spec. A spec is made up of a list of requirements. This list of requirements can be considered constraints on processes, performance, features, limitations, whatever. Whatever makes sense in the world of the specifier.
For example, I can have a requirement that says: "The program shall generate a set of weekly time schedules that are maximally preferable, based upon each students' preferences, for all students at a given location while taking into account resource constraints re: room availability and teacher availability." Of course, this isn't specified to the level of detail I'd put in a real spec, but it serves as an example.
There's many ways to solve this requirement, i.e., there are many different programs that satisfy this spec.
There are two solutions that may stand out: (1) a brute-force approach, and (2) a convex optimization approach.
Since I've not explicitly defined a speed of execution requirement in this spec, then a brute-force approach may make sense... even if it runs for 5 days. In the real-world, you'd confirm this undefined assumption.
If instead my spec said this needs to complete within a day, then maybe the convex approach would make more sense. However, you'd first seek more definition in the spec, i.e., how many students are we generating schedules for? If it's only 10, maybe brute-force, if it's 20k, then convex.
So on and so forth.
Now, the interesting part comes when you create the end-to-end (E2E) and acceptance tests. These tests should be the first thing you write because they follow directly from the spec. They will stand up the program as if it's running in production and drive it as such to test whether it adheres to the spec.
Once all your E2E and acceptance tests are passing, and we've eatablished that your tests cover the spec completely, then we can mark the program as correct with respect to the spec.
There are many different software designs that satisfy a spec.
Thing is, the need to formally define "behaviour" like that is a symptom of poor organisational/team structure. If you have multi-discipline teams with end-to-end accountability for a complete product (or vertical slice of a product) then your "spec" can be replaced with a problem statement and all of a sudden people can start focusing on whether the output solves the problem rather than whether it satisfies some arbitrary behaviour.
Put another way, the problem with having a "software spec" is that you already have the "software which is a spec" and now you have 2 specs.
Or a 3rd way, figuring out the right interface for 2 components is at least 50% of the work when writing software. So, spec writing is like programming. And you wouldn't want to program by committee, would you?
This is one thing Amazon got right - having small internal departments and interacting like separate companies.
I guess you have never heard of declarative programming, design by contract or logical programming, which explicitly does constrain the visible solution space by defining the problem sufficiently.
Though imperative programming looks at the problem from another angle which is closer to execution details, it's not fundamentally different. A smart compiler/interpreter may completely ignore those details as long as it produces the right output, as specified by the spec. That spec being the code.
This is obvious when you see that one style of program can be converted to another style without losing the semantics.
It's blindingly obvious that you've never worked in, worked on, or managed a successful large organization (say >500 people || >$1B mkt cap) or a successful large project (say >5k man-hours || >50 people || >$10M budget).
> whether the output solves the problem rather than whether it satisfies some arbitrary behaviour
The spec is considered the solution to the problem! It's not arbitrary in any sense of the word.
The problem with "specs" is that you don't know whether they solve the problem until the solution is implemented and shipped. And even then, you have no real way of knowing what's meat and what's cud. So lots of time, money and people are thrown at solutions that - at best - are wildly bloated or inefficient and - at worst - completely fail to address the actual problem at hand.
The _need_ for specs is - even in large organisations - typically down to misplaced accountability. When you decompose the problem space into small pieces and give development teams a high degree of problem-solving autonomy _and_ accountability for production, the organisational disconnects that lead to the "need" (or, rather, the ill-conceived desire) for burdensome process and specification largely go away.
This isn't witchcraft - it's progress. It works; and it works in large organisations. You haven't witnessed it, so you don't believe me. If/when you do, I'd be willing to bet you'll be converted as I was.
But I'm sure I've given you plenty of reasons to double down on your skepticism.
> The problem with "specs" is that you don't know whether they solve the problem until the solution is implemented and shipped.
No. Good product management eliminates this risk. And that's what you're talking about: risk.
You can test a product, feature, anything, many different ways before you build an actual implementation.
That's basic product and risk management.
> And even then, you have no real way of knowing what's meat and what's cud.
Monitoring.
> When you decompose the problem space into small pieces and give development teams a high degree of problem-solving autonomy _and_ accountability for production
You just like... defined what a spec is... man.
> This isn't witchcraft - it's progress. It works; and it works in large organisations.
Please provide the proof to back this up. Otherwise it's a baselsss claim.
> You haven't witnessed it, so you don't believe me.
No, I've arrived at my beliefs through the data on this point.
And the fact of the matter is that 100+ successful companies that have shipped successful products/projects operate with specs across many different industries from pharmaceuticals to construction to aeronautics and so on and so forth.
If the data supported your conclusion, then I'd agree with it. But the data does not support your conclusion.
There are very, very few languages (or few applications of every language) where we can honestly say "software is the spec".
Please tell me, what is the specification of this code so that we can verify and validate it:
(defun f (x y) (* x y))
Is the specification: `f` shall return the product of two numbers?
Perhaps. Perhaps it was supposed to be addition. Perhaps it was only supposed to apply to integers. If the above spec is correct, is the code correct? Maybe. It doesn't react well when given non-numeric values. Is that a problem? I don't know, the code doesn't explain who is responsible for validating input and who is responsible for handling errors.
A specification is a hybrid prose/formal document that would give us all that information (if it had any value). The code above is not a specification, it is an implementation. No different than a gear or a cog or a lever in mechanical engineering. It is a thing which does some work. We can examine it and see what it does. But we cannot, by observation or execution, determine why without greater context. That context is the specification.
The software is an artifact, one among many, which (hopefully) satisfies a specification.