---
title: 'Describe the User''s Perspective: DDD, acceptance testing, and you'
teaser: Learn about the user first.
tags: design,playbook,testing
author: Mike Burns
published_on: 2012-06-22
---

Do not write any code unless you know why the user cares.

We have two ways of knowing whether a user cares: the design, and the acceptance
specification.

## The Design

When starting a feature, we start with a design. What we mean by this can be
vaguely high level, or it can be exact. Here are two example stories:

* As a moderator I want to mark a message as spam so I can improve the messaging
  experience.
* As a paying member I want the latest news articles 15 minutes before unpaying
  members.

We "design" both of these first. The first one gets a visual: either a drawing
on a piece of paper, or a <abbr title="HyperText Markup Language">HTML</abbr>
wireframe, or a full template using
[high_voltage](https://github.com/thoughtbot/high_voltage), or something else.

The second example is harder to represent visually, so it gets a more detailed
user experience discussion, coupled with diagrams: which news articles, how do
they get these articles, how do they know it's 15 minutes faster--and all of
that leads into a visual to work off, too.

## The Acceptance Spec

Much has been written about [acceptance
specs](http://c2.com/cgi/wiki?AcceptanceTest) through the ages, but a topic that
continues to arise is that of varying level of detail. Here are two examples:

    Scenario: Moderator marks messages as spam
      Given a user exists with a username of "joey user"
      And the following message exists:
        | user:username | subject           |
        | joey user     | Subjects are lame |
      And I am signed in as a moderator
      When I go to the spams page
      And I follow "Subjects are lame"
      And I press "Spam"
      Then I should see "the message has been marked as spam"
      Given I am signed in as "joey user"
      When I go to the messages page
      Then I should not see "Subjects are lame"

    Scenario: Moderator marks messages as spam
      Given a user has a message
      And I am signed in as a moderator
      When I mark that message as spam
      Then the user should not see the message

The first scenario spells out exactly what to do, step-by-step. It is written as
if I were using a super lame programming language that didn't have abstractions.
The second scenario describes the user's experience; it describes the reason to
care about the whole concept.

The second scenario is very closely related to the design discussion: all the
key points of the discussion are there, with none of the boring details (like
the fact that messages can have subjects). Moreover, it's readable.

"OK, great," you say. "Woo hoo, cucumber. [So
what](http://37signals.com/svn/posts/3159-testing-like-the-tsa)?"

Cut the sass; you can do this in Rspec too:

```ruby
describe 'moderation (like smoking cigars)' do
  it 'works as expected when the moderator marks a message as spam' do
    harness.make_user_with_message
    harness.sign_in_as_moderator

    harness.mark_the_message_as_spam

    harness.user_should_not see_the_message
  end

  let(:harness) { ModerationTestHarness.new }
end
```

## The Reasoning

There are at least four reasons why you absolutely need to start doing both of
these things right now:

* Do not build what you do not need. If it never shows up in the UI, and
  especially if it never shows up in the UX, drop it. Why did you even think you
  needed it at all?
* Confine changes to one place. If the existing story does not change, why
  should the test for it? For example, say you finally convince the client that
  messages should not have subjects ("'cause it's, like, 2012; c'mon," is your
  winning argument); this would cause you to re-write the first scenario, even
  though that story is fine and intact. You would have to change the
  implementation of the second scenario, but that's OK and boring; the
  high-level concept still exists.
* Keep it readable. The second scenario is easier to read, plain and simple. It
  hides more--when debugging, you will need to open another file--but that is
  only relevant when it breaks.
* Provide consistency. Going through the app from the end user's perspective
  means the names of models will match what the user sees, the algorithms and
  especially data will make sense. Compare "I need to show all weekly reminders
  across the events" to "I have a reminders table and an events table and need
  to select the reminders that have the weekly flag set and join with events
  on ...".
