- Presenter First Pattern (Part 2)

The Discussion

  • User profile image
    rojacobs - Presenter First Pattern (Part 2)

    Announcer: It's Monday, June 4th, 2007 and you're watching ARCast TV.

    Ron: Hey, welcome back to ARCast TV, friends. This is your host Ron Jacobs and today we're going back to Grand Rapids, Michigan to finish the second part, actually there's three parts of this because it was such a great conversation I couldn't stop.

    Some of you guys that are hardcore patterns junkie kind of people, you want to know how these guys think about architecting at the lowest levels of design. Well, today we're going back to Atomic Object to finish our discussion about Presenter First. And where we left off, we were just kind of wrapping up talking about the View and the Model and the Presenter, and we were talking about, "Where do you begin?"

    And I just said, "Don't you start with the user story?" And if you're an agile person you know all about user stories, if you're not, you're going to hear a little bit about that today. So let's go back to Atomic Object.

    David: Yeah, we found that in addition to creating a nice, insulating layer between models and Views and some application models and other application models, that the Presenter is an excellent place to start, writing code based on a feature that has been asked for by your customer.
    Scott: "Presenter First" is not just a clever name. [laughter]
    David: It's meant to be the place where you would start writing tests, they're very easy tests to write and very easy to implement. You can be done with your average Presenter object within an hour of conceiving it, after you've had the design discussion with the customer and the other developers.

    They don't take very long to write because they get to operate in terms of interfaces that have not been fulfilled yet. They define new interfaces. I need a View that will do this, this, and this, and provide these events. And I need a model that will do this, this, and this, and emit these events.

    And if I had those two objects, we'd be done. And that is what the Presenter is saying, and so you write him, you lock him down -- you write as tests and you lock him together and you have expressed the user's desires in your code and all that's left is two weeks worth of work to fill out all those models and write all those GUI elements to fulfill those needs.

    So, your domain objects are going to flow through the plumbing, which your MVP triplets create. Users won't be wired in to a Presenter, won't be wired in to a View, and they won't be the Model, necessarily, but the Model will transmit them, or hold them, or erase them.

    And the Presenter is kind of like the pump that moves them from point A to point B.
    Ron: In one of the papers I looked at, Fowler's written a paper called the "Passive View" and he talks about, as he uses as an example a little four map that shows readings of ice cream particulate matter in the atmosphere. [laughs]

    And so he's saying, you go out and you take readings, you get these ice cream particulate matter so he did not tell any user stories in his paper, but I began trying to imagine some, you know maybe, "I'm going to open an XML file that has a bunch of these readings that were taken by a device somewhere, and so I want to open and review these readings. That's all I want to do. "

    Maybe that's a simple user story. Right, so if that were the user story, so you and I would sit down, we'd talk about it, we'd go, "Yup, that's what we want to do." And then you'd say, "OK, and now I'm going to write the Presenter." Where do you go from there?
    Scott: Well, before we get into that, something that you said is one of the keys to making this worthwhile, and that's writing good user stories.

    [general agreement]

    I think that in many cases, we're educating our client on methods of writing user stories as much as we're developing software for them.

    A lot of times, we work with clients who at some level know what it is that they want to accomplish but have a hard time expressing what it is that they want. I mean this is pretty difficult in software development. So you spend a lot of time at the beginning working with them to hone their ability to describe their desires in user stories. When those get written well, then the rest of it flows a lot easier.

    In the paper one of the keys is to use the word when. When this happened I want this to happen. If you can write most of your user stories in that cadence then it fits into the MVP pattern pretty well and the development goes pretty smoothly.

    So in your particular example, where you want to see the readings from these files displayed graphically in something, a good user story might be, "When I select this file I see the readings displayed on this graph."
    Ron: OK, so let's say that's the user story and it's not really a graph. Maybe there's a set of readings and I pick a particular one so I see the details for that reading and maybe some controls for that day. So where would you go from there?
    David: I would break your whole statement into two stories. When a file has been loaded display the readings in an overview listing. When one of those is clicked then display it in detail in the next pane over. So it's two user stories.

    I would start with the Presenter for...actually you could do both in parallel...I think we have done that. Anyway, the first Presenter for the list subscribes for an event from...

    Let's simplify it. Let's say that there is an.xml file loading widget in the View that you can just use. When the users have gone through a cycle and selected that file then that file name becomes available.

    So, the Presenter listens for an event in the View, subscribes for the event that a user has selected a file. If he takes the file there might be a name that he wraps in a file object. Some small translation does occur from time to time. He essentially takes the file name and sends that to the model. Conversely the Presenter is listening for the Model. When the data set has changed, when the readings change, he retrieves the new set of readings data and sets that into the View.

    So two events. One coming from the View, through the Presenter, to the Model to trigger some sort of file loading. How that happens is not our concern at the moment. Then we also listen for how the data has changed. How that event is emitted is not important, just that it is and that is what the Presenter wants.

    So the View requires that both the Model and the View have an event and some sort of input to except data or retrieve data. That is a really simple Presenter to write using mock objects. Define the View's interface. Define the Model's interface. Mock out those two objects in the test then trigger events from the mocks and observe that data was retrieved from the Model and put into the View.

    You then trigger an event in the View and you'll see that the file name gets retrieved from the View and sent to the model. Perhaps half and hour to an hour is all the more it takes to create that Presenter once you are in the swing of it.
    Ron: Hold right there. We just introduced something that a lot of people are thinking whoa, what is he talking about.

    So the concept of a mock is crucial to getting this right. A lot of people don't know what that is. I know you think everyone should know what that is, but it's true that a lot of people don't know. You mentioned an important thing, so let me back up.

    We talked about an interface. So I have an interface to my view. My I-reading View is going to show me the readings. You said lets assume to begin with that this thing knows how to tell me when the user has entered a file name.

    Let's make it real simple and say that all the user does is type in the file name. Somehow tells me here's a file name. Presenter really doesn't do anything with that file name except say, "Hey Model, go get the data from this file." Right? So then you'll have an interface for the eye readings model. It says, "It has a method that allows me to pass it a file name." So, then it's going to go off, and do whatever it does. OK, so I got those two things.

    Then the Model is going to go off, and after it loads this data... So instead of returning from, "Get file name. Here's your data," that's the wrong way to think about it.

    The right way to think about is the model goes off and changes, and then it tells me, "Hey, the Model's changed." Cause no matter what, if the Model changes, we have to tell the View to display it, even if it changed for some other reason. Right?
    Scott: Exactly.
    Ron: OK. The thing that I think is interesting here is, it helped me to focus first on the interactions and behaviors, more than the typical way where people do this. Which is, "Oh, well let me start drawing a dialogue. Here's our forum, here's our button, here's our..." Like that's where most people begin for this kind of app.
    Scott: Yeah, and in fact in a typical development cycle for a story in VP development, the View will be the last thing you do.
    Ron: Yeah, because then you always find people are like changing their mind about, "Oh, I don't like that widget there."
    Scott: [laughs]
    Ron: "Can we make it over here, use a different kind of widget," and all that kind of stuff.
    Scott: Yeah. In fact usually we'll make the first view iteration very simple--functional, and nothing more...
    Ron: Yeah.
    Scott: ... and present that to the client. Maybe half the time they'll say, "Yeah, that's what I was looking for." So, we just saved all that time that we might have spent really doing something special with the View.

    The other half the time they say, "Well no--I want to do this, and I want to do that." Well that's no problem, then we just modify the View. Assuming the data flow hasn't changed, then all we have to do is change this dialogue or this window, and nothing else about the application--no other change.
    Ron: You know what's funny about that is that it reminds me of when I first started doing Windows programming way back in the early '90s. I remember once spending -- I'm embarrassed to say this.
    Scott: [laughs]
    Ron: I remember once like spending half a day drawing a button during traffic.
    Scott: Doing the "About Box."
    Ron: No, no.

    Ron: I did a lot of those, but just the graphic for a button. I was trying to get this thing right, I'm using "Paint" and setting pixels.
    Scott: Yeah.
    Ron: I'm like, "Oh, that looks really cool. No, we can make it look like this." I spent all this time on this stupid graphic. [laughs] But, this is the kind of thing you get wasted hours on stuff that doesn't matter.

    So, when I was first looking at your paper it occurred to me that one of the things that I've spent a lot of time looking at is, kind of service orientated architecture and web services. We talk a lot about in that environment sort of contracts--making good explicit contracts that will find the behaviors you want as a means of encapsulation.

    It seemed to me that you almost have the same thing going on here, that there's really a contract between the View and the Presenter, or the Model and the Presenter also. They're contracts that you're establishing.

    So instead of the Presenter saying, "Hey, take this reading value, and stick it in textboxa.text." Right? Like the Presenter doesn't know if there is a text box "A" or what it is, or anything--like it doesn't care.

    It says, "There's a contract that the View has, " and the View tells me, "Here's a set of the reading value." That's all I know, "Set reading value." It could go into a graph, it could go into a text box. It could go into some other unknown widget--don't know what it is--don't care. All I need to know is where do I put it, and then the View decides what to do with it.
    Scott: That's right. It's the interface that defines that contract. It defines all the public methods that are available, like on a model they'll be a lot of setters, and a lot of getters. It also defines the events that this object could possible generate.
    Ron: Right.
    Scott: A typical Model event is just a update event. Essentially meaning the data that I contain has changed, and that will be the event that the Model fires. It's the Presenters job to capture that event, to interpret what it means. What it means is, I go get the data the Model using its getter and I put it into the View using the View set.
    David: Sounds almost too simple to bother with, [laughter] but the part that really makes it at a coding level very nice is that you get to say that those are the correct methods to have on your Model and View, at least so far.
    Scott: Before they exist.
    David: Right, as opposed to when you writing a Presenter reading through the EPI specification for a Model that someone else built and finding out what methods exist here, and how can I use that to create meaning for myself, as opposed to imposing meaning downward and saying its your problem. Do as I require you to do, assuming that you're willing to be implementing your own models.

    Sometimes our Model implementations are very thin wrappers around otherwise very complete third party vendor packages. This guy's got most of what we need. He doesn't have the events that I need necessarily so I have a very, very thin wrapper around him. The fact that that third party library is the actual class that's doing most of the work is hiding from us. In.NET all of our views are essentially subclasses of other.NET components. But we refer to them by their interface.

    The Presenter is wholly unaware that it is a.NET component. They can't even exploit the fact that this thing has a width and height because its not part of that public interface. So he's been kept ignorant. He says I demand a view of these three or four methods, and then all the actual code that goes into the View and the code that goes behind the scenes in the Model is somebody else's job, or your job for later.
    Ron: You know one of the interesting things in Fowler's example about the ice cream reading? He threw in this little interesting problem and that is in the user story says that if you visualize this reading there's a field witch is calculated it the variance so you have what the reading is what the target is and then there's the variance so the variance field is calculated first question is where do you do the calculation.

    So a lot of people in the past would have said oh well when I set that value on the text box I'll just do the calculation on the View. Which would be a bad idea for test involvement because then you've got some what effectively is calculations because the way you do the calculation could change over time or whatever. You would never want to put that in the View would you?
    Scott: No, absolutely not and depending on the complexity of the calculation it would either be encoded directly into that Model or if it was something simple like average these two numbers together, or if it were something more complicated that involved getting some data from a data base.

    Or maybe something complicated then the Model would have some helper class that it gets injected with and it just users that and it will pass whatever data the calculator needs down to it and just make one method call through that helper's interface, and retrieve the information.
    Ron: So the rule is business logic does not belong in the View, but also does not belong in the Presenter.
    Scott: That's right. The Presenter really is an implementation in code of a user story.
    Ron: OK.
    David: Application behavior as opposed to business logic.
    Ron: OK and then he throws another very interesting wrinkle in which the user story says that if the variance this calculated value is more than ten percent above the target I think its above I don't remember if its above or below it doesn't matter if its more than 10 percent above the value is supposed to be displayed in red if its more than five percent below its supposed to be displayed in green.

    It's sort of a business rule that deals with how this is visualized. This is a interesting problem because we have this kind of a business rule which business rule being applied equals business logic but the effect is visual not just the calculated value, so what do you do with that one?
    David: This is where the difference between using your models as data models versus application models really becomes evident in a sense that we have a body of data representing the readings, or a specific reading in its recorded form, the data structure with fields set to certain values.

    And that is mostly what we want to display on the screen. Except for we've got a variance, which is a calculation, not a value, on that structure. And now you've got some sort of a visual cue that is a result of a calculation, but otherwise, just purely visual.

    The data that we would push from the Detail Panel Presenter would be extracted from the Model and gotten into the View when the Model announced the change to that data. But the structure of that data would be a decorated version, or a wrapped version, of a core reading object.

    And it would have already set upon it a pre-calculated variance, and perhaps, if it's just that one visual trick that we needed to pull, a flag that says whether or not the variance is to be colored red, or perhaps, a color field, or, for more sophisticated scenarios, a color model object that maybe an adapter between the Presenter and the Viewer could translate by looking up.

    I have 10 fields that I need to render to the screen, any of which may potentially be a different color, based on complex business rules--analysis of the data, calculations, perhaps even relationships to other individual reading objects, of which we're not directly concerned with right now.
    Ron: Oh, OK.
    David: We're writing an application currently that shows CAN frames from vehicle communication bus, in the same way that the Ethereal program shows Ethernet frames. And any one of these packets might be related to another packet. It's a multi-part message, and you click on that row, and you need to see the related objects showing up green. And the logic needed to correlate these two messages is sometimes really, really involved, and it requires analysis of an entire log's worth of data, in advance...
    Ron: Oh. Uh-huh.
    David: And we send the items out and send out a color model to make that available. And that was all part of our application behavior data, or application logic. Using application behavior data would be some sort of massaged version of core data--that being log data, that being ice cream reading data.

    And the Presenter would barter in that information. He would trade that up and down from the View in the Model. In the case of the ice cream problem, we don't have any data coming in from the View yet.
    Ron: Yeah.
    David: We haven't heard any stories yet that say, "Allow the user to adjust readings or change data."
    Ron: OK. I like what you just said there, so let me see if I got it. That if there's something about the visualization of data that requires interpretation, let's say, through some kind of complex set of business rules or related events or whatever, that becomes a bunch of code that we don't want to put in the View...
    David: Right.
    Ron: But we want to pass along to the View so the View can just say, "Hey, go figure that out for me through this adapter."
    Scott: It's close to that. I wouldn't say that we pass it to the View, but rather, the Presenter, instead of talking directly to the View, would talk to this intermediate object that we typically would call an adapter.
    Ron: Oh. Oh, OK. OK. So then the adapter would push it into the View.
    Scott: It'd be the adapter's job to know, using business logic, how to translate this data into more simplistic data that we can push into the View.
    Ron: Oh, OK.
    Scott: So in the color example, you might get some code from the model, saying that it's above this value or it's below that value. There wouldn't even necessarily be any color information in there. It would just be a flag, or a trigger, saying that, "It's above this range or below that range. That's my job, is to tell you whether it's in one range or the other."
    Ron: OK.
    Scott: So that gets thrown up into the Presenter. The Presenter then passes it into the adapter.
    Ron: Yeah.
    Scott: It's the adapter's job to know, in this case, that, "OK, for this range, I tell the View red, and for this range, I tell the View green."
    Ron: Ahh, OK.
    Scott: So in that respect, we continue to keep the View as simplistic as possible. There might be one additional method on the View, called setTextBoxColor.
    Ron: Yeah.
    Scott: And the adapter would know how to interpret the range.
    Ron: So, again, we let the model handle the business logic, the interpretation of the range, to flag it somehow, right?

    The model is handling that. But a visualization rule, if you will, like make this green or red or whatever, belongs in the adaptor. And the View is just dead, dead simple. [laughs] Right? OK.
    David: There is a level of complexity that will usually prompt us to make and insert an adaptor between a Presenter and a View. And sometimes, what I was trying to initially, was that the model would actually take that on to himself in a simpler case.

    Whereas, if you had a more complex case with a lot more possibilities, it wouldn't just be black or red, but the actual color is for in-range and not abounds, is a user-configurable option from some other menu in the application.

    You've got a lot more to bring in, the adaptor might have references out to some sort of global color model, or preferences. And so it's important that the adaptor is in the realm of testable code. So that he can be complicated and use other complicated items as well.
    Scott: Yeah, there is definitely a level of pragmatism involved. If it were literally something as simple as you said, then yes, the model would probably just pass some sort of color information up and that would get sent directly to the View.

    But in an ideal world or if it were more complicated than that simple example, then you would definitely want to extract out those additional elements.
    Ron: So now, if I were on your team and I'm writing this code - and we're paired programming -- and I say, "Hey, I think down the road, this customer is going to want the ability to configure what the ranges are. So I'm going to create this adaptor now because I think they might want that in the future." What would you say to that?
    Scott: Well, the textbook answer, of course is, "Well, no, you don't know you're going to need that yet, so we're not going to do that until it becomes necessary."

    But again, there is definitely a level of pragmatism that gets involved there. I don't want to say, "If you know for a fact," but if you know at a certain level of likelihood that this is going to be needed and it's not a hugely complicated thing to put together, then you might go ahead and do it right then.

    But if it was a large complicated thing to have to put together, or you weren't entirely certain that you were going to need it down the road, then absolutely. You would say, "Well, we're not going to worry about that now. We're going to do it as simple as we can to get this story working and if we need it next week, it's not that big a deal to refactor it out into an adaptor class."
    David: You would treat it like a thought experiment. Well, let's say that the customer is going to do this in two days. We have a choice right now; which choice is going to make it harder to adapt later?

    And sometimes, it's an answer of, "The model is already doing what it needs to do for today. We need to add one field to it and tests are simple to update, so let's just finish them out."

    Versus, "Well, we haven't started them all yet" or "we haven't had that code for the models. Tests are already a little hairy; we can go put it here."

    But it would be a matter of, if we pick one path, is that going to make it really hard? Because we're picking a different metaphor that doesn't line up with what the user's likely to want tomorrow.

    Don't pick that route. There is usually a middle road. Like this one: this choice leaves us open to these possibilities. The whole Presenter-first pattern is really kind of geared around that idea in the first place, unless you do what you need to do today without cutting off what you might need to do tomorrow.
    Ron: OK. So, I was just thinking we got off topic. I was going to talk about mocks and we never did.

    [sound effect]
    Ron: Oh, I'm so sorry. We were just going to talk about mocks and we hadn't gotten to it. And I just said, "Oh, we are out of time."

    We are way out of time, but we'll have more from Atomic Object as we go and talk about what all this mock object stuff is. Not that I mean to mock you but, please, come back for one more ARCast. We'll get to that.

    Have you heard about this Microsoft Surface thing? I have to tell you that is way cool. If you're wondering what it is, go to and just check out some of their videos.

    Now, I don't mean for this to sound like an infomercial, but I'm genuinely excited about this. I think it represents one of the first really innovative things we've seen in computing. I mean, world changing, kind of like the introduction of the mouse or the introduction of the GUI. It's huge. Possibilities. I can't imagine what it's going to be like.

    Anyway, I'm just ranting about that because I've been watching it. It's so cool.
    Announcer: ARCast TV is a production of the Microsoft Architecture Strategy Team:

Add Your 2 Cents