Using MVC Pattern in Web Interactions(reship)

Using MVC Pattern in Web Interactions

 

Why do we need a server side Presentation Layer Architecture?

The Presentation Layer of a web server application is rarely designed. It's usually just coded. For small and medium sized sites this can work perfectly well but it becomes chaotic on larger sites. This article provides and structure and notation for designing the implementation model for large scale web server presentation layers. This can lead to better project management, more accurate tracking and ultimately better time estimating and closer control. This leads to developer and management confidence that the system under construction will work soundly and will be finished within a reasonable time frame. The advantages for project management and how to track a Presentation Layer development cycle using the techniques in this paper will be discussed in a future White Paper at this site.

The increasing demand on web applications is making them more and more complex. Very quickly they are becoming as sophisticated as many GUI Client/Server applications. This is puting a strain on the traditional "stateless, thin client" idea of a web application. Modern web applications have to carry out conversational transactions with the client. This requires the server to have a firm idea of the client state and a strong knowledge of the transaction boundaries. Part 3 of this article will show you how to scope the transaction boundaries within a Presentation Layer and how to enforce them leading to improved Transaction Isolation.

Web Applications are somewhat different from traditional green screen mainframe applications or more recent GUI Client/Server applications, because the client can be manipulated using the Browser and can change to an unknown state. The server must be able to cope comfortably with unexpected events from the client because the user has altered the client state using the Browser Back button or the Browser Goto Bookmark facility. Again Part 3 of this article will show how it is possible to have the server track the state of the client and still cope adequately with unexpected events from the client.

Introduction to a thin-client Web application

First let us define what we mean by "thin-client" in this context. A Thin-Client application for the purposes of this article is one which presents plain HTML documents in a Browser and receives back HTTP Requests. There is NO client-side code - no javascript, no java applets, just HTML. The browser is being treated as if it were a dumb (green screen) terminal with two notable exceptions.

The client can store "stateful" data i.e. data can be kept at the client through one of three methods, URL re-writing, hidden fields in an HTML Form and using cookies.

The client can also change its current state unexpectedly through the use of the browser "back" button and through the Goto bookmark mechanism.

This architecture does not rule out the use of client-side code and Just van den Broecke has demostrated that the notification ascpects of a typical MVC model can be implemented using minimal client-side javascript. A technology which he calls Pushlets.

Deterministic Presentation Layer

In Web Applications, the server side code which is responsible for the User Interface is usually referred to as the Presentation Layer. Perhaps this is to distinguish it from the client browser which is closer to the user and is often referred to as the User Interface. In other words, the Presentation Layer is the layer which constructs the User Interface but resides at the Server. As with all User Interface code, it's never too difficult to hack something together which does the job. Often, no one is quite sure how it all works but it seems to hang together, process input and display output as required. Design is often minimal and the code is simply written without much thought for design. This is often exacerbated by the rapid, incremental nature of UI prototyping which doesn't lend itself to rigorous design and keeping design documentation in synchronization with the developed code. With a lot of web applications, a static HTML prototype is constructed and then server side code is written to process form submissions and build html pages. The HTML prototype is then glued to the back-end and little or no additional design effort goes in to this activity.

This will work adequately well for small and even some medium scale applications. However, it is likely to become problematic for larger scale applications. Something with say 200 screens and perhaps 6 to 10 programmers just for the Presentation Layer. When a project gets this large, its necessary to have proper design documentation for the Presentation Layer code and its necessary to have some deterministic control over how it all works, what state is it in and what can it legally do next. Having tight control helps prevent bugs and helps to identify them when they do occur. This kind of control improves the confidence of the developers and the management and helps reduce the stress towards the end of a larger project. Spending time upfront with design, pays off later in reduced debugging and better test results.

Knowing deterministic information about the state of a user interface becomes very useful when you have a transaction processing application which must accurately define the scope of a "Unit of Work" for a logical transaction. Equally to ensure data integrity and consistency these transactions must be suitably isolated. Many web applications to date have avoided this complexity by implementing "stateless" type functionality where transactions only happen on single http requests. These have been called "atomic transactions" as they happen in their entirety without interruption and complete before anything else can occurr. However, increasing demands for more sophisticated web applications mean that browser based applications are increasingly being asked to deliver client/server like functionality. This can require what are known as "conversational" transactions between client and web server i.e. transactions which span http requests. To accurately control such transactions and provide other widely expected GUI functionality such as "Cancel" and "Retry", it is necessary to have a deterministic Presentation Layer.

A Deterministic Presentation Layer can be achieved by first modeling the User Interface using UML Statecharts and then implementing the Statechart Design using Mediator Pattern as part of a Model-View-Controller (MVC) engine. This article sets out the groundwork with a very simple example of a Login Dialog. Later parts will show how to implement a Statechart engine and MVC architecture and will demonstrate how to cope with difficult aspects of web applications such as the Browser back button and proper scoping of transaction, "Unit of Work".

Input Events - HTTP Requests

All Web Applications are Event driven. The Server receives HTTP Requests from the client. An HTTP Request is an Event. Specifically, it is a Get or a Post event. For the purposes of this discussion they can be treated as generic HTTP Requests. In Part 2, the specifics of handling Get and Post Events will be discussed.

HTTP Request

Fig 1. HTTP Request shown as an Event from Client to Server

If we consider what Figure 1 is showing, the Browser at the client sends an Event to the Server Presentation Layer. The Event is either a Get or Post Event which is encapsulated inside an HTTP Request. Later we will see that it is easy to model Event driven systems using Statecharts.

Event Evaluation

When the web application server receives an Event, it must evaluate it and decide how to respond to the client. This evaluation process may involve interaction with the business logic of the application. It has long being advocated that business systems should be evaluated and understood first before any computer system implementation is envisaged. This Business Analysis or Problem Domain Analysis as it is also known can take place independently of the screen design. Problem Domain Analysis can be implemented as a Business (or Model) layer. This Business Layer usually has to be persistent. Persistence is usually achieved with a database. Figure 2, shows the Presentation Layer messaging to the Problem Domain code and Persistent Storage in order to properly evaluate the input from the HTTP Request.

Three Tier Server Model

Fig. 2. Presentation Layer messaging Business Layer to access Persistent storage

This separation of Presentation Layer, Business Layer (the Problem Domain logic) and Persistence Layer (the Problem Domain data) is often referred to in Web Application Server literature as the 3-tier model. This separates it out from traditional client/server database forms applications which are usually called 2-tier. 3-tier is more flexible. Physically all 3 tiers can be implemented on different server boxes, this can lead to greater scalability and an ability to process more client requests simultaneously. A thorough examination of this 3-tier architecture is beyond the scope of this paper which is interested in the Presentation Layer and its relationship with the client.

Output States - HTML Pages

The application server Presentation Layer is also responsible for sending an HTML output stream to the client. Each time we send the client a new Page (or Frame) of HTML, we can consider that the client has changed state. The Browser is displaying a new page.

HTML Output

Fig 3. HTML output stream from Server to Client

In order to build the appropriate HTML output, the Presentation Layer may need to access Business Information such as a list of outstanding Invoices. This can be obtained by messaging into the Business Layer and requesting a list of such Invoices from the Persistence Layer. It can then use that data to build an appropriate HTML table populated with invoice details and send it out to the client for display in the browser.

Client to Presentation Layer Interaction

If we take a look purely at the Client to Application Server Presentation Layer interaction, we can see that the Client sends the Application Server input as a series of HTTP Requests, these can be considered to be Get or Post Events purely at the physical level. The App. Server then processes the HTTP Request and sends back an output stream to the client of HTML data to construct the required page or frame.

Presentation Interaction

Fig. 4. Client to App. Server Presentation Layer interaction

Modeling the Client to Presentation Layer Interaction

If we look at the Client from the perspective of the Application Server, the client is displaying a series of HTML pages. From each HTML page, Events can arrive back at the Server. These Events are physically HTTP Get or Post events, however, a logical semantic could be added into the data which accompanies the event. For example, if a "Submit" were pressed, an additional parameter "Event=Submit" could be included in the HTTP Request data. This could be used to turn the Physical Post Event into a logical "Submit" Event. This mechanism is widely used in Web Applications to identify specific messages from the client to the server e.g. an "Add" button would have a Form Submission including a parameter "Event=Add" and a "Remove" button would similarly have an "Event=Remove" parameter.

Thus the Client appears to the Server as displaying say Page 1, then receives an Event, some processing at the Server, send Page 2, Client displays Page 2, another event arrives, some more processing, Client displays page 3, and so on.

We can easily model what is happening at the client using Statecharts. Page 1 is State 1, Page 2 is State 2, Page 3 is State 3. What happens in between are Events.

Simple State Event example

Fig 5. Basic Statechart Diagram for 3 sequential pages of HTML

Actually, what is really happening can and will be more complex. A client in a current state, may produce an Event, the event may be accompanied by some parameters. On receipt of an Event, some conditions are evaluated which may require the Event parameters. The combination of the current state, the event and the result of the condition evaluation will determine the next state and possibly some actions which must be undertaken as that state transition is made. The diagram above shows a basic simple case where there are no parameters and no conditions to evaluate. As you will see later many state transitions are not usually this simple. We can state very clearly what is possible with this simple definition:-

[the current state + an event + some conditions] determines [the actions + the next state]

There is a well established architecture for User Interfaces which facilitates Event driven systems such as this known as Model-View-Controller or MVC. In recent years there has been a lot of confusing material published about MVC. I believe this was in part due to the arrival of increasingly complex GUI environments and the tight coupling of Views with Events and difficultly of separating out the concept of a View from the Client. This has led to a lot of confusion.

There are two requirements of the Controller in an MVC architecture. The first is the one we are most interested in. The Controller must determine the "control flow" of the system. It must process an incoming event from the User Interface and determine the next state of the User Interface. Much of the confusion in writing on MVC comes from the second requirement from the Controller which is to message the Model code(or Problem Domain) carrying out any actions required. This can change the state of the underlying business system. Much of the confusion has oriented around this. The state of the underlying business system and the state of the User Interface are two different, though often related, things. In a GUI environment the Model is then responsible for notifying View Classes that there has been a change. Normally, with a thin-client application, there is no way of notifying the client existing View. So notification mechanisms need not be discussed. [ Notification can be achieved through the use of Pushlets ]

Our thin-client web application is a close cousin of dumb terminal applications. The requirements for an MVC architecture in a dumb terminal system is very much simpler than some modern GUI MVC implementations as notification is not required. I would like to propose a very simple explanation for how MVC works. Controllers process input, they take Events, consider the current state of the client and determine the next state of the system. Based on the newly determined next state, the Controller invokes an appropriate View which displays the required output.

Controllers are all about input. Views are all about Output.

We are focusing the Controller responsiblities on controlling the flow and state of the User Interface rather than the underlying state of the business system. This may represent a subtle change for those who have attempted MVC designs in the past.

As we are building each View on demand, it must request data from the model every time it is instantiated. Hence, there is no Model to View notification. Simply the creation of the View object which must demand any necessary data from the model.

Views and Controllers together can be considered the Presentation Layer in a Web Application. However, as we will see it is easy to cleanly separate Views from Controllers in a Server-side Web Application.

MVC Simplified

Fig 6. Client to Presentation Layer Interaction showing the MVC Separation at the Server

The Model, on the other hand, is separate from the Presentation Layer Views and Controllers. It is there to provide Problem Domain services to the Presentation Layer including access to Persistent Storage. Both View and Controller may message down to the Model and it in turn will send back appropriate responses.

Altogether, this is a clean and simple implementation which is easily mapped against an Implementation Level Model of the User Interface using a Statechart Diagram.

An MVC Design

Fig 7. The complete MVC Architecture for a Thin-Client Web Application

Finally, we can consider how this Generic MVC model would look as a UML Class Diagram. Here we are showing the HTTPRequest wrapped as a class. On its arrival at the Application Server, it invokes a Controller (the exact mechanism for this is discussed in Part 2), the Controller evaluates some conditions using the Model if required. It decides which View should be built and invokes the appropriate View Class by calling its buildPage() method. The View in turn may require some information from the Model as it constructs the HTML for display. Finally, it streams the output to the client with its print() method.

Generic MVC Class Diagram

Fig 8. Generic Class Diagram for an MVC implementation

Login Navigation Diagram

Fig 9. Navigation Model for a Login Request and two subsequent screens

First a Login Screen with one of two alternate labels saying "Please enter your name and password" and "Your name or password was incorrect, please try again". This then leads to one of two screens, either Login is successful in which case, Main Application is reached or unsuccessful in which case the User is rejected with the Access Denied screen.

We can create an Implementation Model of this using a Statechart diagram as shown in Figure 10.

Login Attempt Statechart

Fig 10. Implementation Model Statechart for a Login Request and two subsequent screens

Here we are clearly showing the "Submit" Event and its three possible outcomes. A Valid Name and Password will lead to the Main Application state, an invalid name or password will lead either to the Try Again sub-state of LoginRequest or if there have already been 3 attempts then to the Access Denied Screen.

We can provide a physical mapping of this Implementation Model to our View-Controller Presentation Layer as shown in Figure 11.

Login Request Physical VC Implementation

Fig 11. Mapping the Implementation Model to Mediator Pattern.
Note that the central state element is a Controller and the other 3 are Views.

We can now implement this model as classes. Each Controller (or Event Handler) becomes a Class and each State which represents a buildable HTML Page or Frame also becomes a Class. The Event is wrapped inside our HTTPRequest Class as shown in Figure 12.

Login MVC Diagram

Fig 12. A Class Diagram for the Login Example, showing the LoginSession Model Layer class

In this example, our Controller class requires to call down to a Problem Domain Class in the Model, in order to evaluate whether the Login Name and Password are valid. The View classes do not require to call any Model classes in this example. The Controller calls the LoginSession.isNamePasswordValid() method which returns a boolean answer. This is used to determine whether the resultant state is MainApplication or whether to consider the number of attempts before selecting either TryAgain or AccessDenied as the resultant output.

The LoginSession class encapsulates the concept of a the period of time that a single client is visiting the web site. The period between first Logging In and finally Logging Out. The LoginSession must also timeout in the event that the User simply wanders off to somewhere else on the web. LoginSession contains the key attribute SessionID which is used to identify a returning client on each HTTP Request. The SessionID is issued on the first HTTP Request. An incoming HTTP Request without a Session ID is considered to be a new user. That user will be issued with a Session ID and prompted to Login.

The LoginSession will also be holding references to the SystemUser <<Role Player>> class after it has established a successful ID and Password for a System User. It also stores a collection of visited States for that particular client during this Session. A LoginSession is often called a User or Client Context.

Scaling Up

The example shown above is small. A single form submission leading to 2 subsequent screens. It involves 3 states, two sub-states and a single controller. However, this architectural approach can be scaled to significantly larger applications and complex User Interfaces.

In order to implement such an architecture and design on a large scale web server application, an engine to drive the State machine and the View-Controller implementation in the Presentation Layer is required. Such an engine would need to interpret incoming Events from HTTPRequests and translate them into logical events such as "Submit Password", it would then invoke the appropriate Controller Class based on the current state of the client, execute the condition evaluation and move the client to the appropriate next state. The correct View Class for this next state would be invoked and it would then output the HTML for that View to the Client. The Client Browser will have changed to the new State.

This architecture can be used to deliver a deterministic, large scale user interface for a web application which remains manageable and understandable even when a large number of people are working on code development. Such a design is more easily tracked for Project reporting purposes and can lead to significantly tighter control on Presentation Layer development, improving development estimates and helping to keep delivery dates on track.

In Part 2

Part 2 will be showing how we can design and build an MVC Statechart engine as generic server-side plumbing and cleanly implement a Presentation Layer which is initially developed as an HTML prototype then modelled as a Navigation Diagram, developed into an Implementation Statechart Diagram and finally coded as a series of View and Controller classes as the Presentation Layer of a Web Server application.

Part 3 will explain complex details such as Transaction Scoping and Exception Handling.

Acknowledgments

I would like to thank Ian Horrocks for review comments on this article.  This article was first published in October 1999 and republished in the 2nd edition in June 2000.

posted @ 2008-02-26 12:54  hq5460  阅读(345)  评论(0编辑  收藏  举报