My favorite story about specs centers around a team I joined a few years ago that was in the process of re-designing their analytics pipelines. They suffered from one large issue: most of their transformations where in one schema without a clear naming convention, and since there were so many developers over time it had become nearly impossible to know where any of the data lived. There were hundreds of tables and often as many as ten levels of dependency. No one ever argued it didn’t need to be fixed, but when it came to solutions… everyone got real quiet.

One unlucky staff engineer was assigned to do a design that would address all these problems. He spent months, relatively siloed, working on a spec. Upon emerging, the team I was on was given a roughly 50 page technical specification for how every piece of the analytics system should work, which we were then to implement. The manager in charge asked us to read it thoroughly and comment on anything that’s unclear. What followed was a multi-month slog of back and forth of “what about X?”, overlooked usability problems, security issues, and still many missing details.

It was painful, and the entire project was quietly canceled after nearly a year of false starts.

At this point I assume most developers have their own version of this story. Usually the lesson taken from it is that specs are a waste of time or that BDUF (Big Design Up Front) is a failure. The agile alternative that most teams live with is to have lots of meetings and basically wing it until you get something out the door. The success rate for those types of projects isn’t much better.

The first problem in these styles is a lack of distinction between a technical vs functional specification. A technical specification will list programming implementation details, functions, databases, etc. It may even include code to be used. These tend to be extremely long and rarely read. The functional spec is meant to describe what the program does from a user-facing perspective. If it’s an analytics system it’ll include information about what data comes in and what format it comes out in, and where users can locate it. But it wouldn’t include SQL or python or other implementation details.

I’ve never worked with a technical spec that didn’t implode on first contact with development effort. On the other hand, putting together a minimal functional spec and presenting it to both users and dev teams works surprisingly well. Users and developers benefit immensely from knowing what the usability expectations are. Instead of doing the implementation details in the spec, leave that to the developing team where it belongs. With a functional spec they have what the need to start their work, and can raise objections early if it elements of the spec aren’t feasible.

As part of a functional spec the acceptance criteria needs to be stated explicitly. I’m a stickler for well written acceptance criteria as it can break a project when not done clearly and directly. Any even medium-sized project will have behavior that needs to be specified down to the level of “If X happens then the program will do Y.” The developers and the users must agree on these. Having explicit acceptance criteria gives everyone a voice at the beginning, but stops them from showing up mid-project with ‘just one little thing’. New issues can be added, of course, but agreeing to the AC should be understood as “If it does this, I will approve it.” I’ve lost my temper a few times at a developer refusing to approve a pull request after agreeing to the AC that it met. Don’t do it!

For your next project, write up a short functional spec, include the acceptance criteria, meet with the stakeholders, agree on it, and then get to work. It’s that or spend months in meetings. I know which one I’d pick.