The essence of client-server computing is that two kinds of processes (units of program code) that are specialized for different tasks, running on possibly different hardware, applications software and operating systems co-operate to solve a computing problem. One kind (a client) makes a request of another. The other kind (a server) performs the service requested (if the request is a valid one). Many applications have been constructed to operate in client-server mode. For example, most Internet-based servicesnews readers, E-mail, the World-Wide-Webhave been designed this way. (These may be regarded as database applications in a way, but the database being accesseda collection of articles, or messages, or a listing of resources is not necessarily in relational form.)
In most cases, the machine on which the server is a powerful machine that resides remotely, while the client machine sits locally on the users desktop, but this is sometimes reversed. For example, in the X-Windows model of screen display, used widely on UNIX machines, a remote application running on UNIX (e.g., a supercomputer) can perform complex computations that are eventually designed to be the raw material for graphical output. This output is sent to a (local) machine with a request to display the data, using the X protocol. Therefore, the remote machine is the client. The local machine processes this request and converts it into the appropriate display commands for the local hardware. Therefore the local machine is the server.
At other times, both the client and the server may be running on the same CPU as separate processes, and all that the end-user has is a view into the client process (for example, through a dumb terminal).
Often, but not always, you have a situation where several clients are connected to a single server. However, in the field of databases, a local machine may be connected to several remote databases in client-server mode, with each application running in a separate window. Therefore a more usual situation is multiple clients, multiple servers.(This is especially true of the Web, where your browser- the client- connects to servers from all across the world. These servers are servicing numerous other users along with you simultaneously.
Relational database applications are well suited for client-server computing.
Client-Server Computing and Relational Databases
In relational database client-server computing, there are two components to the client-server communication protocol. One deals with communication at the network (hardware) level, the other deals with the database level.
At the network level, there are several communications protocols used for two machines to talk with each other. The communications standard used in the UNIX world (and for clients that talk to UNIX-based servers) is the Transmission Control Protocol/ Internet Protocol, abbreviated to TCP/IP. This is increasingly becoming a de facto standard for all long-range communication. (There are also vendor-specific protocols such as Apples ADSP.)
At the database level, the protocol is vendor specific. Relational database vendors usually base their protocol on SQL (Structured Query Language). SQL was originally created at IBM for their DB2 database package, and, for better or worse, has become a de facto standard in the mini and mainframe relational database world.
Client-server database computing has pluses and minuses. The real advantage of client-server computing is increased modularity. A well-designed client-server protocol is operating-system independent, and even hardware-independent. Any software that abides by the rules of what a client should do (and includes the necessary library subroutines to facilitate doing so) can be a client to a particular server. From that point onward, the only limiting factor is the client developers ingenuitythe client package may be a custom program aimed at performing a specific task, or it may be an integrated development environment with a full programming language and debugger.
Coupled with the increased modularity is economy of communication. Because the client is an active participant in the communication rather than a passive display, we can make its CPU do some real work. The messages between client and server are typically based on a high-level (i.e. highly concise) protocol that is translated at either end into a much larger number of individual instructions that are executed on either machine.
With respect to databases, there are certain other advantages. We can look at these pluses from two points of view: from that of an organization moving "down" from the mainframe-terminal model to client-server, or from that of an organization moving "up" to client-server from a LAN-based micro DBMS.
Looking from Above: Better User Interfaces
In the best of all possible worlds, the server does what servers do best; namely, it manages data. The client machine does what clients do best; it provides a robust and friendly user-interface. If the client product also has add-ons which perform tasks like business graphing or drawing, very fancy front-ends can be designed.
Server database packages are not typically bundled with user-interface building tools. While this may seem a bit like selling an automobile without an engine, one must remember that client and server run on different operating systems. Many RDBMS vendors have therefore wisely focused on doing what they do best (managing data on heavy-iron machines) and leaving the user-interface tools to those who understand this client machines (PCs and Macs) much better. (For example, the 3rd party interfaces to Oracle databases are, according to most developers, considerably superior to Oracles own.)
When you wish to use a graphical user interface to view and manipulate a remote database, you are forced to use client-server computing. This is because, if the remote machine generated large volumes of raw graphics and sent them across the network to individual machines, the network would grind to a halt. It makes more sense to send only the data to be manipulated, and make the data display the responsibility of the local machine.
The user interface advantages mentioned here apply only to mainframe programmers who are hemmed in by archaic user interface tools. People who have moved "up" to client-server from a robust micro-based DBMS (which have good user interfaces anyhow) cannot be sold on this point.
Looking from Below: Robust Data Dictionaries
Server packages generally have a very strong data dictionary. A data dictionary is simply a database about a database. It holds knowledge of the objects in the database and how they interact with each other. Thus, it may store rules regarding management of the dataconsistency checks on a field (maximum, minimum or default values), or actions to be performed when records in particular tables are modified, added or deleted. The server constantly consults the dictionary as it interacts with users, thereby enforcing integrity and security checks, and controlling what individual users can and cant do with data.
In many micro packages data dictionary facilities are non-existent. Integrity checks have to be written into the code that manages the forms through which the user interacts with the data. If different users interact with subsets of the same data through different forms, the integrity checking code must be duplicated for each form. With such packages, problems arise when the rules change or new rules are to be added. With a central data dictionary, on the other hand, the changes would have to be made in just one place; they will take effect irrespective of which form is used to view the data. With a weak micro package, such changes have to be made in tens to hundreds of places. Here is a situation ripe for Murphys Law: the integrity checks imposed by the procedural code in different forms may be accidentally inconsistent with each other, like two clocks in the same house giving different times.
Client-server database development has a seamy underside. Some of these are due to the client-server model itself, the second due to limitations of the particular vendor package youre working with.
Firstly, the developer has to be a lot more meticulous about detecting error situations. Because of the increased modularity that client-server entails, there can be multiple points of failure, and each of these must be anticipated.
In terms of programming, this means that most routines in a client library are functions returning a value rather than procedures client-server paradigm per se. The function typically returns a number which is either a SUCCESS value, or one of several error values that tell you what went wrong. When you write client code, every function must be tested for success before proceeding to the next step, or else the user will be faced with a barrage of error messages.
Ill now describe package-specific limitations.
Since client-server computing is based on messages being passed from the client to the server. These messages are typically long strings of commands, or activation of particular subroutines that request particular services. From the user-interface point of view, it means that the users keystrokes or mouse clicks have to be converted by the client software to the appropriate server requests. Depending on the environment youre working with, you can either spend a little time, or lots of time writing code to do this conversion.
To achieve this, Microsoft has created a standard meta-protocol called ODBC, for Open Database Connectivity. If you are developing an application that connects to multiple classes of server, your code makes ODBC calls rather than server-specific calls. Specifically, if you use the ODBC flavor of SQL, you are guaranteed that it will be correctly translated to the vendor-specific SQL dialect of the database that you are connecting to. The ODBC drivers (which may be supplied by Microsoft, or by the server vendor) have the responsibility of translating ODBC calls into server-specific calls.
The best client packages, such as Microsoft Access, use ODBC to take care of almost all the message generation, so that the developer may not even care which table is stored locally, and which table happens to lie on a remote server. Depending on what is being done, s/he may not even have to worry about which type of server (e.g., Sybase, Oracle, DB/2).
Restrictions on the Ability to Browse
When working with a standalone micro database, the end user has the freedom to browse all the records in a database of arbitrary size, to go back and forth, and to make changes in a totally unrestricted fashion. This is possible because data is being transferred at high speed between the users hard disk and the memory of the machine.
When data is being shipped across a network (probably from halfway across the continent over a slow connection), things get complicated. If the shipped data has to be held in memory on the local machine, memory can easily run out if the user asks to see too many records a large table. (A smart client/server engine will use the local hard disk to buffer the data.)
But even if we ignore the problem of storage, were still left with the problem of the speed of data transfer. Most applications deal with the situation by shipping only the data that is required by the user, as formulated through a query. Historically, some DBMS engines were pathetic in their ability to let the user move back and forth within the data fetched by a query; a task as simple as scrolling backwards in the data, for example, required Herculean programming convolutions. It may seem incredible that after having scrolled to the thirtieth record in a selection you couldnt simply just get back to the first, but thats how it used to be (such engines lacked a feature called scrollable cursors). The situation is much better at present.
Limitations in the Server Data Manipulation Language
When the client wishes to manipulate server data, it must do so using the language of the server, in this case SQL. The problem is that SQL is not a single unified language, but a family of dialects (like BASIC) with markedly different functionality between vendors. Vanilla (or ANSI) SQL is not a computationally complete language: it has nothing by way of conditionals or iterators, no subroutines, no complex data structures. However, some vendors have added extra features to make their own SQL dialect approach computational completeness. Most advanced in this regard is Oracles PL/SQL dialect.
This difference shows up in batch updates to large volumes of data. If you have to update the contents of a field in most or all records of a table using a complex computation, you will generally have to download each record, get the value of the field, compute the updated value on the client, and post this value back to the server. However, some servers may have an SQL dialect expressive enough to let you do this update on the server itself through a server subroutine or function (i.e., without downloading the data to the client).
ODBC does not take advantage of such server-specific capabilities; it is a least-common-denominator product. It does, however, allow "SQL pass-through", which means that, if conditions demand it, you can bypass the normal ODBC mechanisms and explicitly send a server-specific message (typically a SQL command) from your client.
Delayed Validation and Clunky Ergonomics
When creating forms for data entry or edit in a micro DBMS package, the programmer typically codes in validation checks for one or more enterable fields in the form. The check for a field is activated the moment the user tries to tab out of the field.
With many micro database packages, many validation checks, such as referential integrity and uniqueness, do not have to be coded at the form level, but can be defined at the data dictionary level. Even though the check is stored at the dictionary level, it is activated at the form level just like a hand-coded form check (i.e., when the user tries to tab out of a field).
With a networked C-S architecture, field-by-field communication between the client and the server (such as foreign key checks when a wildcard pattern has been entered) may generate considerable network traffic, depending on the table to be looked up. Some packages attempt to minimize this traffic by not automatically consulting a remote data dictionary every time a field is filled in. Instead, the client will communicate with the server by default, only after a record has been completely filled in by a user. After the record is sent to the server, the data dictionary performs its checks and reports possible errors.
But this causes ergonomic problems: a user does not want to be told, after filling in a multi-page form, that the first field was an invalid foreign key. In such a situation, the system designer has several choices:
1. Redundantly duplicate the servers validation logic within the client application.
2. If it is important enough to do so, the developer must hand-code certain checks such as foreign-key validation, so that the server table is checked as soon as the user tries to tab out of the foreign-key field.
3. A really smart client package would, at startup, scan the server data dictionary, capture the existing validation rules in the dictionary, and internalize them so that they could be consulted in a manner transparent to the user and the developer. It is possible to create Web-based frameworks that actually do this.
To be a productive client-server developer, you have to know both sides well. This means that you have to be able, among other things, to plunge into a command-line driven server environment when you need to. (This is in addition to all the skills required to be a good database developer.) The size of the requisite knowledge base ensures that highly productive client-server developers are always a rare and precious commodity.
The name of the client-server game is efficiency. You should be able to take advantage of your servers capabilities to the fullestthe objective is to do as much computation on the server as possible, and download only the ultimate or penultimate results to the client for viewing (or further processing). Theres a lot of testing involved herebefore deciding to make the server do some computation, you have to benchmark the task with the client doing the work, and then decide if the performance bottleneck is bad enough that you want to "server-ize" the code.