Stephen Freeman Rotating Header Image

Mock Roles not Objects, live and in person.

At the recent Software Craftsmanship conference in London, Willem and Marc ran a session on Responsibility-Driven Development with Mocks for about 30 people. Nat Pryce and I were sitting at the back watching and occasionally heckling.

The first striking thing was that when Willem and Marc asked who was using “Mock Objects” most everyone put their hand up (which was nice), but then only a handful also said they were thinking about Roles and Responsibilities when they did (which was frustrating). We first wrote up these ideas in our paper “Mock Roles Not Objects” and much of the difficulty we see people have with the technique of Mock Objects comes from focussing on classes rather than relationships.

As it happens, an example popped up in the rest of the session, which was run as a Coding Dojo. What was interesting to me was how the group managed to turn around its design ideas. Here’s what I can remember about how it worked out.

The domain was some kind of game, with a hero who moves around an environment slaying dragons and so forth. The first couple of stories were to do with displaying the current room, and then moving from one room to another. It was a little difficult getting started because the limitations of the event didn’t allow enough time to really drive the design from outer-level requirements, but the group managed to get started with something like:

describe Hero do
  it "should describe its surroundings" do
    hero = Hero.new(room)

    room.stub!(:description).and_return("a room with twisty passages")

    console.should_receive(:show).with("in a room with twisty passages")
    hero.look(console)
  end
end

The expectation here says that when looking, the hero should write a text describing the room to the console. This was a place to start, but it doesn’t look right. Why is a hero attached to a room? And hero.look(console) just doesn’t read well, it’s hard to tell what it means. The tensions became clearer with the next feature, which was to have the hero move from one room to another. If we write

hero.move_to(other_room)

how can we tell that this has worked? We could ask the hero to look() again, but that means making an extra call for testing, which is not related to the intent of the test. We could ask the hero what his current room is, but that’s starting to leak into Asking rather than Telling. There may be a need for the hero to hold on to his current location, but we haven’t seen it yet.

Suddenly, it became clear that the dependencies were wrong. We already have a feature that can be told about the hero’s situation, which we can build on. If the feature were to be told about what is happening to the hero, we could use that to detect the change in room. So, our example now becomes:

describe Hero do
  it "should move to a room" do
    hero = Hero.new(console)

    room.stub!(:description).and_return("a room with twisty passages")

    console.should_receive(:show).with("in a room with twisty passages")

    hero.move_to(room)
  end
end

That’s better, but it’s not finished. The term Console sounds like an implementation, not a role. Most of the sword-wielding adventurers that I know don’t know how to work a Console, but they’re quite happy to tell of their great deeds to, say, a Narrator (as David Peterson suggested). If we adjust our example we get.

describe Hero do
  it "should move to a room" do
    hero = Hero.new(narrator)

    room.stub!(:description).and_return("a room with twisty passages")

    narrator.should_receive(:says).with("in a room with twisty passages")

    hero.move_to(room)
  end
end

The whole example now reads as if it’s in the same domain, in the language of a D&D game. It doesn’t refer to implementation details such as a Console—we might see that code when we get to the detailed implementation of a Narrator. Obviously, there’s a lot more we could do, for a start I’d like to see more structured messages between Hero and Narrator, but the session ran out of time at about this point.

Some lessons:

  1. Naming, naming, naming. It’s the most important thing. A coherent unit of code should have a coherent vocabulary, it should read well. If not, I’m probably mixing concepts which will make the code harder to understand and more brittle to change than it needs to be.
  2. When I’m about to write a test, I ask “if this were to work, who would know”. That’s the most revealing question in B/TDD. If there’s no visible effect from an event, except perhaps for changing a field in the target object, then maybe it’s worth waiting until there is a visible effect, or maybe there’s a concept missing, or maybe the structure isn’t quite right. Before writing more code, I try to make sure I understand its motivation.

Willem’s (and many other people’s) approach is slightly different. He likes to explore a bit further with the code before really sorting out the names, and he’s right that there’s a risk of Analysis-Paralysis. I do that occasionally, but my experience is that the effort of being really picky at this stage forces me to be clearer about what I’m trying to achieve, to ask those questions I really ought to have answers to, before I get in too deep.

3 Comments

  1. […] Steve Freeman did a great writeup of the session Marc Evers and I hosted at the Software Craftsmanship Conference: Mock Roles not Objects, live and in person. […]

  2. […] “Specify as little as possible in a test”…”One of the risks with TDD is that tests become ‘brittle’, that is they fail when a programmer makes unrelated changes to application code.” This is on of the most common criticisms of TDD that I have heard from other developers. The paper goes onto say that the cause is that “…(the tests) have been over-specfied to check features that are an artefact of implementation, not an expression of some requirement in the object.” I’ve written tests that fall into in this category and I think it can be quite challenging to avoid doing so. Steve Freeman, one of the authors of the paper, blogged about this situation happening in a Coding Dojo earlier this year. […]

  3. Pete DiSalvo says:

    Hi Steve. I’ve been working very hard to improve the design of my code, and learn to take advantage of the semantic and architectural benefits of object-orientation via message passing and ignorance of implementation.

    I recently introduced myself to TDD hoping it might act as a guide to improve the design of my abstractions. However, I found state-based testing disappointing in terms of the eventual structure of my applications. I felt there was too much state and data flooding out of objects, and object protocols were unclear.

    I read through David West’s book “Object Thinking”, and was inspired to think more deeply on how to structure code into networks of communicating objects. Some searching on Google using the vocabulary I learned from his book led me to your “GOOS” book, which I’m currently in the middle of reading.

    I’m starting to understand the importance of “messages” and the idea of “tell, don’t ask (but sometimes ask)”. However, a concept that continues to puzzle me is related to this blog post. The concept is: How do you tell when you’re “telling” vs “asking”?

    In this post, you have a room object that you “ask” for its description. On the other hand, you could say you’re “telling” the room to provide its description. I look at this and think, maybe the room should be told to describe itself to the narrator, as in room.describeTo(narrator).

    Here is how I think about it…
    The meaning of the code changes as follows:

    Your version: The Hero wishes to tell the Narrator the description of the room he’s in. This version implies that the Hero must temporarily become custodian of the room‘s description in order to give it to the Narrator. However, the Hero doesn’t care about the description itself, only that the Narrator is told about it.

    My version: The Hero wishes the room to be described to the Narrator. This version implies that the Narrator receives the description of the room without needing to know the details of the description.

    In my version, the Hero depends on the Narrator, but for no other reason than to pass it to the room. Is this good? How do you tell? Also, this makes the Room dependent on the Narrator. Is this good? How do you tell?

    The interaction might look something like this (pseudocode):

    Hero {
    new(narrator){
    this.narrator = narrator
    }

    move_to(room) {
    room.describeTo(narrator)
    }
    }

    Room {
    describeTo(narrator) {
    narrator.describe("...")
    }

    }

    Narrator {
    describe(description) {
    // makes it happen
    }
    }

    When using “tell, don’t ask” I find that objects tend to take on more dependencies. My first thought is that these dependencies are okay and that this is a good opportunity to find new interfaces and protocols that describe the interactions (for example, if I thought narrator was too implementation-specific in room’s context, it could be abstracted into an interface that represents “something that receives room descriptions”). At this point, I normally backoff and decide that the objects are too tightly coupled and revert to what I consider an “asking”. However, I never feel confident using either style.

    I’ve seen other explanations of “tell, don’t ask” that say it really means not to query an object and then send a command to the same object based on the data you queried, and that it’s okay to “ask” objects for data if it’s used to perform further operations on other objects (as you’ve done in your version).

    I hope I’m not asking too much, but would you be able to provide some insight into this? It’s keeping me up at night.

Leave a Reply

Your email address will not be published. Required fields are marked *