Client-Server vs. n-Tier

Traditionally, the term "Client-Server" means an application which talks directly to a database server, and often contains business rules. "n-Tier," also in traditional usage, means a thin client which talks to an application server, which in turn talks to a database server. Business rules are normally enforced on the application server tier.

However, "psuedo-n-tier" programming, where a single executable contains both the application server and thin client tiers, has recently become popular. In this model, there is a clear separation in code between application server (business rule) and client (presentation) functionality. It’s outside the scope of this paper to examine the advantages of this model in detail. When I discuss "n-Tier" applications, I’m referring both to "real" n-Tier systems with a separate application server, and "psuedo-n-tier" applications contained in a single EXE. From an optimization point of view, they are very similar.

There are some important differences between client-server and n-tier applications from an optimization point of view. I’m not going to cover how to optimize DCOM, but one of the most important differences originates from the principle that n-tier application servers should be stateless. Stateful n-tier systems do not scale well, which defeats one of the most important reasons for using the n-tier design.

In a client-server application, it’s OK to open a query and fetch records a few rows at a time. InterBase has some specific performance issues when a transaction is held open for a long time, which will be discussed in more detail below, but having a query open for a couple of minutes isn’t going to cause any problems in a client-server application. Stateless n-tier application servers, on the other hand, require that results of a query sent by the client tier to the application server tier be returned in a single method call.

Delphi’s TClientDataset defaults to this behavior by making -1 the default value of PacketRecords. It is possible to page through a large result set a few records at a time in an n-tier system, but each "page" of records must be returned from a separate call to the application server, in much the same way that each page of search results from a Google query is a separate request to the web server. Since the application server must be stateless it is not possible to presume that the same data module instance will supply subsequent pages of data, so you can’t simply keep a query open and fetch more records when requests come in for the next page.

In practical terms, what this means is that you can get away with things in a client-server application which you simply cannot do in an n-Tier system. In a client-server application, for example, it’s fine to open a query which would return 1000 records, if a FetchAll were performed, and fetch additional records as the user scrolls. In some cases there is no performance penalty for a query which could return millions of records, provided that you don’t actually attempt to fetch them from the server at once. (There may be a server-side penalty if the records must be sorted before it can return the first record, but there will be no network overhead). In an n-tier system, on the other hand, the application designer must be careful to ensure that the client cannot make requests to the server which would swamp the system, as fetching even a few thousand records at a time can introduce unacceptable delays in a user interface.

This means that stateless n-tier systems should be designed from the ground up to never require or request large result sets. There’s no penalty for doing this in a client-server application, of course, and in my opinion doing so tends to improve the user experience. But in an n-tier system this is a strict rule which must be followed from the outset.

Borland’s dbExpress components and the ADO.NET architecture practically require an n-tier design for interactive applications, and in my opinion the n-tier design should be used in all but the simplest applications. While the n-tier design does impose design restrictions which can seem burdensome at first, it pays back by allowing your system to scale much larger than a simple client-server design can.

Comments