Tuesday, January 24, 2006

Few findings about Presentation Model

Almost every project that I have been on strives for code testability. By increasing code testability one can better the design of the solution as well as continue to change code without worries. However when it comes to increase testability of the view in the classic MVC, it is always hard to do. Microsoft proclaims that they have achieved MVC (or Model-ASPX-CodeBehind), but it fails to address the testability issue of the code in V and C: CodeBehind logic are extremely hard to test against. Both the Presentation Model (PM) and the Model-View-Presenter (MVP) pattern address this issue.

Having used both patterns for my past few projects, I think I am seeing some pros/cons. Today let's look at the Presentation Model first:

Presentation Model:
I like using Presentation Model (PM) when I am developing a web application. In web apps, there are a couple major headaches when it comes to increase code testability, the first of which is carrying state across requests. Secondly, in ASP.NET, the Page class gets created and disposed of every request, making using an intermediary class (such as a Presenter) to "push" content from the model to the view very difficult, and hence a directional referencing problem.

PM employs a "pull" model, meaning the consumer class (aka the code-behind) will ask for data that the PM has prepared for it. Because of this model, at each Page cycle step (Page_Load, Page_Init, etc.) the view will be in the driving seat as far as controlling when to reload the controls and what to load them with. The PM simply sits there and wait for someone to tap his shoulder to ask him to produce something. Notice the directional reference: the view has a reference to the PMs. The PMs do not know about the view, and do not push content out to force the view's state to be refreshed.

Usually you will have one PM per ASPX page, which I call a Page PM. When the page gets busy, your Page PM is likely to be a gynormous 1,000 line class, containing many properties for the use of the many dynamic view controls' use. Therefore, use sub-PM classes to better organize your code and avoid code duplication. The levels of sub-PM classes from my experience probably won't go deeper than 3 inheritance hierarchy.

Most of your Page PMs usually will have reference to the session object, in which most probably the aggregate root of your Domain Model will be stored. For a more complex Domain Model, the PM's task of flattening out this 3-dimensional beast starting with this aggregate root will make your view look extraordinarily simple.

Because PMs usually flatten out your Domain Model into some easily readable grid or string format, your Domain Model objects may not be the ultimate data holder objects that your view 's controls bind to. For example, you will obviously need a new object for a grid showing an insurance policy's type, coverages, each and every insured entity, and each coverage's premiums. (Hopefully they live in separate objects in your Domain Model). Create some what I call "Data Item" objects to facilitate data binding to your grids or lists. Data Item objects are just for holding your diced and sliced Domain Model data and have no behaviors. Think of them as classes that represent a row of data in every single grid on your page. In the above example, your PolicyInfoDataItem class will have public properties of [PolicyType :string, CoverageName :string, InsuredEntityName :string, CoverageAmount :double]. This inspiration comes from DataGridItem, and various ListItem variants in the .NET Framework.

Unit testing your Page PMs in NUnit is always not easy because it uses the Session object, which is not available in NUnit testing. I have seen people use reflection to create a fake HttpContext object that stores Session data on the current thread, which then during [SetUp] set the context object (yes it does have a setter). Then your PM unit test classes have access to HttpContext.Session.

Speaking of unit testing PMs, I find it to be much more work to use mocking to unit tests your PMs. Especially if you love constructor injection, having your PM's ctor to take all those IEverything classes and during unit tests have them all mocked out is a lot of work because PMs is much more object state dependent than behavior loaded. As a result, I would prefer state-based testing (Stubs or the Object Mother pattern) to facilitate unit testing PMs. One must also manage the creation and customization of your domain model's state carefully, because these tend to duplicate code across your test classes easily if you go with state-based testing.

Your view also should not directly instantiate or reference any Domain Model objects (as a guideline, not rule). Whenever possible, pass primitive type user input information gathered off the Page and pass them directly to the Page PM for actions. This can consolidate exception handling routines (instead of scattering them all over your views), and also decouple your view from your Model, which you might later put them into separate assemblies.

Your Page PM can also handle behaviors that your view requests. For example, whenever a button is clicked, its code-behind event handler will make a call to the Page PM's "Save" method, passing the necessary information gathered off the controls, and then the Page PM will delegate the responsibility of the actual save to the Domain Model layer.

No comments: