Presenter First with POA
Plain-old ASP.NET (POA) has a lot of advantages: rapid UI prototyping, incomparable support from 3rd-party vendors, and a simplified programming model that abstracts away the problems of a stateless application to name a few. But there remains the problem of testing. ASP.NET applications--any web-based application--is difficult to test. The traditional architecture of having your code-behind orchestrate your business logic components in response to events generated through the postback mechanism requires that you instigate those postbacks in order to test the orchestration. In other words, you have to drive the UI to test your application.
UI testing is expensive. If you've done it, you already know that. If you've not done it, then trust us on this one; the cost of tools, the complexity, and brittleness of web tests drive the cost up. Furthermore, if an application isn't designed to be UI tested, it becomes a nearly intractable problem to do so. The folks at Atomic Object know this from experience. As proponents of test-driven development, they have looked down the barrel of that gun and found a better way. They call it Presenter First.
The basic idea behind Presenter First (PF) is to obviate the need for UI testing. It is a Model-View-Presenter (MVP) variant that is closely related to Martin Fowler's Passive View. The application architecture is such that UI is so humble that there is no need to test the UI. This architecture requires that the Presenter be responsible for orchestrating the Model (business components) in response to events generated by the View, and updating the View appropriately. A View in PF only implements events and property set methods. This View can be defined by contract, e.g. IView, and mocked to allow for test-driven development.
A hallmark of PF is that Presenters are constructed with an IView and an IModel and do not implement any other public interface members. Thus, the encapsulated worfklow is driven completely through IView and (possibly) IModel events. Concordantly, it becomes evident that PF architectures are implicitly stateful, i.e. the Presenter is extant between events. In POA, the HttpContext only exists for the duration of the processing of a request. While the HttpSession remains there is a non-trivial amount of complexity involved with it; ultimately, this too should be considered transient in the general case. From these facts one might conclude that PF is not applicable to POA.
The purpose of this writing is to propose a method of implementing Presenter First in ASP.NET. The general approach is outlined below:
- All page's implementing a PF IView (e.g. ICustomerEditView) must inherit from PFPage.
- PFPage implements a Dictionary<typeof(IView),PresenterInstance> lookup.
- Before Page processing, the PresenterInstance is given a reference to the View, i.e. the current page.
- The IView events are fired (from postback) and the Presenter handles them appropriately, updating the View via setters.
- The Presenter handles the Page.Unload event and drops its View reference
This approach diverges from "classical" PF in a few ways. Most importantly, the actual concrete View acted upon by the Presenter instance is transient. This should not pose any particular difficulty as the ASP.NET postback model ameliorates this stateless condition of web applications. Further, while this requires the Presenter interface to implement a mutator for its View reference, the Presenter implementation need not diverge from the "classical" PF approach, save in one important way. IModel events would need to be queued.[1]
Furthermore, the Presenter instance and the dictionary must be serializable if that pattern is to be used in an ASP.NET deployment where the HttpSession was out-of-process. This might propose problems with Presenter references to cached objects that can't be extended to support serialization; though this is considered a minor flaw in the general case and an impediment that can be ameliorated by recreating objects from metadata.
To compose views it would only be necessary to create a PFControl base class that implemented nearly identical functionality to the PFPage. Also, though declarative databinding is no longer possible, DTOs could be used in View mutators for databinding.
Through the use of mock objects, this approach to ASP.NET development using Presenter First enables Test-Driven Development of the business objects and their orchestration in response UI events to without the need to involve ASP.NET pages.[2] Additionally, this allows for the tandem of presentation (.aspx) and interaction (.aspx.cs) to be isolated from business logic (Model) and orchestration (Presenter).
Please let me know what you think. Is your organization using a very similar approach? How have you fared?
[1] Because the Presenter MUST NOT call mutator methods on the View between postbacks, IModel events must be queued until a new View instance is received.
[2] While issues such as declarative security and AJAX can make UI testing a necessity, we are assuming that these are not direct considerations for vetting the business logic and orchestration. Further this kind of UI testing will generally be done as a part of UAT and thus does not "cost" the development team.