«Sharam Hekmat PragSoft Corporation Contents 1. INTRODUCTION 1.1 PURPOSE 1.2 SCOPE 1.3 SOFTWARE TOOL 1.4 GLOSSARY OF TERMS 2. ...»
Each screen in the user interface (e.g., a window, a dialog box, or a web page) needs to be
• A picture of the actual physical layout of the screen. If possible, this is best produced using the tools that come with the development environment. Most such environments are visual and provide resource editors for painting the GUI screens in an interactive fashion. This has the advantage that the screens can be used ‘as is’ later in the development cycle.
• For each element (i.e., widget) in the screen, the data associated with that element needs to be identified and its type specified. In most cases, this data is expected to map directly to an attribute in a business object.
• The validation rules for the screen elements need to be defined. These apply at two levels: (i) field-level validation rules applicable to a given element (e.g., valid date), and (ii) screen-level validation rules that operate across elements (e.g., ‘start date’ should predate ‘end date’).
5.2.2 Navigation The navigation paths across user interface screens need to also be defined. In a conventional interface, for example, this may involve specifying how an action performed in one screen (e.g., pressing a button) leads to the display of another screen. In a web-based interface, this will also involve the specification of the hyper links.
For example, consider the ‘Create New Tax Payer Record’ action in our tax office model. In this action, the user (a MailHandler) enters the details of the taxpayer into a form, which in turn creates a new TaxPayer object and adds it to the system. The following sequence diagram illustrates this scenario.
TaxPayerForm is an example of a boundary object. It collects the required information from the user and communicates it to the rest of the system.
In this case, it should be obvious that the contents of the form will closely resemble the attributes of the business object it corresponds to. The following design considerations are worth noting.
• Given that a change to a business object attribute will result in a similar change to the boundary object, a good design will attempt to minimise this overhead. Under the conventional client model, there is not much that can be done. A browser-based client, however, can alleviate this problem by using an intermediate generator object that can take a meta-data specification of the object and generate a matching boundary object for it.
• Field-level validation rules should be the responsibility of the boundary object. Simple field-level validation rules (e.g., numeric value) can be directly encoded into the boundary object. More complex field validation rules should be handled by invoking methods on objects that can perform the validation on behalf of the boundary object. Any form of validation that requires database access (e.g., valid postcode) is best handled by an object in the middle tier. Other complex filed validation rules (e.g., valid date) can be implemented by utility objects available in the front-end and shared across the user interface.
• Screen-level validation rules should be the responsibility of the underlying business object. For example, when requested to create or modify a business object, the business object should perform the necessary validations to ensure that the resulting object will be valid.
In favour of better usability, more and more modern user interfaces incorporate dynamic behaviour.
A typical example of this is when the value entered into a given form field affects the remaining fields, which may be enabled/disabled or displayed/hidden as a result. For example, in an account form,
Also, there are cases where the relationship between a screen and the underlying business objects is one to many. For example, a ‘fund transfer’ screen typically involves two account objects, and an ‘account summary’ screen may involve an account object and a list of transaction objects.
Dynamic screens and screens with one-to-many business object relationship are best supported through proxy objects in the middle tier. Coding these complexities in the proxy object rather than the boundary object results in greater decoupling of the two tiers.
Finally, most modern interfaces are required to support pick lists. A pick list is a list of possible values for a field, which the user can simply choose from, rather than entering the value directly. Pick lists may be static or dynamic. A static pick list provides a list of values that remain forever fixed (e.g., a list of 12 months in the year). A dynamic pick list provides a list of values that change over time (e.g., a list of available products). Static pick lists are simple enough to be coded directly into the boundary object. Dynamic pick lists should be implemented in the middle tier and made available to the front-end through appropriate interfaces.
5.3 Middle-Tier Models The middle tier is by far the most complex part of any 3-tier client-server system. This is where the bulk of the development effort should go to ensure a resilient design that can best cope with future changes. The scalability of the system, in particular, is directly impacted by the design of the middle tier.
The middle tier must achieve the following:
• Realise the business processes defined during business modelling.
• Release the business objects defined during application modelling.
• Implement transaction control (using the chosen middleware).
• Provide the services required by the front-end through a well-defined interface.
• Manage efficient communication with the back-end to ensure persistence for the relevant objects.
• Partition the middle tier into components that can be distributed across physical resources with minimal overheads.
The middle tier is constructed using three types of objects: entity objects, control objects, and boundary objects. These are discussed below.
5.3.1 Entity Objects An entity object is a persistent object that participates in transactions. The main entity objects in a system are the business objects themselves. Ideally, the persistence of an entity object is managed www.pragsoft.com 42 UML Process by the middleware. Where this is not the case, the entity object itself is responsible for issuing backend requests to maintain its own persistence.
Each business object specified during application modelling is implemented as an entity object. For example, in our tax office model, TaxPayer, TaxReturn, and TaxAccount are all entity objects. If these objects are specified fully during application modelling then their implementation as entity objects is fairly straightforward. In practice, however, this is rarely the case. Often additional analysis is required to pin down the business rules for each such object, and to devise appropriate algorithms for the non-trivial methods.
The implementation of an entity object should satisfy two things: (i) it should conform to the object specification, and (ii) it should preserve the relationships between the objects. For example, in our tax office model, there is a one-to-many aggregation relationship between TaxPayer and TaxReturn. The methods of these objects must ensure that this relationship is not violated.
Another important implementation consideration is that, ideally, an entity object should make no assumptions about the underlying data representation for object persistence. This ensures that changes to the data model will not directly impact the entity objects.
It is worth noting that not all entity objects are business objects. For example, consider a ‘workspace’ object that remembers the position of the windows for a given user and their preferences. This object needs to be persistent so that the next time the user logs in, his/her workspace can be restored. Another example is an object that records transaction related statistics for audit or tuning purposes.
An important property of an entity object is that it is shared by all users, i.e., different users can engage in different transactions that potentially impact the same entity object. Of course, such changes cannot occur concurrently. It is the responsibility of the transaction management mechanism of the middleware to manage this.
From a design point of view, because entity objects are persistent (i.e., require database IO), they consume precious resources. The middle tier design, therefore, should try to exercise control over the number of entity objects that need to be kept in memory at any point in time.
Most middle tier designs employ techniques such as smart pointers, object caching, and database connection pooling to reduce the load on the resources.
5.3.2 Control Objects A control object sits between boundary and entity objects, and performs a task on behalf of the boundary object. In other words, a control object is an extension of a boundary object. Rather than implementing the task directly inside the boundary object (tight coupling), the task is implemented
independently (loose coupling). This provides enormous flexibility. Specifically:
• Changes to the boundary object will not necessarily impact the control object, and vice versa.
Unlike entity objects, control objects are non-persistent, i.e., they do not need to maintain state beyond the scope of the task they perform. However, some control objects may need to maintain state for the length of the task (i.e., duration of conversation with a client). Based on this, control
objects are divided into two categories:
• A stateful control object needs to maintain the state of some (or all of) its attributes for the duration of the conversation with its client. When the client finishes with the control object, the state disappears. For example, a PolicyValue control object would need to remember the policy number attribute of the control object for the duration of the conversation.
• A stateless control object does not maintain a conversational state for a particular client. When a client invokes the method of a stateless object, the object’s instance variables may contain a state, but only for the duration of the invocation. When the method is finished, the state is no longer retained. For example, a CommissionPayment control object would require no state due to its atomic nature.
Except during method invocation, all instances of a stateless control object are equivalent, and hence can be assigned to any client. Because stateless control objects can support multiple clients and require no persistence, they can offer better performance and scalability for applications that require large numbers of clients. As a rule of thumb, therefore, you should avoid using stateful control objects unless you really need to.
In general, each transaction is implemented in the middle-tier by a control object. The control object is itself responsible for transaction control (i.e., commit and rollback). In some cases, this responsibility may be abstracted by the middleware through deployment descriptors.
However, not all control objects implement transactions. A control object may also implement a query. For example, a query to retrieve the last 20 transactions for a given account may be handled by a control object. This control object retrieves the account and the transactions (all entity objects) and makes them available to the client as required. This approach is particularly useful for queries that may return very large lists (e.g., retrieve all the transactions for a given account). Given that entity objects are expensive, the control object can be implemented to do this smartly. For example, it may retrieve only a limited number of transactions at a time, and retrieve additional transactions only when the client needs them.
Proxy objects that support boundary objects in the front-end tier (as described in Section 5.2.3) are also examples of control objects.