More with Three-Tiered Design

Reuven shares more tips on the usefulness and limitations of three-tiered architecture—and just what is it?
Editing a Person

Now that we have seen how to add a new person to the database using our People object, let's try a slightly more difficult task: changing a person's first name, using the update_first_name method. (See Listing 3 and Listing 4 at ftp://ftp.linuxjournal.com/pub/lj/listings/issue82/ for examples.) We can only invoke this method once we have already selected an individual, which means that our editing form will have to let us do so.

While it might be tempting to let users select an entry by typing a name or e-mail address into a text field, this is prone to too many errors to be effective. Instead, we will allow users to choose from a <select> list. This removes the possibility that a user will enter an e-mail address (or another defining characteristic) for a person who might not be in our database.

We want to use a unique key to choose the person whose first name will be modified—but at the same time, it seems a bit impersonal to present a list of e-mail addresses. My solution was to go back to the People object (People.pm) and define a new method, get_names_and_addresses (see Listing 5 at ftp://ftp.linuxjournal.com/pub/lj/listings/issue82/). This returns a list of array references, where each array reference contains a name and an e-mail address. The former can be used as a unique key (and as the “value” within an <option> tag), while the latter can be used for display purposes. We can thus iterate over the e-mail addresses and produce a <select> list as follows:

<select name="email">
% # Iterate through the names and addresses,
  # printing them out
% foreach my $info (@names_and_addresses) {
  <option value ="<% $info->[1] %>"><% $info->[0] %>
% }
</select>

Allowing users to edit other user attributes would proceed in a similar way. Indeed, so long as you ensure that the user chooses a key that uniquely identifies the user, you can change any and all of its attributes using a similar type of form.

Adding an Appointment

Now that we have seen how we can use the People object to indirectly manipulate our People table in the database, we will start to look into our appointment book, handled by the Appointments object. This object allows us to add an appointment with a particular person on a particular day and time.

In order to accomplish this, we will (once again) need two components. The first component (add-appointment-form.html, in Listing 6 at ftp.linuxjournal.com/pub/lj/listings/issue82) produces an HTML form that allows users to enter a new appointment into the system, choosing a person from a predefined <select> list. (If this were an actual project, I would put the <select> list in a separate component, allowing other components to produce a menu of entries in the address book.) In addition, we have to know when the appointment starts, as well as when it ends. Once again, I prefer to have people select a date and time from <select> lists, since it removes the problems associated with time and date formats.

The following Mason code produces the three <select> lists that we need in order to have the user choose a month, day and year. By defining the @months and @years arrays in advance, we can make the code more readable, as well as update the system for future years quickly and easily:

<select name="begin_month">
% foreach my $month (@months) {
    <option value="<% $month %>"><% $month %>
% }
</select>
<select name="begin_day">
% foreach my $day (1 .. 31) {
    <option value="<% $day %>"><% $day %>
% }
</select>
,
<select name="begin_year">
% foreach my $year (@years) {
    <option value="<% $year %>"><% $year %>
% }
</select>

The second component, add-appointment.html (see Listing 7 at ftp.linuxjournal.com/pub/lj/listings/issue82), allows us to add a new entry into the appointment calendar. It checks (using an <%args> section) that we have submitted all of the required name-value fields from add-appointment-form.html. We then issue the same kinds of basic checks that our other components have done.

Are These Three Tiers?

Now that we have demonstrated how easy it is to create a three-tier web application, it's time to consider how many tiers we're really using. Does the term “three-tier” really apply here?

The term “three-tiered architecture” grew out of a dissatisfaction with another popular architecture known as “client/server”. For example, databases and web servers are both examples of modern client/server systems. Just as a client/server system typically refers to two physical computers, a three-tiered system refers to three physical computers, with each tier residing on a separate machine.

By contrast, the simple three-tiered application we have examined certainly had three layers in that there were distinct software systems that had clear goals and APIs and made it possible for the application and database layers to speak through a common middleware layer. At the same time, at least two of these layers (the web application and the middleware objects) were on the same computer without any real possibility for separation. If the web application were to become swamped with traffic, we could certainly add one or more identical Apache servers—but there is no way to put the application layer on one computer and the middleware objects on another.

So while I believe that we have now demonstrated some of the advantages of three tiers from the perspective of an application developer needing standard APIs, we have not seen a true implementation of such a system. In order to do so, however, we must have the ability to perform remote procedure calls (RPCs), such that a web application on one computer can invoke a subroutine or object method on another computer. This is possible and is getting increasingly easy with the growth of SOAP (Simple Object Access Protocol), but it brings with it a number of other problems and caveats, including the need to learn yet another transmission protocol.

While we're reconsidering how to define tiers—perhaps we should consider that the application developed does have three tiers, but that they are defined in a different way than we have considered until now. Instead of counting the tiers as (a) database, (b) middleware layer and (c) web server, perhaps we should count them as (a) database, (b) web server and (c) web browser? If we think in these terms, then we have indeed created a three-tier architecture—but come to think of it, so has anyone who has ever written a CGI program that talks to a database.

Moreover, we can introduce additional layers of abstraction into the mix here, complicating things further. What about stored procedures, triggers and views created on the relational database? Although not a physical tier, it can certainly make life easier for the person writing either an object layer or an application that accesses the database. Indeed, stored procedures are often better than an object middleware layer, because they execute on the database and are precompiled, making them relatively speedy.

We can also execute code on the web client (i.e., inside of the web browser) using JavaScript. While I generally encourage my clients to avoid JavaScript as much as possible, this buggy, insecure language riddled with cross-platform incompatibilities is the only way to execute programs from within a web browser, rather than on the server.

So, when we have a web application that uses a relational database, stored procedures, an object middleware layer, a web application layer and client-side JavaScript divided between three computers, how many tiers do we have? It's probably still three, but the fact is that it doesn't really matter what you call it. In the end, a decent design that takes into account your project's specifications, including the need for future growth, is the right way to go—regardless of how it jibes with the latest buzzwords and techniques.

______________________

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix