Writing a specification with sufficient detail to know exactly what software one should build is as much work as writing the code itself. In many cases, fully specifying the work beforehand is not possible because we don’t know enough about the problem or the domain to begin with. This is why our codebases are always in a state of flux and never complete systems.
This circular problem means most software development should be treated iteratively and course correct as more information becomes available. It’s worth investing more time in techniques for dealing with uncertainty rather than trying to figure out how to make better specification.