Monday, June 15, 2009

Screen Factory

Let’s go right to the ending. When I need a class to construct a Model-View-ViewModel triad, I’ll call that class a “Screen Factory”;  the terms I’ve been toying with recently, “Coordinator” and “Director” should be reserved for cases involving triad coordination. How did I get here?

Jeremy Miller called me last week after reading my post on the “Coordinator”. He’s been watching a lot of the MVVM noise we’ve all been making recently as he girds his loins to write a book about “Presentation Patterns”. He recently announced his plans for this book and I encourage you to look at his proposed Table of Contents and send him feedback.

[Warning: I am about to render my recollection of our conversation and to try to represent Jeremy’s thinking accurately. He is more than capable of doing that for himself. But I’m forging ahead because he’s off to Norway, won’t get to these topics for awhile, and I’d rather misremember and flub the concepts than forget altogether.]

Anyway, he read my post and called to talk about it … as well as some of his ideas for the book. He mentioned almost casually that I had misunderstood something he wrote awhile back. He was right about that … as we’ll see.

The gist of my post was that the creation of Model-View-ViewModel (MVVM) triads is a separate responsibility from the internal synchronization among the triad members parts. The VM is dedicated to synchronization of V and M. It should not also assemble either its own triad or other MVVM triads. The job of creating a complex view belongs to something I called a “Coordinator”.

To support my argument about separating creation and synchronization concerns, I cited Jeremy’s “Main Players” article from his 2006 “Build Your Own Cab” series.There he identified something he called the “Screen Conductor” which he said was responsible for “the activation and deactivation lifecycle of the screens within the application.” I glommed on to this, thinking it to be another name for what I’m calling “Coordinator”.

Turns out that isn’t what he had in mind at all. His Screen Conductor doesn’t create screens or views. It oversees a collection of “screens” and decides when to activate (show) or deactivate (hide/close) them. Activation is not creation … although it may require screen creation; Deactivation is not screen destruction … although we may dispose of the screen once it has been deactivated.

Think of Visual Studio. Click an item in the Solution Explorer tree and VS displays the selected solution element in one of its tabs. Click another element and you get another tab. Click the first element again … and instead of a new tab, VS activates the already displayed tab. Try to close that tab and, if you’ve made any changes, you’ll be asked if you want to save or cancel; cancel and the tab remains in place. You’re seeing the Screen Conductor at work, managing a collection of “editors” displayed in tabs.

Note: I don’t know how VS is actually put together. This is an exercise of my imagination; join me, won’t you? 

How does the Screen Conductor add a new tab? I figure it finds the association between the item you clicked and an editor for an item of that type. It then might ask something to construct an appropriate editor instance for the selected item … and then adds a tab populated with this editor.

Whatever the actual implementation, we can be sure that the Screen Conductor itself does not construct views. It may know which view to create: a code editor for a C# file, an XML editor for an app.config file. But it doesn’t know squat about how the editors themselves are built. It delegates creational responsibility to something else.

My “Coordinator”, on the other hand, does construct views.

Observe also that there need only be one Screen Conductor in the entire VS application. Screen Conductor is a part of the VS Application Controller … of which there should be exactly one. VS only needs one apparatus to manage the coming and going of tabs.

But there are many “Coordinators” in an application, each capable of constructing a composite “view” of a particular type.

Clearly “Screen Conductor” is not “Coordinator”. This would have been clear to me if I had reread his article with a modicum of care … as I invite you to do.

“So Jeremy”, I said, “if the Screen Conductor doesn’t create the view, what does?”

After a brief digression into open-generic type resolution with StructureMap and whether he actually needed anything specific to create the view, we arrived at the essence of it.

“If you need something to create screens, it would be a Screen Factory.”

“Factory” versus “Coordinator”

When the Screen Conductor determines that the Visual Studio item you clicked - the item that identifies the “Screen Subject” that you’re interested in – is not represented in a tab on screen, it finds the right factory for this kind of subject … and calls it. If you can rely on the IoC container to assemble the pieces; fine … it is acting as your factory. But if you’re not comfortable with IoC handling that task, you’ll want a screen factory class.

And, trust me, you will find that you cannot always rely on IoC / Dependency Injection to create the “view” (the MVVM triad) for you, especially if the “view” is complex and composed of constituent views. You may need a dedicated factory class to assemble such a view. Of course you’ll use IoC to acquire or inject this factory where you need to call it.

My “Coordinator” class is functioning as such a factory. If all it did was create triads, I should have given it a different name … a name with the word “factory” in it.

How did I miss that? The title of my post was “Birth … of M-V-VM Triads”. Hello?

I missed it because I was thinking about an (unnamed) class in one of my applications. That class has additional responsibilities. I was thinking about how it closes and disposes of views. And I was thinking a lot about how it coordinates a set of closely collaborating MVVM triads.

Somehow, in my entire post, I barely mentioned view coordination … which was the reason I called this thing “Coordinator” in the first place. I redress that omission below in a sidebar on “Coordinated Collaborating Views” where I also consider whether you’re “permitted” to write a class that creates, coordinates, and destroys views or if you “must” re-factor such a class because it violates the Single Responsibility Principle (SRP).

But I got ahead of myself. I should have stuck to the challenges of view creation … and called it a factory.

“Screen Factory” or “View Factory”?

What do we call it? Jeremy calls it a “Screen Factory” in keeping with “Screen Conductor”, “Screen Collection”, “Screen Subject”.

We both feel uncomfortable with the word “screen”. “Screen” can mean “everything that appears within the windowed walls of your application.” That’s too big a canvas. In the Visual Studio example, when we say the Conductor manages a collection of screens we are referring to the individual tabs, each one of which holds a “screen.” Is that confusing?

John Papa and I considered calling it a “View Factory” instead. Unfortunately, “View” is at least as overloaded as “Screen.” “View” has the “big” versus “small” problem in reverse. A toolbar or a chart might be implemented as a view within a larger view composition. Some views can be adequately represented with a data template. I wouldn’t want to write a factory for these. Too far down in the weeds. I only need a factory for a view with heft … such as the editor view in the Visual Studio tab.

Moreover, there is potential confusion surrounding the difference between the view type, the “V” in the “M-V-VM” triad, and the view concept which the triad implements. Writing “the MVVM triad” gets old fast. I prefer to just say “View” meaning the conceptual view … and trust that you understand that I mean “that which appears in the UI”, regardless of its implementation. It should be obvious when I’m talking specifically about the V in MVVM (or MVP, or MVC).

But in code, if you see a class named “CustomerOrdersViewFactory” you might wonder if it creates the whole view or just the view instance within the triad. In fact, I may need a view instance factory that determines dynamically which of several alternative view implementations is most appropriate for this particular user at a particular moment. Localization, accessibility requirements, user authorization, … these kinds of factors can lead you to offer several flavors of what is otherwise the same view; the V changes while the M and VM do not.

I’m going to stick with Jeremy’s “Screen Factory” … for now. By “screen” I’ll mean the chunk of visual real estate devoted to a significant user scenario.

Does this work for you?

SideBar: Coordinated Collaborating Views

In the general case, MVVM triad interactions are loosely coupled … often through some pub/sub scheme, e.g., Event Aggregator (EA). There is no need for anything to coordinate them. They just listen and respond. Or they publish an event that another view might care about … and then they immediately forget about it. Remember: EA is always fire-and-forget.

However, I often have a set of “views” that collaborate too closely and too dynamically for a reasonable EA implementation. For example, imagine a “Customer Screen” displayed as a Customer overview positioned above a Details Tab Control. Each detail tab displays particulars of the customer: orders, contacts, credit info, etc.

I would construct this “Customer Screen” compositionally; there would be some MasterDetails mini-shell … the visual framework for the “Customer Screen” … into which I poured the customer overview and each of the detail tab views. Something has to put all of these pieces together (the creational responsibility) and something has to mediate among the composite views to keep them in sync.

Why sync? It is inevitable that something will happen in one of the customer sub-views that affects its colleagues. You could use EA to signal across views. But that gets out of hand pretty quickly. The number of cross-view synchronization events begins to multiply. You start to worry about the diversity of event payloads. The moment you enable viewing of multiple Customer Screens (e.g,, to see “Acme Grocery” and “Fine Food Mart” simultaneously) you have to scope the events by customer so that the two customer screens don’t respond to each other’s messages. You’re reliance upon pub/sub complicates testing and debugging. It’s a mess.

My preferred approach is to provide a common context object to each of the constituent views (I mean their VMs of course) . The context constrains the scope to a single customer and contains all the necessary coordinating machinery. The constituent views remain decoupled from each other … they never address each other directly … but we can still coordinate them with something that is both local and apposite to the task.

What do we call this context? A “coordinator”? A “director”?  Either name will do.  What I’ve described fits the Mediator pattern as described in GoF where the example class is called “DialogDirector”; it also appears in Wirfs-Brock’s, “Object Design”, as a Coordinator implemented with the Mediator pattern (p. 339).

Look closely at the GoF DialogDirector sample code. Notice that the DialogDirector both creates the constituent components (“widgets”) and coordinates them. It passes itself into the constructor of each of the components it creates.

Argue if you will that the GoF  “Director” violates the Single Responsibility Principle (SRP); at least I am in good company.

Is this a problem? Certainly there are at least two dimensions of change. We could change the way we construct the dialog and we could change the way we coordinate its parts. We could refactor DialogDirector into a DialogFactory and a DialogCoordinator. The factory would “make” the widgets, “make” a coordinator, and wire them all together. I have taken this approach with modest success. But I must admit that many found it a tad confusing and overwrought.

I’m not sure it is necessary. Multiple responsibility classes are “bad” because the forces of change impinge upon the responsibilities from different sources at different rates. But the dimensions of change in our coordinator are rarely independent. Am I really going to change how the dialog is constructed without simultaneously changing how its parts are coordinated? Can I change the coordination without knowing about the parts and their instantiation?

Maybe. But let’s be pragmatic, not pedantic. We can always refactor after we take the first bullet.

17 comments:

Anonymous said...

Ward, once again, really insightful post! I think I am seeing eye to eye with you now. When you were previously discussing the "Coordinator" I was thinking much more in terms of activation/deactivation. Mainly, because that is what I associate with the word. I have been thinking about our excahnge on your blog, trying to understand your scenario and pondering whether it was better to repurpose an old term (Supervising Controller) or invent a new term (Director). In other words, which would be most expressive and introduce minimal confusion into our pattern language. I really like your choice of "Screen Factory." It leverages the GoF Factory without changing its meaning, but specializes it by applying the "Screen" modifier. What's interesting about GoF is that a lot of those patterns, if you remember the original narrative section, were related to solving UI problems. One of the things I am going to blogging about is how various GoF patterns manifest themselves in the presentation layer, specifically as part of a VM.

Julian Dominguez said...

Great post! I like these names better also, precisely for the arguments you exposed: it mainly manages creation of the MVVM triads, and the wireup between them althouth it's after the CLR instantiated the classes, is still part of the creation process.
By the way, I prefer the "View Factory" name better, because even it might get confused with the "V" in mVvm, it's the "View" in these acronyms the objective of the creation. You wouldn't think of creating a VM in the first place if there was not any View to display it. When the Controller is creating the MVVM triad (or a pure View-with-code-behind-and-no-separated-model), all that it cares is asking the "view factory" for a view, and it will be this class who would be the main consumer of the factory by calling ViewFactory.GiveMeTheViewByBuildingItUpAsYouWish().

Ward Bell said...

@Rob. Yes, ... I think we're aligned now. I recall you made a comment about how GoF had something to say on this after I had said I hadn't remembered GoF contributing on it.

Well GoF didn't tackle Separated Presentation patterns as we describe them now. But you are right, they WERE talking about UI scenarios.

The Mediator example might have been an MVC discussion. Back in the day, the "V"s were the individual controls in the dialog. Today the "V"s we talk about are entire structured collections of controls. Progress I guess.

BTW, John Papa and I have been kicking around the Screen Conductor off-and-on all day. Something is bound to come of it.

Ward Bell said...

@Julian ... thanks for the thumbs up.

I remain conflicted on the name but I'm still favoring "ScreenFactory".

I was re-reading my post to see if I still felt that way and realized that I hadn't been as clear as I wanted to be about when you really need a Coordinator or a Factory.

I was trying to describe the construction and management of a complex Composite View. Such a view consists of a structure of NESTED sub-views.

In a Composite View there is typically an uber-view class that acts as a kind of shell into which we drop the sub-views.

Many times you can create this uber-view and the sub-views, put them all in their proper slots, and you're done.

But just as often you will find that the sub-views have to communication and you want a single point of contact ... a mediator ... to manage the conversation ... and to communicate outside the Composite View.

The Composite View is not simply a visual boundary. It also establishes an operational boundary within which the sub-views interact. They are invisible to code outside the Composite View.

Considered from the outside, this Composite View is a "Screen". A Screen Conductor might find one of these in its Screen Collection. And it would call upon a ScreenFactory or Coordinator to make a new one.

The Screen Conductor would never make the sub-views; it has no idea they even exist. Only the ScreenFactory (or Coordinator) would know to create the sub-views.

Meanwhile, the ScreenFactory ... in the process of constructing the sub-views (each an MVVM triad) might resort to View Factories to acquire the sub-view "V"s.

It is this vision, dancing in my brain, that leads me to distinguish ScreenFactory from ViewFactory and to prefer the term "ScreenFactory" when describing the "big view" dynamics that were the subject of my post.

But choose what works for you. I'm sure not going to start a war over whether you open a soft-boiled egg from the big end or the small end.

Mikael Koskinen said...

Thank you for an interesting post. It was very timely because I was battling with the same naming issue just couple weeks back. I ended up calling your "Screen factory" as a "Screen composer" and your "Director" as a "Controller".

In my application (WPF client built around the Prism) only one module can be active at all times. User can switch between the modules by clicking the appropriate icon and when that happens the old module is closed and the new module is shown. Inside the module there can be multiple screens. Every screen represents one tab page. When a screen is activated, it's up to the Screen Composer to build the screen. It creates the required presenters (I'm using MVP), hooks them up with the same Screen Controller and then asks the presenters to show the view. Presenters don't communicate directly with each other, instead they talk to the screen controller.

There's one other thing which my screen composer currently handles: Hooking the screen components with the same unit of work. I want one unit of work per screen and I want the screen controller to take care of the unit of work. Currently the uow is created by the screen composer which makes the class a little too complex. But it shouldn't be hard to transfer that part of the code outside of my composer.

-Mikael

Glenn Block said...

Nice Post Ward.

I prefer View Factory as well. In a composite application, a "screen" can be a mini-shell with it's own screens embeddeed within. In that sense I think they are all just views. Also if you look at the GOF Composite pattern, the premise is that each node can be treated as the whole.

In many instances today, the "screen factory" is actually something offloaded to the IoC container of choice alongwith some configuration magic.

Ward Bell said...

Glenn - I'm going to have to disagree. A Screen is not a View.

A screen represents the UI of a large-scale user scenario (e.g., CustomerEditor) which visually occupies some defined display space managed by a ScreenConductor.

A Screen HAS a view ... perhaps a mini-shell ... which the ScreenConductor may place on the physical display ... but it is more than just that view. It is a higher level concept that responds to demands from the ScreenConductor that are particular to screens alone. As such, it is not eligible for Composite Pattern treatment.

Let's look at a candidate IScreen. Its members include View, yes, but also (probably) ScreenSubject, CanClose, Close, Activate, and Deactivate.

At first blush we say "views can close", etc. But upon closer inspection we realize that we mean something else.

Most obviously, View's don't have to have a subject. A tabular view, for example, has no one subject.

A view (and here I mean a View's ViewModel) need not know whether it can close or how to close. It likely contains information relevant to closing ... but, as a participant in a nexus of companion views that collectively implement the screen, no one of the views can speak for all.

The Screen speaks for all of it's composite views. At least the Screen is responsible for all, even if, in practice, it delegates some or all of the responsibility to its ViewModel(s).

You could require all of your views to implement IScreen and supply them with do-nothing implementations; but that does violence to the Composite pattern.

Moreover, the Composite pattern exists to support iteration over a graph of heterogenous objects with a common base type.

There is no such graph of screens. The ScreenConductor maintains a flat collection of screens that have no relation to each other. Nor do we want anything to be probing into the interior of a screen to probe for (possibly) nested views.

It may be possible to construct a screen without benefit of a ScreenFactory. In practice, I find this so fraught with complexity and murkiness that I would always avoid it. I can't speak for Jeremy but I believe he said he shares my opinion on this.

Of course there will be some screens that are so incredibly simple that they are little more than wrappers around a view. If this were often the case, we'd never have brought this up.

We're after bigger fish. We're trying to understand how to manage complex screens such as CustomerEditor, OrderEntry, and PayrollTimesheet. These fellas are typically rich in various UI controls, hold lots of pending state changes, and lend themselves to compositional implementations.

Suppose we've made a change to the Address view within a CustomerEditor. Who knows if the CustomerEditor can close? The Address view? I don't think so.

The Address view's VM knows that an address change is pending but that VM cannot determine whether the change can be discarded in this scenario.

The address view is deep inside the CustomerEditor. There is no obvious way for the ScreenConductor to know of its existence let alone ask the address view if it can be closed.

You might conjure up some event-driven scheme where each view heard about a close request and recognized the request as pertinent (good luck). Then what does it do? Vote? Who counts the votes? Is one view's vote more important than another view's vote?

It just gets ridiculous if you bubble this complexity up to the level of the application as a whole (or to the ScreenConductor). However such decisions are made, they are made within the boundary defined by the screen.

We need a distinct construct to represent the screen as an integral whole, as a thing unto itself.

The ScreenConductor wants one point of contact when it asks "Can You Close?". There is one locus for decision making ... the Screen.

Ward Bell said...

Mikael - I agree that a screen often holds its own unit-of-work.

When I edit Customer Acme and Customer Zeta simultaneously, changes to Acme are independent of changes to Zeta and their respective persistent object graphs should be kept apart.

Within a screen, which represents a sizeable user scenario, it is usually sufficient to have a single unit-of-work.

As in all things, one may depart from this advice and share units-of-work across screens or require multiple uow within a screen. Such departures are exceptionally rare in my experience.

Glenn Block said...

@Ward

I see what you mean now in saying that screen is introduced as a higher level concept.

Still and all it feels like a Composite View. You describe Order Entry, and Payroll, I see these as Composite Views which perhaps may have a SupervisingController / or higher level VM that strings them together.

For example, in the Prism StockTraderRI we had a CompositeView representing a buy/sell transaction. Whether or not the "Screen" can close would be the job of that controller. Now maybe what i am thinking of as a controller is what you are calling Screen.

Glenn

DanM said...
This comment has been removed by the author.
DanM said...

Hi Ward, As someone who is just starting to use MVVM for the first time, I'm finding your blog very interesting and helpful. I have a couple thoughts on your nomenclature conundrum. A factory should be named after what it produces. In the case where you have a single view composed of one or more MVVM triads, I agree with you that a "View" (in the MVVM sense of "View") isn't what is being built. I also agree that "ScreenFactory" isn't quite right because a "screen" feels like the entire application window, not simply a meaningful section of this window. So, please allow me to propose a few alternative...maybe one of them will resonate with you: ViewSetFactory, ViewGroupFactory, ViewCoordinatorFactory (ha!), UIModuleFactory, FrameFactory, UIFrameFactory, AppletFactory. I had a number of other ideas but these were my favorites. I think I like AppletFactory the best. I guess it's sort of a Java term, which may offend some people around these parts, but that seems to be the only single word that really brings home the idea of "a coordinated set of MVVM triads that form a meaningful unit of the overall UI". EDIT: I guess AppletFactory wasn't sitting with me as well I thought it was, but I came up with something similar but maybe more apt: ScreenletFactory.

Colin said...

Hi, I've just come to the party late and I'm sort of new to the whole presentation patterns stuff but may I suggest instead of Screen Conductor, Screen Factory, etc, how about Layout Conductor, Layout Factory etc. A layout doesn't convey a large area such as a screen but can be small enough to be part of a tab or composite item on a larger layout. What do you think? Anyway wanted to thank you and your other collaborators in enlightening me in designing better GUI frameworks and apps.

Regards, Colin

Ryan Haney said...

Ward,

I agree with Glenn in that it makes sense to have a CompositeView that coordinates sub-views via its CompositeViewModel.

It also eliminates potential confusion between the scope of Screen and Shell, and in the case where a PRISM IRegionManager is being used, still conforms to the convention of adding a "View" to a region (as opposed to a screen).

Thoughts?

Unknown said...

Ward, having read both your articles and all the comments for both - it seems clear to me that what you are talking about here is a composite view. The way I have created this in the past is to create a view (let's call it the parent view) that contains a grid, itself containing several ContentControls that have a region attached. The 'child' views are loaded up into the content control 'regions' via view discovery (i.e. wired up in the module class) when the parent view is displayed itself (either by view discovery or view in injection, take your pick). The parent view has a presenter, not a view model since there is no actual model bound to the parent view. The parent view's presenter handles any composite logic. In this way we don't need to introduce any additional class types.

Unknown said...

Another approach to this is also playing on my mind. The parent presenter could instead be a View Model that contains a view model property for each child view. The datacontext of the parent view would then be bound to its viewmodel and as the contained child views inherit this context, they would set their datacontext to the inherited datacontext.childviewmodel - where childviewmodel is the viewmodel for that particular view. Any composite actions are still maintained in the parent view model. Thoughts?

Ward Bell said...

Darius - Not ignoring you. Just buried right now and your thoughts require more than casual reflection. Hope to get back soon.

Richard Gardiner said...

Thank you - this has solved a problem for me. I was having problems with view first or viewmodel first - neither seemed to always work for me in different parts of my app. View first worked initially when creating new data but got very messy when recreating the views from my database (I am using nested views to work on hierarchical data). I prefer to take a consistent approach and didn't want to use both.

I like the name as well!