Jeremy D. Miller -- The Shade Tree Developer

Sponsors

The Lounge

Syndication

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Build your own CAB Part #4 - The Passive View

When last we left our brave companions, between courses of cheese and fine wine, Athos was sharing his strategy for dividing screen responsibilities by employing the Supervising Controller pattern.  Mighty Porthos suddenly cleared his throat and exclaimed "since I am the strongest man in all of France, I would face my opponents a different way.  Because the View itself is the trickiest piece of code to test and maintain, I would squeeze the View with great force until the only thing left inside the View is a mere skeleton of presentation logic.  I will render the Lady de Winter's greatest warrior a mere...

Passive View

Last time we looked at a small screen that allows a user to select options for configuring the shipment options for some sort of online order.  We examined a sample approach utilizing the Supervising Controller variant of Model View Presenter that left the View in charge of simple screen synchronization while utilizing an external Presenter class to handle more complex behavior and all communication with the rest of the system.  This time around we're going to build the exact same system, but use the Passive View variant of Model View Presenter.

It's probably easiest to explain Passive View by first explaining how it's different than Supervising Controller.  The goal of the Passive View is to maximize the ability to automate testing of the screen, and that means taking as much as possible out of the hard to test View code and moving it to the Presenter.  For that reason, the biggest difference is the reduced role of the View -- even from the already slimmed down View attached to a Supervising Controller.  The Presenter/Controller is responsible for all screen synchronization.  The View in Passive View is an extremely thin wrapper around the presentation details with next to no behavior of its own.  The view probably doesn't even know about the Model classes.  To start the Passive View solution, let's look first at the interface for IShippingScreen:

    public interface IShippingScreen

    {

        string[] ShippingOptions { set; }

        string[] Vendors { set; }

 

        bool InsuranceEnabled { set; }

        bool SignatureEnabled { set; }

 

        string StateOrProvince { get; set;}

        string Vendor { get; set;}

        string ShippingOption { get; set;}

        bool PurchaseInsurance { get; set;}

        bool RequireSignature { get; set;}

        double Cost { get; set;}

    }

As you can probably guess from this interface alone, the View becomes simplistic.  The Presenter is now responsible for telling the view what piece of information to put into each UI widget.  The concrete View is going to end up looking something like this:

    public partial class ShippingScreen : Form, IShippingScreen

    {

        public ShippingScreen()

        {

            InitializeComponent();

        }

 

        public string ShippingOption

        {

            get { return shippingOptionField.SelectedText; }

            set { shippingOptionField.SelectedText = value; }

        }

 

        public bool PurchaseInsurance

        {

            get { return purchaseField.Checked; }

            set { purchaseField.Checked = true; }

        }

 

        // Who sees a problem here?

        public double Cost

        {

            get { return double.Parse(costField.Text); }

            set { costField.Text = value.ToString(); }

        }

 

        // Stuff that we don't care about

        #region Stuff that we don't care about

 

        #endregion

 

    }

At this point, the view is as dumb as we can possibly make it.  It should be nearly trivial to verify the functioning of the View code by simple inspection -- for the most part anyway.  We could easily decide to forgo testing the actual View itself at this point and judge that to be a perfectly acceptable compromise.

The Presenter is now more complicated because it's taking on the additional responsibility for synchronizing data between the screen and the Domain Model.  In this case it's making a one to one transference of properties from the screen elements to the properties of the Shipment class.

        private Shipment createShipmentFromScreen()

        {

            Shipment shipment = new Shipment();

            shipment.PurchaseInsurance = _screen.PurchaseInsurance;

            shipment.StateOrProvince = _screen.StateOrProvince;

            // so on, and so forth

 

            return shipment;

        }

For a small screen, that's not that bad.  In reality, I generally use Passive View for small screens like login screens.  I do find the screen synchronization to be a chore.  Then again, think about the case of a screen that serves to display and edit an aggregate object structure with multiple levels of hierarchical data.  Data binding works best with "flat" objects, so you've got to do something.  In my mind, sacrificing the structure of the business domain to fit the user interface tooling is mostly a poor compromise.  To have the best of both worlds you can either create a wrapping object to provide a "flattened" view of the object hierarchy to allow data binding to work, or skip that and use Passive View to have better control over the screen synchronization. 

What is cool about Passive View, besides the extra testability, is a further set of insulation between the presentation technology and the business and service layers of the application.  When I built the Supervising Controller approach, I deliberately used an object specifically built for the data binding and hid the "real" domain behind IShippingService.  This time around, let's let the Presenter work with the "real" domain classes somewhat.  That being said, ShippingScreenPresenter will now interact with an IShipper class to get at the business rules for a particular shipping option. 

    public interface IShipper

    {

        bool AcceptsInsurance { get;}

        bool CanRequireInsurance { get;}

        string[] Options { get;}

        string Description { get;}

 

        bool CanCaptureSignature { get; }

 

        double CalculateCost(Shipment shipment);

    }

Of course, we've got to find the correct IShipper in the first place.  For that, we'll use a Repository:

    public interface IShipperRepository

    {

        IShipper[] GetShippersForLocation(string location);

        IShipper FindShipper(string shipperName);

    }

Even more so this time, the ShippingScreenPresenter is largely a Mediator between the interfaces exposed by IShippingScreen, IShipper, and IShippingRepository.  The screen synchronization can be more work inside the presenter, but I think you can get by with less abstraction of the rest of the application.  The ShippingScreenPresenter might look like this:

    public class ShippingScreenPresenter

    {

        private readonly IShippingScreen _screen;

        private readonly IShipperRepository _repository;

        private IShipper _shipper;

 

        public ShippingScreenPresenter(IShippingScreen screen, IShipperRepository repository)

        {

            _screen = screen;

            _repository = repository;

        }

 

        public void ShipperSelected()

        {

            _shipper = _repository.FindShipper(_screen.Vendor);

            _screen.ShippingOptions = _shipper.Options;

            _screen.InsuranceEnabled = _shipper.CanRequireInsurance;

            _screen.SignatureEnabled = _shipper.CanCaptureSignature;

        }

 

        private Shipment createShipmentFromScreen()

        {

            Shipment shipment = new Shipment();

            shipment.PurchaseInsurance = _screen.PurchaseInsurance;

            shipment.StateOrProvince = _screen.StateOrProvince;

            // so on, and so forth

 

            return shipment;

        }

 

        public void OptionsChanged()

        {

            Shipment shipment = createShipmentFromScreen();

            _screen.Cost = _shipper.CalculateCost(shipment);

        }

    }

Needless to say, using the Passive View pretty well demands an Interaction Testing style of unit tests with lots of mock objects.  If you don't grok RhinoMocks, Passive View might not be for you.  Supervising Controller is a definite alternative, but in a later section I'll take a look at the Presentation Model pattern for a state-based style of unit testing.

Interlude

Young D'Artagnan looks puzzled.  He finally asks his older friends "Wouldn't that make the communication between the Presenter and View very chatty?  And what's to stop the Presenter from becoming just as convoluted as an Autonomous View?"  Porthos snorts and exclaims "You are a perspicacious lad!  I would not stop with crushing the View into submission.  I will use my superior strength to crush the Presenter until it only contains a single, cohesive responsibility!"

Summary

I used Passive View quite extensively on my first WinForms project in 2004.  Overall, the experience hooked me for life on using Humble Dialog Box design philosophies for building fat clients.  It became routine for screens to work on the very first attempt to run new screen features -- assuming that you really did unit test the individual pieces first.  We also so another noticeable trend, screens that were fatter with more logic and less unit test coverage generated alarmingly more bugs and took much more time to debug.   

I mentioned that the screen synchronization can become a chore.  The presenter potentially picks up more responsibilities for screen synchronization and state like "IsDirty" checks.  The downside of Passive View is a chatty interface between View and Presenter.  I wrote an article early last year detailing my Best and Worst Practices for Mock Objects.  Most of the advice for what not to do with Mock objects came from that same project that we used Passive View.  My advice is to watch the size of the Presenter.  If it gets too big, split up responsibilities.  Maybe you take screen synchronization, IsDirty logic, and maybe validation and put it in some kind of "inner" presenter.  The "Inner" presenter talks to the View itself.  The "Outer" presenter talks to the "Inner" presenter and the outside world. 

One way to detect a need for this Inner/Outer presenter case is to watch your unit tests.  If you ever find yourself writing an uncomfortable number of mock object expectations in any one test, you're probably violating the Single Responsibility Principle (SRP).  If you find yourself setting up mock object expectations for something that's barely relevant to the subject of the unit test, you almost automatically split the class under test into multiple classes.  One of the best design tricks you can apply is to continuously move your design closer and closer to SRP.

Conclusion

The four friends finished their repast and sat around the fire, sated from the provisions generously supplied by a minor noblewoman of Atho's acquaintance.  Aramis, who the companions know is the craftiest of the four friends, speaks up:  "slaying a View of many responsibilities with the sharp edge of a mock object is a fine thing, but I think that we can use our wits to fool the screen into  subservience to state based testing by employing the Presentation Model to..."

To be continued in Part #5 - The Presentation Model -- unless you'd rather talk about something else.


Posted Wed, May 30 2007 10:17 PM by Jeremy D. Miller

[Advertisement]

Comments

GJK wrote re: Build your own CAB Part #4 - The Passive View
on Thu, May 31 2007 11:09 AM

As always, love the series of articles.  BUT could you please post some working source code.  What I am not understanding from reading about it I will learn from seeing it work.

Please.

Rick Donaldson wrote re: Build your own CAB Part #4 - The Passive View
on Mon, Jun 18 2007 10:24 AM

Could you post an example of a more complicated view being used? For example, if your form contains a treeview control, would you add AddTreeItem()/RemoveTreeItem() methods to the view interface or would you create a platform-independent treeview wrapper or perhaps something else?

Jeremy D. Miller -- The Shade Tree Developer wrote Build your own CAB Part #10 - Unit Testing the UI with NUnitForms
on Tue, Jun 26 2007 9:57 PM

I've long, long since left the rails of "Build your own CAB" topics and wandered off into

ShawnD wrote re: Build your own CAB Part #4 - The Passive View
on Wed, Jun 27 2007 12:38 AM

I LOVE the thin view dude!!!  Got all excited when finally seeing a view that does not have GUI Control Event Handlers (_checkedchanged events, _selectedValueChanged, etc.) and no reference to "_myPresenter" ...until I saw in the ShippingScreenPresenter class the method "public void ShipperSelected()"...surely the view still needs to have a "_myPresenter" variable, along with a call to "_myPresenter.ShipperSelected" in the cbxShippingVendor combobox's SelectedIndexChanged event?  Or am I missing something?  If I am correct, I guess this post is an affirmation of what GJK said on May 31st - please post more complete classes - not necessarily working code, but more complete classes will help affirm the concepts you are trying to get across - even if you include more comments in the classes like "this type of code goes here", "that type of code goes there"...that kind of thing - so that the whole picture is still kept in play.

Jeremy D. Miller wrote re: Build your own CAB Part #4 - The Passive View
on Wed, Jun 27 2007 5:15 AM
ulu wrote re: Build your own CAB Part #4 - The Passive View
on Thu, Jun 28 2007 3:35 PM

Jeremy,

First let me thank you for the great series. Not only your articles smart and clear, they are a big fun to read!

Now to the point. I recall that it is the very basic principle of OO programming that you shouldn't make your objects passive, instead, you should let the object maintain itself. Otherwise, you end up with a sort of procedural programming. Your View class seem to contradict this idea. Also, everybody says that anemic models are just bad, but what about anemic views?

Now, I absolutely agree that this model is much easier to test (with RhinoMocks and without NUnitForms), but here's another question that's been left unanswered elsewhere: should we design for testability, or should we try and test what's designed (perhaps designed badly, so we refactor later)?

Another thing that seems to be against the OO basics here: we are forced to make the InsuranceEnabled property public, which might be against our idea that other views (and presenters, and services) shouldn't be able to access this property. So, if we really want to keep the separation, perhaps a good idea would be to make the Presenter a private class of the View?

Jeremy D. Miller wrote re: Build your own CAB Part #4 - The Passive View
on Fri, Jun 29 2007 8:30 AM

@ulu,

I'm answering some of this in another post.

Making the View "Passive."  You might be reading that too literally.  The classic OO truism *is* to make the class with the data responsible for doing stuff to that data (Information Expert), but in this particular case I think that testability buys me more than encapsulation.  The View's responsibility is just to manipulate the Control state inside.  It's not like the Presenter is reaching into the View to set values directly on a CheckBox or TextBox.

Keep in mind that Passive View isn't the only way to do things.

"perhaps a good idea would be to make the Presenter a private class of the View?"

I'm not sure about your reasoning.  Offhand that seems to almost completely defeat the purpose of doing the MVP split in the first place.

Jeremy D. Miller -- The Shade Tree Developer wrote Designing for Testability
on Fri, Jun 29 2007 8:52 AM

From a question on my Passive View blog post : "should we design for testability, or should we try

Jeremy D. Miller -- The Shade Tree Developer wrote Build your own CAB #11 - Event Aggregator
on Fri, Jun 29 2007 11:12 AM

I will finish "Build your own CAB" at least before Acropolis hits and makes it all obsolete

ulu wrote re: Build your own CAB Part #4 - The Passive View
on Sat, Jun 30 2007 5:57 PM

@Jeremy

"I'm not sure about your reasoning.  Offhand that seems to almost completely defeat the purpose of doing the MVP split in the first place."

The View and the Presenter are still separate classes. So the split is there. All the methods and properties from your post are there. The idea is to make the Presenter a private class within View. So,  you can't call the methods of the Presenter from any other class but the View, but the Presenter still can manipulate the View, get the data from other classes etc.

But of course, testability could be a problem here. Perhaps a lot of reflection could do that. Of course, that depends on the situation. It might be that having methods like ShipperSelected() public is undesirable, and you are willing to make some extra effort and test a private Presenter.

Designing for Testability « Tuff Stuff wrote Designing for Testability « Tuff Stuff
on Wed, Jul 4 2007 4:39 AM

Pingback from  Designing for Testability « Tuff Stuff

Jeremy D. Miller -- The Shade Tree Developer wrote Build your own CAB #13 - Embedded Controllers with a Dash of DSL
on Fri, Jul 6 2007 12:40 PM

Just to continue the world's longest run on sentence. Before I start, here's the table of contents

Emad wrote re: Build your own CAB Part #4 - The Passive View
on Sun, Jul 22 2007 11:00 AM

I know I am late, but I need to ask this (till this moment...i haven't read the rest of the series...i hope i am not asking an answered question).

but, I am still caught in the place where you tie the events together; I have an event handler for changing the Shipper in which i will call ShipperSelected(), ok cool...now by consequence i will execute the line:

_screen.SignatureEnabled = _shipper.CanCaptureSignature;

but i expect that the Signature Check box will have an event handler that would say SignatureChanged or something (in the case the user changed by his choice), then...that is called..i will be recalculating the view because i would expect a code close to what exists in ShipperSelected().

in some cases we will have two controls that change each other in which we could have infinite loop. how to solve this in a good manner?

in the crazy code i ended up with (i know it's not the best answer...but it worked..and i want better answer that what i have)...i produce a flag ...that would tell me what was the cause of the data moving...(is it the users click?..or another control in the form)...if it was the user..i change it to THE control...and do the code..and then reset it to Neurtral.

i don't like this, is there better thing that suits the sweetly-though series?

thanks for your valuable posts,

Emad

Jeremy D. Miller wrote re: Build your own CAB Part #4 - The Passive View
on Sun, Jul 22 2007 7:03 PM
Jeremy D. Miller -- The Shade Tree Developer wrote Build your own CAB #14: Managing Menu State with MicroController's, Command's, a Layer SuperType, some StructureMap Pixie Dust, and a Dollop of Fluent Interface
on Tue, Jul 24 2007 5:18 AM

The title is a mouthful and accurately implies an alarmingly high jargon to code ration, but I just didn't

Jeremy D. Miller -- The Shade Tree Developer wrote The Build Your Own CAB Series Table of Contents
on Wed, Jul 25 2007 9:21 PM

Yes, this is overdue. Here is an introduction and table of contents to my "Build Your Own CAB"

Jeremy D. Miller -- The Shade Tree Developer wrote Build your own CAB #14: Managing Menu State with MicroController's, Command's, a Layer SuperType, some StructureMap Pixie Dust, and a Dollop of Fluent Interface
on Thu, Jul 26 2007 10:57 AM

The title is a mouthful and accurately implies an alarmingly high jargon to code ration, but I just didn't

Jason wrote re: Build your own CAB Part #4 - The Passive View
on Wed, Aug 1 2007 10:40 AM

My interpretation is that with the Supervising Controller variant the View Interface can take the Model (entities) as parameters but in Passive View (PV) it is limited to primitive types that map directly to the UI elements.

The question that I have is how you deal with grids etc. with PV? For example what if you have a List<Customer> and want to display in a pageable / sortable form. The ASP.NET GridView control is (deservedly) much maligned but you do get a lot of functionality for free.

Jeremy D. Miller wrote re: Build your own CAB Part #4 - The Passive View
on Wed, Aug 1 2007 12:06 PM

Jason,

All bets are off when you get to needing a Grid.  That alone will force you to a Supervising Controller.  I think 3rd party controls, and especially grid controls, are one of the last redoubts of untestable code.

The Evolving Developer wrote Passive View Architecture
on Thu, Aug 23 2007 4:28 PM

One of the new things we&#39;ve recently tried is the use of a Passive View architecture. The main idea

Jeremy D. Miller -- The Shade Tree Developer wrote Build your own CAB #15 - MicroControllers
on Sun, Oct 21 2007 9:13 PM

After a bit of a hiatus and a fair amount of pestering, I&#39;m back and ready to continue the &quot;Build

Todrom.Com » Build your own CAB Part #4 - The Passive View wrote Todrom.Com &raquo; Build your own CAB Part #4 - The Passive View
on Sun, Oct 28 2007 4:24 PM

Pingback from  Todrom.Com &raquo; Build your own CAB Part #4 - The Passive View

Jeremy D. Miller -- The Shade Tree Developer wrote Development Trivial Pursuit: The difference between MVC and the different flavors of MVP
on Wed, Oct 31 2007 9:12 PM

You can happily go your entire career without knowing the textbook definitions of either pattern and

Rod wrote re: Build your own CAB Part #4 - The Passive View
on Fri, Nov 23 2007 6:40 AM

Hi Jeremy,

The Best MVC-MVP article I've read!!! Good work!!!

After creating a sample project to put all interface into action by adding shell and UI I came up with the following questions:

1. Can we combine Passive View and Supervising Controller? Like in the case of the Shipping sample in Supervising Controller, can we add a Cost interface in IShippingScreen view inorder that everytime the Shipment_PropertyChanged event is raised in Presenter Cost field is automatically updated.

2. Is it a good approach to inherit a view interface(s) in another view to combine interfaces into one view. In my experiment I created a IFormView out of  the "The Humble Dialog Box" sample and I inherit IFormView in ISheepingScreen view (see Fig 1.0), that way when I inherit ISheepingScreen in my Form (UI) it will have the both ISheepingScreen and IFormView view interfaces (see Fig 2.0).

Fig: 1.0

public interface IShippingScreen : IFormView

{

....

}

Fig: 2.0

public partial class MyForm : Form, IShippingScreen

{

...

}

Fig: 2.1

public partial class MyForm : Form, IShippingScreen, IFormView

{

...

}

Do you prefer inheriting view (see Fig 2.0) or just inherit them separately in the Form (UI) (see Fig 2.1)

Thanks in advance!

Rod

Rod wrote re: Build your own CAB Part #4 - The Passive View
on Fri, Nov 23 2007 7:03 AM

Hi Jeremy,

I want to rephrase my #1 question, Adding Cost interface IShippingScreen view will violate the Supervising Controller pattern? or its a matter of Service vs. Repository/Domain?

Cheers!

Rod

Jeremy D. Miller -- The Shade Tree Developer wrote Resources from my DevTeach talks
on Thu, Nov 29 2007 12:03 PM

To everybody that attended one of my talks at DevTeach this week. All of the materials are now online

nblog wrote Tfs Spotlight – buduję własny CAB
on Tue, Mar 11 2008 7:07 AM

Od kilku miesięcy nic tu nie pisałem (oczywiście poza poprzednim nieplanowanym wpisem ). Jak łatwo się

http://www2.codebetter.com/blogs/jeremy.miller/archive/2007/05/30/build-your-own-cab-part-4-the-passive-view.aspx wrote http://www2.codebetter.com/blogs/jeremy.miller/archive/2007/05/30/build-your-own-cab-part-4-the-passive-view.aspx
on Tue, Apr 8 2008 11:25 AM
江南白衣 wrote View to Presenter Communication(转)
on Sat, Aug 2 2008 7:40 AM

Alright, I've purposely hid the View to Presenter communication in my previous posts on Supervising Controller and Passive View because I thought that subject was worthy of its own post. As I see it, there are 2 1/2 basic ways to communicate screen events

Presenter First ??? A bibliography « CodeForNothing wrote Presenter First ??? A bibliography &laquo; CodeForNothing
on Sun, Sep 7 2008 5:04 AM

Pingback from  Presenter First ??? A bibliography &laquo; CodeForNothing

Sam Gentile's Blog wrote New and Notable 168
on Tue, Dec 2 2008 9:42 PM

My four year old daughter, Heather, had her first ballet recital last night. It was a very proud moment for me. She had to wear a little makeup for the lights and with hair up, she looked beautiful but older and that was emotional. I have some things

Add a Comment

(required)  
(optional)
(required)  
Remember Me?