Presenter First: Get your Triads Talking

Today I got an email from Sandro Aloisio asking an important question about the connection of one MVP (model–view–presenter) triad to another. When introducing the basics of Presenter First, one usually runs out of breath before getting to the topic of connecting triads using Managers (or Coordinators, whatever you call them), which is a technique that has grown up a little and proven to have some merit. So here’s a little more discussion on that front:

Q: There should be at least one MVP triad per user story, is that correct?

Yes, at least one triad for a user story is a good way to go, especially at the outset of a project. It’s worth pointing this out, as I have seen code written by folks who interpret Model-View-Controller patterns to mean your application should consist of exactly 3 gigantic classes.
One user story usually involves one or more like-minded statements that start with “when the user clicks Save” and “when the user clicks Cancel”. A subsequent user story might augment a feature by saying “when the user clicks Apply, save changes but don’t dismiss the dialog” which might involve going back to the old Presenter for that feature.

And it could happen that a small handful of innocent, related phrases from the same story are technically separated enough to make you want to compose more than one triad to answer the story. There’s nothing in the pattern (or our experience) that says this is a problem. At worst, you’ve added a little extra interface code. At least you’ve introduced that much more domain language into your code.

That second case comes up often when the actual verbiage from the customer covers a lot of ground, such as “I can double-click the user name in the list, change that user’s password, then save.” This implies a collection of smaller stories, such as an interactive user list, a password editor, etc. Decomposing the larger story into several related smaller stories gets you several related MVP triads which will need to interact according to the overall user story.

Q: What if a model from one MVP needs to know the state of a foreign model (in another MVP)?

The model-to-model communication you’re asking about is something we answer with the loosely-named “manager” pattern (naming of these objects varies from project to project, I’ll discuss that below). A Manager is structurally identical to a Presenter: it acts as an observer on two objects, and channels data and intentions from one to the other. The Manager exists only to do these things, and has no public API (same as Presenter) and nobody holds a direct reference to this object.

Managers come into existence when you recognize that a user story describes the interaction between two other story-level application features. You’ve already got a triad for each feature, and you’ve decided that the models from these features need to talk to each other. Responsibility and testability issues pop up quickly if you simply let the models reference one another directly, and even if you try to wire one model up to observe the other. (We’ve found that subscribing for, reacting to and processing input is indeed too much to do cleanly all in one class… Presenters lift a lot of this burden from our backs.)

A Presenter’s basic event-and-data brokering habits have freed you up to write much simplified View and Model code. Objects get to “wish” for things to make their testing easier, like “I wish someone would send this data to me, instead of my having to retrieve it, and knowing when”. if you take two models and put a Presenter-ish object between them (creating a new triad) you get to connect your models without overloading them too much. Additionally, you’ve got a specific place to transcribe the user story that connects these two features in the first place.

If you still feel like your models in this triad are starting to get somewhat heavy in their dual responsibilities, do not hesitate to elaborate on the relationship between the models by introducing more models, and perhaps more Managers to connect them. Don’t be frightened of the additional classes… if a problem has become complex enough to make you ask yourself if you need another class to get the job done, you probably do.

On naming:

In several large projects, we found that we wanted to reserve the word Presenter for that specific type of object that connects Models to Views (or Adapters, but that’s a different topic). Verbal design sessions are easier when the words always mean the same thing. In our seach for terms that mean “Presenter-like object that connects models to models” we’ve used Manager, Conductor and Coordinator. We tend to refer to this aspect of Presenter First as the “coordinator pattern” or “manager pattern.”

When choosing a specific name for a Manager object, try naming it directly for the feature the object will enabled. Eg, you might connect the UserListModel and PasswordEditorModel via the UserPasswordEditorCoordinator.

Conversation
  • Orfeo says:

    Great article!

    A question…you wrote:
    “(Manager).. acts as an observer on two objects, and channels data and intentions from one to the other.”…well , my question now is “how can I do this”?

    So, an example, I’ve IAModel and IBModel and BModel must know the value of A property Foo:

    // IAModel
    event System.EventHandler FooChanged;
    string Foo {
    get;
    set;
    }

    // IBModel
    void Bar {
    // Use A.Foo property
    }
    // Placeholder for A.Foo value..see coordinator
    string Foo {
    get;
    set;
    }

    I’ve created a ABCoordinator :

    // ABCoordinator
    public class ABCoordinator {
    private IAModel aMdl;
    private IBModel bMdl;
    public ABCoordinator(IAModel a, IBModel b) {
    this.aMdl = a;
    this.bMdl = b;
    this.aMdl.FooChanged += delegate(object o ,EventArgs e) {
    this.bMdl.Foo = this.aMdl.Foo;
    };
    }
    }
    When A.Foo property change, it raises FooChanged event and the coordinator copies the A.Foo value in B.Foo
    What do you think? It’s correct?

    Thank for your attention!

  • peter says:

    Who creates the coordinator/manager object?

    If a model needs to react to events from another model, then a presenter-like class seems like a good solution but who has the responsibility for creating this? One of the models? Then they must know about the other model…Some type of DI framework that wires up your dependencies from XML?

  • David Crosby David Crosby says:

    Orfeo: Yes, I think you’ve got it. Your “event resolution” may vary… depending on the size and time cost associated with accessing data in your models, you may choose to define more or less refined events, such as “ModelDataChanged” in a very broad case, or something as specific as “FirstNameChanged”.

    peter: Yes, we almost always use dependency injection tools to construct and wire our model/view/presenter triads. We’ve used everything from huge, custom bricks of code that build and compose all system objects to using tools like Spring, Structure Map, DIY, etc.

  • Josef Karthauser says:

    Hi there, I’m new to Presenter-First, and I have to say that I love it. Thanks.

    How do you propose to link views together? The scenario I have in mind is a view with two widgets in it and objects that I want to drag and drop between them. Each widget is part of a MVP triad. But it also seems that the presenter controlling the drag and drop needs to connect those same views. How does that fit into PF?

    Thanks.

    • David Crosby David Crosby says:

      Josef: In some cases like this, have connected Views together with an additional Presenter, essentially making that View participate in another triad. The Presenter may connect the two views you mentioned, or indeed another Model that drives the semantics of whatever you’re dragging and dropping. (In languages where we’re making heavy use of nterfaces, the View would implement a new interface geared toward drag-n-drop support, not necessarily overlapping its implementation for the already-existing triad it participates in.)

  • Comments are closed.