![]() |
Thin Client Coding TipsThin-client hardware and architectures have been discussed on this site. Related topics include Reasons To Use Two-Tier Fat Client Instead of Browser-Based Application Development Technology, JDBC Brings the Fat Client to Java, and IE4: The First Fat Client Browser. Still, I frequently get questions along the lines of "How do I write a thin client application?" or "How do I know if my application is a thin client?". This brief provides some thin client coding tips. Do not be fooled into thinking that these tips have no bearing on your work if you are not writing thin client software today. Even if you are deploying two-tier, or even single-tier, applications, many of these tips will help you produce better software. How Thin is Thin or Thinness is In the Eye of the BeholderBefore giving tips, however, I must reiterate that my idea of thin may not agree with your idea of thin, and that my idea of thin may not be appropriate for your application or deployment environment.Thin clients are often discussed in the context of three-tier architectures. In the typical simple description of three-tier, the tiers are labeled Presentation, Business and Data Access, or some trivial variation thereof. So, what does it mean to write the Presentation layer? Well, the code should be responsible two things:
The presentation layer can also be bounded by what it does not do:
Why Thin May Be UsefulI have argued that 2-tier, fat-client architectures are useful and have their place. This is not to claim the absence of usefulness for thin clients. Among the desirable attributes of thin-client architecture are
Even if you don't write thin clients, applying thin client discipline will allow you to produce more adaptable software. Finally, the TipsOK. You've humored me by reading all the preliminaries. Here are the tips, in no particular order. (Sorry Visual Basic haters, but code snippets are in VB.)
A UI event handler can have as many UI operations as you wantUse event handlers to provide a UI richness that enhances the user's experience. Update status bars, gray and ungray buttons, animate graphics, set colors, you name it. Your user interface will benefit from a speed optimization if the Presentation layer is separated from the Business and Data Access layers by a network, especially if it is a slow one.I especially believe in disabling and enabling controls based on whether they are valid. For example, a Save command button should not be enabled if a required field is empty. Therefore, I use code like the following.
A UI event handler can have either 0 or 1 non-UI operationBusiness or Data Access code may reside on different machine than the Presentation code. At the very least, then, we want to minimize calls from the UI code to the rest of the application.I believe in limiting the number of calls strictly to one because any sequence of calls is probably a business rule or business process in disguise. For example, the following code is executed when a new item is added to an invoice form.
This is a pretty simple routine, but it encapsulates both a business rule (the
price may be customer- and quantity-specific) and some implementation details
(an item knows its price, the row's bookmark is the item key). The rule and
implementation details must exist somewhere in the code, but an event handler
is not the right place, for at least two reasons. First, the rule and details
are likely to change, and one reason to use a thin-client architecture is to
minimize the impact of changes on the configuration management of the client.
Second, the rule and details may well be needed on more than one form. If they
are re-used via cut-and-paste, a maintenance nightmare slowly builds.
I prefer an event handler like
Do not cheat the previous tip by creating a "partner" class or module for each form (window)I've actually seen this coding style. A form called InvoiceForm gets initialized with a reference to an instance of InvoiceFormObject. The code for each event on the form is one line, such as
Now the form no longer has any references to business objects or database
access; this is all in the other object.
While this is a step in the right direction compared to "typical" fat client
coding techniques, there are some serious flaws.
First, there is the temptation to give InvoiceFormObject a reference to InvoiceForm or one or more controls on the form. Since InvoiceFormObject has business and/or database logic, it is not part of the Presentation layer. Since one of the goals of n-tier architecture is to be able to change the hardware platform on which each tier resides, we would want to be able to move InvoiceFormObject to a remote machine. To do this, we would have to now be able to pass references to the form and/or controls across the network. Even if we technically can, performance certainly can suffer. This is good general advice: do not pass references to UI objects to the other layers. Instead, pass values from the UI objects to the other layers, and set values of UI objects with values returned from other layers. For example,
A second and larger flaw is that the code in InvoiceFormObject may be needed for several forms. We do not want to have code duplicated multiple times through cutting and pasting. Logic related to a particular business process should be written once and shared by all forms that require it. A form (window) cannot be bound to a database in any wayPretend the Data Control does not exist. All controls are unbound. Yuck. The Data Control (or its equivalent in non-VB development environments) and bound controls, along with visual GUI and query builders, are the foundation of RAD as we know it in the fat client world. It is incredibly painful to return to all the procedural coding required to connect a database to a user interface, but that coding is currently necessary in the general thin client world today. (I say "general" because there are some decent tools, such as Cold Fusion Studio and Visual InterDev, for producing HTML clients without directly writing volumes of procedural code, but the process is not as fluid or visually rich as for building fat clients with Visual Basic, Delphi or PowerBuilder. It also so happens that, although Cold Fusion Studio and Visual InterDev produce applications that run with thin (browser) clients, it is not a fun exercise to try to re-work the code for a non-browser thin client. The UI code is totally interwoven with the data access code.)My personal wish is that environments soon include controls that can be bound to properties of arbitrary object instances, or perhaps even output parameters or return values of methods of said instances. Then the user interface could be declaratively connected to business process or business logic objects. This is a step beyond current Smalltalk and Java environments (Visual Age, PARTS, Visual Cafe) that allow procedural code to be generated for such links in a wizard-like way by interacting with the UI at design time. Separate business processes from other business rules and logicSince all business logic resides outside the Presentation layer, you may wonder what this has to do with writing thin-client code? I'm not certain it does. I do, however, think this is an important topic.Many (but not all) object-oriented software engineering experts that I admire recommend never creating separate classes for processes. They argue that, for example, an instance of a Product class should be able to re-order itself, or that an Invoice should be able to save itself and arrange for picking and shipment. Well, I have gone this route more than once and never liked where it led me. Simple processes typically worked out fine. More complex processes, however, require the services of many, many different classes. The class chosen to orchestrate the process becomes coupled to many otherwise unrelated classes. Likewise, the class assumes many responsibilities that are more clearly related to the process than the concept being modeled. Using separate classes to represent processes yields lightly coupled classes that model business entities, and heavily coupled classes that model processes. Since processes change more frequently than simple rules or attributes associated with business objects, most of the on-going software maintenance is concentrated on the process classes. Translated from the lower level of classes to the higher level of architecture service layers, similar advantages apply. Changes to processes affect only the Business services that implement processes. Further, the process services provide a layer of insulation between the UI and the business objects.
Copyright © 1998 Scott Nichol. 11-May-98 |