DekGenius.com
[ Team LiB ] Previous Section Next Section

1.3 Application Tiers

We've gotten all this way without defining enterprise applications. This is because they often defy simple definition. Enterprise applications range from mainframe-based transaction processing applications with aging green-screen terminals to phone systems, from traditional client/server to intranet web sites, and even to Amazon.com.

All enterprise applications are divided into tiers. These tiers are sometimes referred to as components, although this term is a little misleading; more than one component is frequently present on any given tier. A tier can be thought of as a collection of software with a particular scope of operation and a defined set of interfaces to the outside world.

Different people divide enterprise applications in different ways. The official J2EE application model, as discussed above, divides an application into a Client Presentation tier, a Server Side Presentation tier, and a Server Side Business Logic tier. Enterprise information systems, such as databases, constitute a fourth tier.

We call this the "official" model because it's what Sun's J2EE documentation proposes, but in reality, there's a lot of scope for individual choice. For example, when thinking about application tiers for this book, we came up with five layers:

Client Presentation tier

Provides a user interface to the end user. The client can be "thin" (typically a web browser), "fat" (a full scale application), or something in between.

Server Side Presentation tier

Provides the Client Presentation tier with the materials, such as HTML, required to produce the user interface.

Server Side Business Logic tier

Includes the business methods sitting behind an application, performing actions like registering customers, taking orders, and managing shipping. These can often be thought of as the "verbs" of an application.

Server Side domain model

Includes the data model used by the business logic tier, or the "nouns" of the application. The domain model includes entities like customers, orders, stock records, and any other information that is manipulated in the course of the application's life.

Enterprise Integration tier

Connects the application to other systems. This connection can take place via CORBA, web services, Message Oriented Middleware, email, or even sneakernet.

Notice that we've called two of these tiers "presentation" tiers. That's because both are responsible for creating the interface ultimately presented to the client. Different technologies are used to implement the client-side and server-side presentation tiers (HTML and JavaScript on the client side, Servlets, JSPs, and so forth on the server), but both are complementary.

These five tiers are certainly not canonical. Many applications don't include an Enterprise Integration tier, and many writers correspondingly don't treat it as a tier at all. The business logic and domain tiers are often combined. The persistence engine for the domain tier, typically a relational database, is often considered a separate tier because it is housed separately. We didn't list it that way because, in a perfectly compartmentalized application, the domain tier is the only part of the application that accesses the database layer.[2]

[2] This particular distinction is where a lot of people tend to play fast and loose, and often for good reason, since the domain tier can be most severe performance bottleneck in a large application. Much of Chapter 7 is devoted to addressing this issue. The database can also be seen as part of the Enterprise Integration tier, particularly if it plays host to a large quantity of application logic as well as raw data.

If we assume the client to be the "bottom tier" and the enterprise layer to be the "top tier," we can go on to say that tiers generally see higher tiers but not lower tiers. Furthermore, they should see as few other tiers as possible, using interfaces that are as tightly defined as possible. This makes it easier to modify one tier without affecting others. There are always exceptions to the order listed above. For instance, a fat client might skip the Server Side Presentation tier and interact directly with the business objects on the Server Side Business Logic tier via Enterprise JavaBeans. The same application may include a web interface where a Server Side Presentation tier component uses the same EJBs to create HTML.

1.3.1 Component-Based Development

We just mentioned that J2EE tiers are sometimes referred to, in error, as components. We shouldn't be too harsh, though, because it's a logical assumption to make and can even sometimes be true. A component is a self-contained piece of software with a known, well-defined interface that can be used by other pieces of software. According to this definition, a J2EE tier is a component, but it's a component that can be subdivided (at least hopefully!) into a number of subsidiary components, which in turn can be rearranged to modify the functionality of the software itself.

1.3.1.1 Characteristics of components

If areas of the program depend closely on each other, we say the components are tightly coupled. When one component is modified, its partner will usually need to be modified to match, and vice versa. For this reason, effectively sharing tightly coupled components can be a real challenge. When multiple developers work on these components, each developer risks breaking the entire application and the work of other developers. In the enterprise world, the situation becomes even murkier: individual applications can be components of large business process flows, and changing one small section can, in the worst possible case, cause entirely different applications to fail!

A component is specialized when it can only perform a specific task. While there is nothing inherently wrong with specialization, components that are specialized for a certain task are difficult to extend or reuse. To perform new tasks, the entire component must be copied before it can be changed. This divergence will cause maintenance headaches in the future, since updates will need to be repeated in several places.

Designing for change up-front can help solve these problems. Defining clear interfaces between components separates their interactions from individual implementations. As long as a component preserves its interfaces, it can change internally without breaking its partners. A component can even be replaced with an entirely different one, as long as the interfaces are the same. When components work together using these interfaces, they are said to be loosely coupled. Loosely coupled components can vary their implementation independently, which makes each part more likely to be reusable and easier to share.

To reduce specialization, larger components must be broken up into a collection of smaller ones. Code that is specific to a particular task should be separated out into a subcomponent, which encapsulates the task's functionality. This subcomponent can be modified and replaced independent of the rest of the application, promoting sharing and reuse.

In some ways, designing for extensibility may seem like a contradiction: expecting the unexpected. In fact, as a developer, you usually have some idea about where the software might evolve. This is often the case during iterative software development—you build a subset of the full product in each iteration, knowing in advance what features will be added by the time it is released. You can use this intuitive knowledge as a basis for making your software more extensible.

As software grows, however, it will probably be used in ways you never expected. Users will create new requirements on the program. If your design was not extensible, you will need to complicate it to meet these demands. Eventually, you will realize which areas of the program should have been extensible to begin with and rewrite large amounts of the program in order to retrofit them. The process of adding extensibility into an existing application is known as refactoring.

    [ Team LiB ] Previous Section Next Section