CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

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.



Comments

Rick Donaldson said:

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?

# June 18, 2007 10:24 AM

Jeremy D. Miller -- The Shade Tree Developer said:

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

# June 26, 2007 9:57 PM

ShawnD said:

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.

# June 27, 2007 12:38 AM

Jeremy D. Miller said:

# June 27, 2007 5:15 AM

ulu said:

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?

# June 28, 2007 3:35 PM

Jeremy D. Miller said:

@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.

# June 29, 2007 8:30 AM

Jeremy D. Miller -- The Shade Tree Developer said:

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

# June 29, 2007 8:52 AM

Jeremy D. Miller -- The Shade Tree Developer said:

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

# June 29, 2007 11:12 AM

ulu said:

@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.

# June 30, 2007 5:57 PM

Designing for Testability « Tuff Stuff said:

Pingback from  Designing for Testability « Tuff Stuff

# July 4, 2007 4:39 AM

Jeremy D. Miller -- The Shade Tree Developer said:

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

# July 6, 2007 12:40 PM

Emad said:

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

# July 22, 2007 11:00 AM

Jeremy D. Miller -- The Shade Tree Developer said:

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

# July 24, 2007 5:18 AM

Jeremy D. Miller -- The Shade Tree Developer said:

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

# July 25, 2007 9:21 PM

Jeremy D. Miller -- The Shade Tree Developer said:

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

# July 26, 2007 10:57 AM

Jason said:

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.

# August 1, 2007 10:40 AM

Jeremy D. Miller said:

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.

# August 1, 2007 12:06 PM

The Evolving Developer said:

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

# August 23, 2007 4:28 PM

Jeremy D. Miller -- The Shade Tree Developer said:

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

# October 21, 2007 9:13 PM

Todrom.Com » Build your own CAB Part #4 - The Passive View said:

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

# October 28, 2007 4:24 PM

Jeremy D. Miller -- The Shade Tree Developer said:

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

# October 31, 2007 9:12 PM

Rod said:

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

# November 23, 2007 6:40 AM

Rod said:

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

# November 23, 2007 7:03 AM

Jeremy D. Miller -- The Shade Tree Developer said:

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

# November 29, 2007 12:03 PM

nblog said:

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

# March 11, 2008 7:07 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Jeremy D. Miller

Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy previously worked as a systems architect building mission critical supply chain software for a Fortune 100 company and learned agile development practices as a .Net consultant at ThoughtWorks, one of the pioneers of agile development. Jeremy is the author of the open source StructureMap (http://structuremap.sourceforge.net) tool for Dependency Injection with .Net and the forthcoming StoryTeller (http://storyteller.tigris.org) tool for supercharged FIT testing in .Net. Jeremy's thoughts on just about everything software related can be found on his weblog "The Shade Tree Developer" at http://codebetter.com/blogs/jeremy.miller, part of the popular CodeBetter site. Jeremy is a Microsoft MVP for C#. Check out Devlicio.us!

This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP