Thinkr

Craft

Good PRD vs Bad PRD: The Same Feature, Written Twice

One feature, two specs. The weak one is not badly written — it is well written and empty, which is exactly why it passes review.

Galang Aulia · 7 min read
Craft

The most useful thing to understand about weak PRDs is that they are not badly written.

They are well written and empty. Clear sentences, sensible structure, confident tone, no typos — and almost no decisions. That combination is exactly why they pass review: the gaps do not look like gaps, they look like sentences you already nodded at.

Here is one feature, specified twice.

The feature

A project list where users can save a filter combination and return to it. Small, common, the kind of thing that gets a paragraph and a ticket.

Version A — the one that gets approved

## Saved views

Users can save their current filter configuration as a named view and access
it later from the views menu. This reduces repetitive filtering for users who
regularly check the same subsets of projects.

Users can create, rename, and delete their saved views. Views are personal to
each user. The most recently used view is remembered between sessions.

Success metric: increased usage of the filter feature and reduced time to
find projects.

Read it again and notice how reasonable it is. Nothing is wrong. It would pass most reviews, and in a lot of teams it would go straight to a ticket.

What is actually missing

Every line below is a decision the spec leaves to whoever writes the code first.

How many views can a user save? Unlimited? If so, what does the menu look like at forty? If capped, what happens at the cap — hidden button, error, upgrade prompt?

What is in a view? Filters, obviously. Sort order? Column selection? Page size? Two engineers will make opposite calls here and both will be defensible.

What happens when a saved filter becomes invalid? A view filtered by a project status that someone later deleted. Does it error, silently drop the filter, or show zero results and imply there is nothing there?

What happens on rename collision? Two views called "Q3". Allowed, blocked, auto-suffixed?

What is the empty state? A user with no saved views — is the menu hidden or present-and-empty with guidance?

What does "remembered between sessions" mean? Per device or per account? What if the remembered view was deleted on another device?

How is success actually measured? "Increased usage" from what baseline, over what window, and how do you attribute a change to this feature rather than to the traffic growth happening anyway?

That is seven decisions, and none of them are exotic. They are the ordinary substance of the feature — and every one gets made silently, by whoever hits it, under sprint pressure.

Version B — the one that ships

## Saved views

Users can save a filter configuration as a named view and return to it later,
so people who check the same subsets repeatedly stop rebuilding filters.

### What a view contains
Filters, sort order, and column selection. Page size is not saved — it stays a
session preference.

### Creating
- Save is available whenever at least one filter is active. With no filters,
  the control is visible and disabled, tooltip: "Add a filter to save a view."
- Name: required, 1-40 characters, unique per user.
- Duplicate name: inline error on submit, "You already have a view called X."
  The dialog stays open with the name selected.
- Limit: 20 views per user. At 20, Save is disabled with "You have reached 20
  saved views. Delete one to save another." (Chosen over a paid upgrade path —
  see Not doing.)

### Using
- Views are personal. No sharing in this release.
- Selecting a view applies its filters, sort, and columns in one navigation.
- The last used view reloads on return, per account rather than per device.
  If it was deleted elsewhere, fall back to the unfiltered list with no error.

### Invalid filters
If a saved filter references a value that no longer exists (deleted status,
removed member), apply the remaining valid filters and show an inline notice:
"One filter in this view is no longer available. [Update view]" — never a
silent empty result, which reads as "no projects" and is the failure users
report as a data bug.

### Empty state
No saved views: menu is present, showing "No saved views yet" and one line of
guidance. Never hidden — hiding it means the feature is never discovered.

### Not doing
- Sharing views with the team (adjacent; planned for Q4)
- Views scoped to a workspace rather than a user (rejected: doubles the
  permissions surface for a use case two customers raised)
- Saving page size (rejected: session preference, not a view property)

### Success metric
Primary: % of weekly active users with >=1 saved view, 30 days after GA.
Baseline: 0 (new feature). Target: 25%.
Guardrail: median time-to-first-result on the project list does not increase.

### Acceptance criteria
- Save disabled with zero filters, enabled with one or more
- Duplicate name blocked with inline error, dialog retains input
- 20-view limit enforced with the stated message
- Deleted-filter view applies remaining filters and shows the notice
- Last-used view persists across devices on the same account
- Empty state renders for a user with no views

Roughly twice as long. That length is a side effect, not a goal — every extra line is a decision that was going to be made anyway, made once, in the open.

What actually changed

Version AVersion B
"Save their current filter configuration"Names exactly what a view contains, and what it excludes
Silent on limits20, with the behaviour at the limit and the reason for the choice
Silent on collisionsDuplicate name blocked, message specified, dialog retains input
Silent on invalid statePartial-apply with an inline notice, and the reason it is not a silent empty
"Remembered between sessions"Per account, with the cross-device deletion case handled
No exclusionsThree, each labelled adjacent, rejected, or deferred
"Increased usage"A metric with a baseline, a window, and a guardrail

The five differences that mattered

States are named. Empty, at-limit, invalid-filter, deleted-elsewhere. Version A has one state. Version B has five, and the extra four are where users actually live.

Numbers exist. Twenty views. Forty characters. Twenty-five percent. Each one converts an opinion into something that can fail a test.

Failures are specified. The invalid-filter case is the difference between a feature that degrades gracefully and one that produces a support ticket reading "my projects disappeared."

The boundary is drawn. Version B says what it is not doing and why, before approval rather than during the build.

The metric is measurable. "Increased usage" cannot be evaluated. A percentage with a baseline and a guardrail can be, and the guardrail is what stops you celebrating adoption while the list got slower.

Why Version A felt fine

Worth sitting with, because you will write it again.

Version A is fluent. It has a rationale, it scopes the feature to personal views, it names three operations, it ends with a metric. It has the shape of a complete spec, and shape is what a fast reader checks.

It also encodes real knowledge — the author clearly understood the problem. That knowledge just stayed in their head, because nothing in the writing process forces it out. You do not notice the absence of a limit while writing, precisely because you were not thinking about forty views.

This is why re-reading your own spec surfaces so little, and why the fix is structural: run a pass that asks the questions your imagination did not. The five lenses exist for exactly this.

How to tell which one you wrote

Hand it to someone who was not in your planning conversations. Ask one question:

List every decision you would have to make to build this.

If the list is short, you wrote Version B. If it runs to seven items, you wrote Version A — and it will still read well, which is the trap. The gaps do not announce themselves. Someone has to go looking for them, before the sprint rather than during it.

FAQ

What makes a PRD good? Someone can build and verify it without you in the room.

Why do bad ones pass review? Prose quality and spec quality are independent, and reviews mostly measure prose. A weak spec in confident sentences reads as finished.

Is longer better? No. The length here is a by-product of naming states and failures, not a target.

How do I tell which I wrote? Ask a stranger to list the decisions they would still have to make. The length of that list is your answer.

New posts and release notes. No spam, unsubscribe anytime.

Stop shipping foggy PRDs.
Start the critique loop.

Three minutes to sign up. No credit card. Cancel by closing the tab.

Start freeSee pricing