Server Requests

From CSSEMediaWiki
(Difference between revisions)
Jump to: navigation, search
Line 70: Line 70:
 
*A client consumes the services of the request classes by directly instatiating instances of the concrete classes, because there is no creation mechanism. This violates the [[Stable abstractions principle]] and [[Program to the interface not the implementation]], and couples the client to specific derived class implementations. Additionally this also violates [[Avoid inheritance for implementation]] - the ''XRequest'' class is used only to factor out common functionality for its children.
 
*A client consumes the services of the request classes by directly instatiating instances of the concrete classes, because there is no creation mechanism. This violates the [[Stable abstractions principle]] and [[Program to the interface not the implementation]], and couples the client to specific derived class implementations. Additionally this also violates [[Avoid inheritance for implementation]] - the ''XRequest'' class is used only to factor out common functionality for its children.
 
*[[Sequential coupling]] exists in both hierarchies of ''IRequestSender'' and ''IRequest''.
 
*[[Sequential coupling]] exists in both hierarchies of ''IRequestSender'' and ''IRequest''.
 +
 +
== Use of Patterns ==
 +
 +
The use of patterns was very restricted (I didn't have patterns in mind when designing this initial version). The following are roughly present:
 +
*Bridge pattern used to separate interface/implementation dependencies between ''IRequest'' and ''IRequestSender'' instances.
 +
 +
*A distorted Proxy for composition: ''XRequestSender'' is composed of, and forwards most method calls to an ''HttpPOSTRequestSender'', additionally containing (private) methods for calculating & adding a checksum.
 +
  
 
= Improved Design =
 
= Improved Design =
Line 85: Line 93:
 
*Classes that allow requests to be sent over the network
 
*Classes that allow requests to be sent over the network
  
== Initial Design ==
 
  
This is my initial attempt at the design.
 
 
[[Image:initial.png]]
 
 
== Design Summary ==
 
 
 
 
 
== Possible Design Flaws ==
 
 
* Possibly [[Lazy class smell]], for the numerous concrete implementations of ''XRequest''. Many 1 method classes, which have a very similar implementation (populate a list, though with different parameters). This raises the issue of whether the requests can more appropriately be handled by representing them as classes, or as runtime object instances of a more general class.
 
 
* Something feels weird in the diagram about how requests are sent/ An ''IRequestSender'' is capable of sending any/many ''IRequest'' instances; an ''IRequest'' cannot send itself, while an ''XRequest'' can send itself and be sent by an ''IRequestSender''. The whole interaction feels strange, there are cyclic dependencies between reuquest classes and ''IRequestSender''.
 
 
* The request class hierarchy works. Polymorphism is only utilized in dealing with ''IRequest'' instances in  ''IRequestSender'' implementations. The child classes of ''XRequest'' are always used directly; ''XRequest'' only exists to factor out the common functionality of child classes. Possibly breaks [[Class hierarchies should be deep and narrow]], however as suggested by that maxim, does extract common behaviour into ''XRequest'' superclass. The shallow but wide hierarchy "smells".
 
 
== Design Patterns ==
 
*Bridge pattern used to separate interface/implementation dependencies between ''IRequest'' and ''IRequestSender'' instances.
 
  
*Proxy for composition: ''XRequestSender'' is composed of, and forwards most method calls to an ''HttpPOSTRequestSender'', additionally containing (private) methods for calculating & adding a checksum. Alternatively a Decorator could add this functionality. (Also probably better suited to have this implemented somewhere in the ''IRequest'' hierarchy.  [[Behavioral completeness]],[[Separation of concerns]],[[Coupling and cohesion]])
 
  
*Decorator/Strategy/Chain of Responsibility might be useful for reducing the number of ''IRequest/XRequest'' child classes by further factoring out common functionality.
 
  
 
= Code & Installation =
 
= Code & Installation =

Revision as of 00:13, 1 October 2010

Contents

Background

My design study is related to my part time job, where I am developing an application that can retrieve and plot data from a device that monitors air quality. The application runs on the user's PC and connects to the device via a USB to serial bridge. The following features of the application/device combination are of interest to this study:

Handling Device Registrations

  • When the device is connected to the app, internet connectivity can be used to electronically register the device.
  • If a user has problems with registering a device, they can use the app to send an assistance request to the manufacturer.
  • Lastly, a user can view the registration details of the current device, if they know the e-mail address the device was registered with.

Handling Device Calibrations

  • The application allows the user to calibrate a device using an automated process. Only authenticated users may perform calibrations.
  • Further, the manufacturer stores a complete copy of the calibration process, and final calibration parameters.
  • Lastly, a device may only be calibrated (new parameters applied) after automated approval. The manufacturer is notified when the new parameters are applied to the device.

All notifications/data exchanges with the manufacturer are via HTTPS POST traffic to a webserver. The focus of this design study is the design of the application-side model for the various requests needed to interact with the server in handling registration and calibration requirements as above. In the initial design, the server request necessary for each of these bullet points is modelled as a class. In the revised design, I look at improving that model by using objects to represent the different requests instead of a class-per-request approach.

Requirements

Practically, for the purposes of my work on the application the requirements are largely generic and as follows:

  • something that works
  • is as nicely designed as practical
  • is as easy to understand and maintain as practical
  • is flexible so that new server requests can be added without much hassle

Of course, for the purposes of this design study the goal is additionally to:

  • achieve a good balance of flexibility, practicality, and a decent level of adherence to good-OO principles

Deliverables

  • Classes that model the different request types
  • Classes that allow requests to be sent over the network

Initial Design

I built this design over a short period a few months ago. At the time I had just read a bunch of articles that didn't clearly define the advantages of using composition over inheritance, so I proceeded and made a mess of interfaces/composition and created the following design. It doesn't feel elegant, but it works and is what has been running app-server interactions since. Here I have renamed some of the classes to more general names.

Initial.png

How it Works

Representing Requests

The IRequest interface is the most generic representation of a server request. In the style of HTTP POST/GET requests, a request is defined simply as something which can return a list of name-value pairs (i.e. something that has a GetPOSTParameters() method), representing the request parameters and their names (in particular a .NET 2.0 NameValueCollection). In the context of the application, the children of XRequest define exactly which parameters are required/optional for a particular request and their types.

XRequest is the abstract implementation of IRequest, implementing the shared functionality (send/get response) for all child classes. Each concrete request is then defined by a particular implementation of GetPOSTParameters() method - returning a list with different name-value parameter contents.

The requests represented by the classes in the diagram above are as follows:

  • CalibrationAuthReq - represents an authentication request; POST data: username, password, device serial number;
  • CalibrationUploadReq - represents an attempt to upload calibration data to the server; POST data: username, password, serial, calibration log-1, calibration log-2, calibration value-1, calibration value-2; This request returns a confirmation code, which must be re-sent to the server to confirm that calibration parameters were applied to a device.
  • CalibrationConfirmationReq - represents the request that notifies the server that calibration parameters have been applied to a device. POST data: username, password, serial, calibration confirmation code;
  • RegistrationAssistanceReq - the request which submits an assistance request to the server; POST data: user's name, user's phone, user's email, device serial, user notes;
  • RegistrationDataReq - used to request the details of an existing registration; POST data: email the device was registered under, device serial;
  • RegistrationSubmitReq - used to submit data for registration. POST data: company name, contact name, address, country, email, phone, distributor, distributor phone, serial, user notes;

Sending Requests

Server requests are sent, and responses received using concrete insteances of IRequestSender. HttpPOSTRequestSender is the most generic concrete implementation of this interface - its methods implement the actual sending/receiving mechanisms. XRequestSender is a class with a specific implementation of the IRequestSender interface for the application's purpose. It uses a composition relationship, containing an HttpPOSTRequestSender instance. Functionally, after computing and attaching a checksum to a given IRequest, the class is used to delegate Send/Receive calls to the contained HttpPOSTRequestSender.

Using the classes together

The application creates concrete instances of the request classes, and interacts with them using the Send/GetResponse methods. The individual request objects then interact with the server using supplied instances of IRequestSender (concretely, XRequestSender). The application does not need knowledge of the IRequestSender family of objects, except for creating them and supplying them to request objects. Perhaps a factory method/class could tidy this up slightly.

Design Flaws

At a very superficial glance this does not feel right. The following are the issues & violated heuristics that I can verbalize about the bad feeling:

Use of Patterns

The use of patterns was very restricted (I didn't have patterns in mind when designing this initial version). The following are roughly present:

  • Bridge pattern used to separate interface/implementation dependencies between IRequest and IRequestSender instances.
  • A distorted Proxy for composition: XRequestSender is composed of, and forwards most method calls to an HttpPOSTRequestSender, additionally containing (private) methods for calculating & adding a checksum.


Improved Design

With the improved design I tried to produce a more general and more elegant representation for request and the sending system. The approach I took focussed on trying to create a design that reduces many of the flaws listed above. The largest design differences are in:

  • The addition of creation mechanisms that decouple a client from having to deal with concrete classes, and maintain the strength of the design's abstractions.
  • Moving to a generic Request class to represent behaviour common to all requests, and can be used to represent the different requests as variations in data/state instead of by needing separate classes.

Filip improved.png


Deliverables

  • Classes that model the different request types
  • Classes that allow requests to be sent over the network



Code & Installation

Since my study concerns server requests, testing it out depends on interaction with an actual server/server pages. I've provided a heavily stubbed set of pages that return sample data. A local web-server has to be installed in order to test my design. The code implementation is not 100% complete and I have taken some shortcuts for demo purposes, but most of the expected functionality is there and it largely resembles the UML design above.

Steps:

  • Download and install Xampp - http://www.apachefriends.org/en/xampp-windows.html
  • Run the Xampp control application (xampp-control.exe) from the install directory
  • Ensure the Apache module is running
  • Create a directory called "requests" inside xampp_install_dir\htdocs (e.g. C:\xampp\htdocs\requests)
  • Copy the php pages from the following archive to the "requests" directory
  • The source and VS2008 solution are available in this archive. Open the solution and run the program. The program tries to connect to pages in "http://localhost/requests/", so you must have completed the above steps successfully.
Personal tools