Build your own CAB Part #2 – The Humble Dialog Box

When last we left our hero, D’Artagnan was chasing the evil Lady de Winter across the breadth of France trying to intercept her on her dastardly mission when he found himself beset by disparate responsibilities within the tight confines of a single autonomous view with no room for sword play.  D’Artagnan, being a perspicacious young man, quickly sees a way to separate the numerous concerns he’s facing by opening his attack with…

The Humble Dialog Box 

I’d say the very first concept to grasp in software design is separation of concerns.  Divide and conquer.  Eat the elephant one bite at a time.  Learning how to decompose a bigger problem into a series of approachable goals.  I’d rather work serially on a screen by completing one simple task before moving onto the next instead of working with all aspects of a screen in parallel.  Division of responsibility for easier programming is a major consideration by itself, but there’s another piece of motivation almost as important.  Because user interface code can be very complex to debug and is prone to change based on user experience, I really, really want to extend granular unit testing with automated tests as far into the presentation layer as I possibly can. 

Traditionally, user interface code has appeared to repel all but the most serious attempts at test automation.  Automated testing against UI code was just flat out deemed too much work for the gain.  That equation has changed over the last several years with the rise of architectures inspired by The Humble Dialog Box from Michael Feathers. 

Here’s the canonical example of the Humble Dialog Box I use to explain the concept.  Say you have a user screen for some sort of data entry.  You have a requirement that reads something like:

If the user attempts to close the XYZ screen without saving any outstanding changes, a message box is displayed to warn the user that they are discarding changes.  If the user wishes to retain the outstanding work, do not close the screen.  The message box should not be shown if the data has not been changed.

It’s not that complex of a requirement really, but it’s the kind of thing that makes a user interface client easy and convenient to use.  We want this code to work.  The code for it might look like this:

        private void ArrogantView_Closing(object sender, CancelEventArgs e)

        {

            // Let’s not worry for now about how we figure out the screen has unsaved data

            if (isDirty())

            {

                bool canClose = MessageBox.Show(“Ok to discard changes or cancel to keep working”) == DialogResult.OK;

                e.Cancel = !canClose;

            }

        }

That code really isn’t that complex, but let’s think about how we could automate a test for this requirement to run within our regression test suite.  That little bitty call to MessageBox.Show() and the modal dialog box that results is a serious pain to deal with in an automated test (it is possible, and I’ve done it before, but I’d strongly recommend you keep reading before you run off and try it).  Observing the UI getting closed or not is also tricky, but I think the worst part is that to test this logic you have to fire up the UI, navigate to the screen, change some data on the screen, then trigger the close screen request.  That’s a lot of work just to get to the point at which you’re exercising the code you care about.

Now, let’s rewrite this feature as a “Humble” view, but before I show the new code, let’s talk about the Humble view philosophy.  The first thing to do is to put the view on a diet.  Any code in a WinForms UserControl or Form is almost automatically harder to test than it would be in a POCO.  A Humble view should be the smallest possible wrapper around the actual presentation code.  Going farther, I don’t want implementation details of the view mechanics to leak into other areas of the code, so I want to hide the View behind a POCO-ish interface.  All that being said, the abstracted interface for our View could look like:

    public interface IHumbleView

    {

        bool IsDirty();

        bool AskUserToDiscardChanges();

        void Close();

    }

The view is also “passive,” meaning that it doesn’t really take any actions on its own without some sort of stimulus from outside the view.  I’ll discuss handling user events in depth in a later chapter, but for now let’s just say that the view simply relays user input events to somewhere else with little or no interpretation. 

One of the goals of a Humble view is to separate responsibilities.  As in most designs, we want to assign different responsibilities to different areas of the code.  In this case, we want to pull behavioral logic out of the view and into non-visual classes.  If we put the view itself on a diet and pull out anything that isn’t directly related to presentation, that extra code that implements things like behavior and authorization rules has to go somewhere.  In this case we’re going to move those responsibilities into a Presenter class:

    public class OverseerPresenter

    {

        private readonly IHumbleView _view;

 

        public OverseerPresenter(IHumbleView view)

        {

            _view = view;

        }

 

        public void Close()

        {

            bool canClose = true;

            if (_view.IsDirty())

            {

                canClose = _view.AskUserToDiscardChanges();

            }

 

            if (canClose)

            {

                _view.Close();

            }

        }

    }

In particular, look at the Close() method.  Some user event causes a call to the OverseerPresenter.Close() method.  Inside this method we check the “dirty” state of the IHumbleView member and potentially ask the user to discard changes before proceeding to close the actual view.  It’s just about the exact same code, only now we can write an automated unit test to express this logic — with just a little help from our good friend RhinoMocks.

    [TestFixture]

    public class OverseerPresenterTester

    {

        [Test]

        public void CloseTheScreenWhenTheScreenIsNotDirty()

        {

            MockRepository mocks = new MockRepository();

            IHumbleView view = mocks.CreateMock<IHumbleView>();

 

            Expect.Call(view.IsDirty()).Return(false);

            view.Close();

 

            mocks.ReplayAll();

 

            OverseerPresenter presenter = new OverseerPresenter(view);

            presenter.Close();

 

            mocks.VerifyAll();

        }

 

        [Test]

        public void CloseTheScreenWhenTheScreenIsDirtyAndTheUserDecidesToDiscardTheChanges()

        {

            MockRepository mocks = new MockRepository();

            IHumbleView view = mocks.CreateMock<IHumbleView>();

 

            Expect.Call(view.IsDirty()).Return(true);

            Expect.Call(view.AskUserToDiscardChanges()).Return(true);

            view.Close();

 

            mocks.ReplayAll();

 

            OverseerPresenter presenter = new OverseerPresenter(view);

            presenter.Close();

 

            mocks.VerifyAll();

        }

 

        [Test]

        public void CloseTheScreenWhenTheScreenIsDirtyAndTheUserDecidesNOTToDiscardTheChanges()

        {

            MockRepository mocks = new MockRepository();

            IHumbleView view = mocks.CreateMock<IHumbleView>();

 

            Expect.Call(view.IsDirty()).Return(true);

            Expect.Call(view.AskUserToDiscardChanges()).Return(false);

 

            // No call should be made to view.Close()

            // view.Close();

 

            mocks.ReplayAll();

 

            OverseerPresenter presenter = new OverseerPresenter(view);

            presenter.Close();

 

            mocks.VerifyAll();

        }

    }

So I know what you might be thinking, what have I really gained here?  Let me try to answer this:

  • Orthogonality.  We’ve moved behavioral logic out of the actual view.  We can change the presentation or the behavior independently.  That is a big deal. 
  • The screen behavior is easier to understand.  I’m going to argue that this is a case of Reg Braithwaite’s Signal to Noise Ratio in code (basically, expressing the intent of the code with little code that isn’t directly related to the intent).  When I want to understand the screen behavior, that behavior is the only signal I care about.  Seeing (object sender, CancelEventArgs e) everywhere in the middle of the behavioral code is noise.  The converse is true as well when I’m working on the presentation itself.
  • The screen behavior is easier to test and modify.  That’s enough by itself to justify the Humble View style.  What if this closing behavior changes tomorrow with a requirement to set a user preference to never ask users to discard changes?  If I’m working in a Humble View style, I can probably make that screen behavior change completely, including unit tests, in the Presenter class by itself without ever having to fire up the user interface until the very last sanity check.  Verifying little behavior changes with NUnit is a far, far tighter feedback cycle than doing the save verification by firing up the user interface and doing the manual input steps necessary to exercise the functionality.  Tight feedback cycles == productivity. 
  • By extending the reach of granular and automated unit tests farther into the potentially complex user interface code, we can drastically slow down the rate of screen defects getting through to the testers.  If nothing else, we can knock down all the common uses of the user interface quickly through tests to give the testers more time to break the application with edge cases and exploratory testing.

 

An astute reader will note that we didn’t write any unit tests for the View.  I’ll show an example in later chapters of testing the View itself, but the philosophy in general is to make the hard to test view code so simple as to be reliably verified by inspection alone.  I.e., you should make the View code so simple that it’s almost hard to screw it up. 

 

A Taxonomy of Humble Views 

Arguably the first Humble View is the original Model View Controller architecture handed down, as basically everything good in software developer seems to be, from the Smalltalk community.  As I’ve mentioned before, you can read about the evolution of the Model View Controller (MVC) pattern and the formulation of the Model View Presenter (MVP) patterns that we’re mostly talking about in this series as user interface toolkits changed.

D’Artagnan’s masterful implementation of the Humble Dialog Box vanquishes his foes, but he knows he’ll need trusted companions now that the evil Lady de Winter surely knows he is in pursuit.  Fortunately, D’Artagnan’s trusty three companions are riding hard to join him.  D’Artagnan smiles to himself and imagines his friends coming around the bend in the road:

  1. Supervising Controller — I’m here to help the View with the harder cases!
  2. Passive View — I only do what I’m told
  3. Presentation Model — Just do what I do

D’Artagnan sees dust rising in the air, a traveler is coming…

 

To be continued in Part 3:  Supervising Controller

     

QUICK NOTE:  I showed the MessageBox stuff happening as a consequence of calling a method on the IView interface.  In the past I’ve also used some sort of IMessageBoxCreator interface to create message boxes directly.  There are advantages either way.

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. 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 is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Build your own CAB, Design Patterns, Test Driven Development. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://blog.mattwynne.net Matt Wynne

    I moved my blog, by the way, so the above link may not work for ever. Go here to find it instead, if you’re interested:

    http://blog.mattwynne.net/2007/06/13/mvp-smells/

  • http://blog.mattwynne.net Matt Wynne

    @Pascal,

    So far we’ve managed to use an inheritance hierarchy within the Presenters assembly to manage duplication – so if I have two pages that both need to look up and display a Widget from a widgetId in the querystring, then I’ll put that code into a WidgetPresenter base class from which both those pages’ presenters inherit.

    What we found when we had ‘too many presenters spoiling the broth’ was that sometimes we had two presenters independently making similar, potentially expensive, calls to the model in order to render different bits of the page. By ensuring that there was only one main guy in charge of presenting the page, it’s easier to see when this is happening, and easier to test for it.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Pascal,

    Exactly what you said. Even if you can’t reuse the sub-Presenters, it’s good to keep the size of the main Presenter down.

  • Pascal Laurin

    @Matt

    I’ve read your post and it’s good but do I understand you avoid compositing your presenters as much as possible? That you are re-using (copying) code over and over to new presenter in your 1-1 presenter / view model?

    Actually that is a question I had for some time now…

    @Jeremy

    How do you do the presenter for very complex screen? I bet it is composition of many reusable presenters if possible. I’m not sure if you talked about that in another post, might have missed it.

  • http://mattwynne.wordpress.com Matt Wynne

    Jeremy,

    Thanks for your insightfull blogs posts about the MVP pattern recently, you have been a guiding light amongst a lot of confused and confusing interpretations of this pattern as I try to implement it on our application.

    Having had to go and refactor some of our earlier (and slightly misguided) implementation of the pattern I wrote up what I’d learned here[1] – I’d love to know your thoughts.

    [1]http://mattwynne.wordpress.com/2007/06/13/mvp-smells/

  • Pascal Laurin

    @Jeremy

    I must agree with Eli that it’s important not to put the priority on:

    Design (for testability) ->Write Test->Write Code

    before

    Write Test -> Write Code -> Refactor

    I guess the experience you gathered lead you to sometimes skip a few steps the rest of us still need tackle before really understand *why* it’s better to design the application in *that* specific way. And mind you, every project has their own problems and there is just not the one solution for all the cases.

    I think your Build your own CAB series should be taken only as an example and not *the* CAB solution for every project. But that’s the readers’ job to be objective about it.

    That’s the way I fell reading it and I do like your posts a lot. I’m sure I’ll be looking back at your CAB design when ever I’ll start a new project.

    @Eli

    If you never had problem dealing with MessageBox in your testing then fine but that might not always be the case.

    At my current job we needed some kind of automated acceptance testing. I must tell you that the MessageBox problem was one of the many problems related to UI design and usage we had while implementing our testing framework.

    Again, if your needs are not the same than ours then using the MessageBox class directly might be Ok. Just keep in mind that it may be just another technical debt you’re introducing into your code base.

  • JohnV

    I don’t quite understand this code. If the screen is Dirty and the user Decides NOT To Discard the Changes, shouldn’t we keep the screen open. In that case wouldn’t “DoNOTCloseTheScreenWhenTheScreenIsDirtyAndTheUserDecidesNOTToDiscardTheChanges” be a better name? I used NMock2 to do this and so I had a line in there to show that Close is NOT Called:

    Expect.Never.On( mockview ).
    Method( “Close” );

    Is there a way to do something similar for RhinoMocks? I know this is a record replay type of thing so if we don’t record that action we are saying that it does NOT happen?

  • http://www.elilopian.com/2007/05/31/the-humble-dialog-and-famous-musketeers/ Eli Lopian

    Where ever did you get that idea from:
    “people are interpreting TypeMock and your “no designing for testability any longer” statements to mean that they don’t have to take as much care with design. ”

    The opposite is correct. I have always said -> Business Drives Design as opposed to being testable drives design.

    You know very well that people are interpreting “Testable” to mean, “if I am Testable then I have a good design”, so I don’t have to think of designing any more. I recall that TDD should be:
    Write Test -> Write Code -> Refactor.
    Not:
    Design (for testability)->Write Test->Write Code.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    Eli,

    Fair enough, but I most certainly did talk about responsibilities and separation of concerns in the other posts in this series. The MessageBox is a simplistic example, but an easy one to use. I would go for MVP in all but the most simple screens.

    Going to an IMessageBoxCreator frankly isn’t all that difficult, and helps more in full blown integrated testing as well.

    “Having a good design is one of the responsibilities of the developer / team leader. You must refactor your code to get the best design. Seperation of concerns is one of the many design factors, as well as YAGNI, SRP and more. This should have nothing to do with the tools you use.”

    Cool, now *you* go say that somewhere please. You know full well that people are interpreting TypeMock and your “no designing for testability any longer” statements to mean that they don’t have to take as much care with design.

  • http://www.elilopian.com/2007/05/31/the-humble-dialog-and-famous-musketeers/ Eli Lopian

    Jeremy,

    I want to Quote You
    “but let’s think about how we could automate a test for this requirement to run within our regression test suite.That little bitty call to MessageBox.Show() and the modal dialog box that results is a serious pain to deal with in an automated test”
    This is what you based the need to change the design. I am challenging this. You never talked about separation of concern in this article or said that the design was bad – only that you cannot automate the tests.

    Now to quell your fears:
    Having a good design is one of the responsibilities of the developer / team leader. You must refactor your code to get the best design. Seperation of concerns is one of the many design factors, as well as YAGNI, SRP and more. This should have nothing to do with the tools you use.

    Tests are a safety net that allows you to change your code/design, not twist your arm into using only one Pattern.

    Using this technique will allow you to refactor the code into MVP (in the future, when you really need it), but add value to your customers by having the feature simply designed. That is what agile is about.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    Eli,

    It was a nice post, but I don’t think you ever put enough importance on separation of concerns. Yes, TypeMock is clever as hell and it makes some of the “Mock Driven” design go away, but separation of concerns is important even if it isn’t necessary for testability. My fear with TypeMock is that people will use it as a crutch for bad design.

  • http://www.elilopian.com/2007/05/31/the-humble-dialog-and-famous-musketeers/ Eli Lopian

    Although MVC/MCP is a really nice Pattern, like many patterns, you have to know when to use them. For simple screens they are over-designed. Here is how d’Artagnan handles those simple dialogs (and manages to test them)

    See http://www.elilopian.com/2007/05/31/the-humble-dialog-and-famous-musketeers/

  • http://roytate.blogspot.com Roy Tate

    I always ask my fellow developers to write any production code so that we can use it from the command line or the web as well as from Windows Forms. This usually forces some separation. :-)

  • Dan

    Great post,
    I would love reading your view on hooking up the M with the V and the P using an Ioc container.

  • http://dmihalik.com Dustin

    Thank you for writing this series. I’m very much looking forward to reading the rest. Also, thanks for StructureMap. It makes my job much easier.

  • http://scourtrille.wordpress.com Shane Courtrille

    Awesome second post

  • http://www.philosophicalgeek.com Ben

    Thanks for this series. I’m just starting to build my first larger, multiple-view, complex application in .Net, and I’m very interested in overall design guidelines like these. Thanks!

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @DeveloperDan & @ScottC -

    Whoa! One thing at a time. I’ve got stuff for both topics, I’ve just got to get through more bad Three Musketeer references first.

  • ScottC

    I’m hoping to see how to make the most of StructureMap as you continue this series also — Thanks Jeremy!

  • DeveloperDan

    Great lesson Jeremy. I’ve known it’s wrong for me to have so much code in the button_click events, but I’ve struggled with the best way to do that. Any chance you’ll provide sample code downloads?