Archive for the 'UI' Category

Building A Complex Web Forms UI

I recently wrote a post about composing a UI based on discrete behaviors. I thought maybe I should explain a bit more about the problem that led me to this idea.

Mike Wagg, Zubair Khan and I were tasked with developing a rather complex UI using ASP.NET Web Forms (the company had a suite of existing custom controls, so unfortunately MVC was not an option). We started-off using a Model View Presenter (MVP) pattern, but found that our presenters became overloaded with state management responsibilities. So we introduced a Presentation Model to handle the state and behavior of the View.

The ASP.NET page life cycle never failed to cause us grief. We attempted to abstract away the life cycle using a combination of a View, Presentation Model and backing Controller. The page populated the Presentation Model on Load and bound back to it on PreRender. Any state changes that occurred during the page life cycle was applied to the Presentation Model. The Controller’s responsibility was to receive events from the View, call out to services and pass data to the Presentation Model.

We found this greatly simplified things, as we didn’t have to worry about the changing state of the View throughout the page life cycle. We simply updated the Presentation Model and the View submissively bound to it at the end of the life cycle. We could also effectively test the entire process, as we didn’t rely on the page to manage state changes.

Presentation_Model

The only downside to the Presentation Model was that we had to change the code in order to accommodate new behavior. This violates the Open/Closed Principal (OCP) and increased the risk of breaking existing functionality. That led me to investigate the discrete behaviors approach that I blogged about.

Another problem we faced was getting the presentation components to talk to each other. We were using the View as the messaging bus, but this led to a lot of code that looked like parentView.childView.DoSomething(). This was very brittle, so we created an Event Hub that acted as a central messaging bus that any of the presentation components could publish/subscribe to.

We now feel we have this complex UI project under control. Mike is currently writing a series of posts that go into further details on the Presentation Model and Event Hub approaches. We learned a lot from this project and I hope this can help someone else who is creating a complex UI in a stateless web environment.

Advertisements

User Interface Code And The Open/Closed Principal

The Open/Closed Principal (OCP) is a fundamental object-oriented design principal that states:

“Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.”

This means that we should be able to add new behavior to a software entity without altering its code.

Most UI code I have seen, including Model-View-Presenter (MVP) and Model-View-Controller (MVC) implementations, clearly violate the open/closed principal.

When developing UI code, we tend to create presentation classes in terms of views, or sections of the UI. To add new behavior to the UI, we need to modify these presentation classes. This increases the risk of breaking existing functionality.

UI development can be notoriously complex because of the many interactions and state changes that can occur. To manage this complexity we should ensure that our classes have only one reason to change.

Instead of grouping presentation classes into visible sections of the UI, maybe we should be creating a series of discrete presentation behaviors that react to events raised from the view.

These behaviors can be added and removed without affecting other behaviors on the page.

Behavior-Driven Development (BDD) advocates creating tests based on individual behaviors, so why not create our presentation classes in the same way? The tests then correspond directly to a single discrete unit, rather than a behavior that occurs within a larger structure, e.g. a presenter class.

Each behavior has a name that describes the behavior it represents. Using a descriptive name provides instant documentation of the UI behavior. It should be easy for someone to understand what the UI does simply by looking at the behavior names. If a problem occurs, it should be easy to identify and isolate the affected behavior.

Implementing Presentation Behaviors

I have created a simple music finder application that demonstrates an implementation of presentation behaviors.

Download the sample code here.

The sample application contains a single page, represented by an IFindMusicView interface. The behaviors respond to events raised by this View and update the View accordingly.

A typical behavior can be defined as:

Given… a particular scenario

When… an event occurs

And… all conditions have been met

Then… do something

And… do something else

Each behavior is implemented as a class that derives from a base class with an IBehavior interface. This interface contains two methods: When() and Then().

The When() method contains code that registers the behavior with a certain event on the page. The Then() method contains the code that responds to the event if all conditions have been met. The “Given” aspect is implemented by the class constructor, which takes the view and any associated dependencies.

   1: public class when_song_list_is_empty_disable_select_button : FindMusicBehavior
   2: {
   3:     public when_song_list_is_empty_disable_select_button(IFindMusicView view)
   4:         : base(view)
   5:     {
   6:     }
   7: 
   8:     public override void When()
   9:     {
  10:         View.AfterSongsLoaded += (sender, e) => Then();
  11:     }
  12: 
  13:     public override void Then()
  14:     {
  15:         View.IsSelectButtonEnabled = View.SongsList.Count > 0;
  16:     }
  17: }

 

The behaviors are instantiated by the View, but an Inversion Of Control container could be used to register the behaviors at run-time. The View then wouldn’t need to know anything about the behaviors that are implemented for it. We could then drop-in and drop-out behaviors without needing to change the existing code.

Further Considerations

Although this is an interesting concept, I am yet to implement it on a large-scale application. There are several areas I need to investigate further, such as:

  1. Can one behavior extend the functionality of another behavior?
  2. Can parallel behaviors remain independant from one another?
  3. How does this work with MVC frameworks? Are the behaviors triggered by actions?
  4. How well does this scale?

Feedback

Does this concept make sense? Does it sound practical? Could it potentially solve some of the issues we face with developing complex UI code? Any feedback would be greatly appreciated.

Enjoy!