Architecture is the organizational structure of a system. An architecture can be recursively decomposed into parts that interact through interfaces, relationships that connect parts, and constraints for assembling parts. Parts that interact through interfaces include classes, components and subsystems
Software architecture is “the structure of the components of a program/system, their interrelationships, and principles and guidelines governing their design and evolution over time.”
UML 1.3: A system is a collection of connected units that are organized to accomplish a specific purpose. A system can be described by one or more models, possibly from different viewpoints.
IEEE Std. 610.12-1990: A system is a collection of components organized to accomplish a specific function or set of functions.
When automation first hit business, it was in the form of a huge “Mainframe” computer. Here, a central computer served the whole business community and was accessed via dumb terminals. All processing took place on a single computer – and therefore in one place. All resources associated with the computer (tape and disk drives, printers etc.) were attached to this same computer. This is single tier (or 1-tier) computing. It is simple, efficient, uncomplicated, but terribly expensive to run.
Figure 1 – Single Tier Architecture
Figure 1 shows a physical layout of a single tier environment. All users run their programs from a single machine. The ease with which deployment and even development occurs makes this model very attractive. The cost of the central machine makes this architecture prohibitive for most companies, especially as system costs and return on investment (ROI) are looked at carefully nowadays.
Dual Tier Environments
In the 1980s, a revolution happened in the world of business computing: the Personal Computer (nearly unimaginable until then) hit the streets. The PC quickly became the standard equipment on desks around the world. The demand for personal software was also in demand and, with the advent of Windows 3.0, this demand became a roar.
In order to provide personal software which ran on personal computers, a model needed to be found where the enterprise could still share data. This became known as the client/server model. The client (on the personal computer) would connect to a central computer (server) and request data. With limited network bandwidth, this would offload the need for expensive infrastructure since only data would be transmitted, not the huge graphics necessary to make a windows application display. In Figure 2, we see the very model implemented in most organizations today. This model is also quite easy to implement. All you need is an RDBMS, such as MS-SQL Server 2000, running on Windows 2000 Server and a PC running TCP/IP. You application connects to the database server and requests data. The server just returns the data requested.
Figure 2 – Client Server Physical Model
There are, however, several problems with this model:
- The connections are expensive – they take a long time to establish and require a lot of RAM on the server. Because the fact of connecting is slow, most applications connect when launching the client application and disconnect when the application is shut down. Of course, if the application crashes, then the connection is left open on the server and resources are lost.
- One can only connect a limited number of users to a server before SQL server spends more time managing connections than processing requests. Even if you are willing to increase server resources exponentially, as your user base grows (get your corporate wallet out) there still comes a time when your server will choke. This can be solved in part by splitting the database in two or three and replicating the data. This is definitely NOT recommended as replication conflicts can occur. The more users you connect, the more errors you’re likely to get.
- This method is so cost-ineffective. Many users only use their connection 2-3% of the time. The rest of the time it is just sitting there hogging memory resources. This particular problem is usually resolved artificially, by using a TP monitor such as Tuxedo which pools and manages the connections in order to provide client/server for the masses. TP monitors are quite expensive and sometimes require their own hardware platform to run efficiently.
Figure 3 puts the above into context and shows the logical system components – most of which are on the client.
Figure 3 – Logical View of a 2-Tier Architecture
With the advent of the Internet, many people jumped to the conclusion that the days of the mainframe were back. Client/Server had obviously failed, personal computers had failed and, above all, Windows was on its way out. A host of “thin client” applications were developed usually by overzealous IT managers hoping to wrest computing control back from the users. TCO – Total Cost of Ownership was the watchword of the day and everyone was consumed by downsizing the client. Thus 3-tier applications were born. These applications run the traditional client/server model but from a web server.
Figure 4 – 3-Tier Thin Client Architecture
The client only displays the user interface and data, but has no part in producing the results. Figure 4 shows the physical representation of such architecture, whilst Figure 5 gives a logical view.
This architecture presents one advantage over the former: a well implemented web server can manage and pool database connections as well as running the applications. The disadvantage is that the web server is quickly overwhelmed by requests and must either be clustered or upgraded.
Figure 5 – Logical 3-Tier View
Did you also notice that the software model has not significantly changed over the 2-tier model? We have merely moved the 2-tier client processing onto the web server. Also the thin client user interfaces, by their very nature, are not as rich as their Windows counterparts. Therefore, applications developed using this model tend to be inferior to their Windows counterparts.
The clue in really making an application scalable, as you may have guessed, is to split up the processing (in the red boxes) between different physical entities. The more we can split it up, the more scalable our application will be.
“Isn’t this expensive?” I hear you cry? I need a different server for each layer. The more layers, the more machines we will need to run. Well, this is true if you have thousands of users accessing your system continuously, but if you don’t, you can run several layers on the same machine. Also, purchasing many lower-spec servers is more cost-effective than one high-spec server.
Let’s explore the various layers we can create, starting from the logical model in Figure 5
Overview of an N-Tier System
The Data Layer
The data layer can usually be split into two separate layers. The first will consist of the set of stored procedures implemented directly within the database. These stored procedures will run on the server and provide basic data only. Not only are they pre-compiled and pre-optimized, but they can also be tested separately and, in the case of SQL Server 2000, run within the Query Analyzer to make sure that there are no unnecessary table scans. Keep them as simple as possible and don’t use cursors or transactions. Cursors are slow because processing rows one by one instead of as a set is inefficient. Transactions will be handled by the layer above, as ADO.NET gives us much more control over these things.
Figure 6 – N-Tier Logical Model
The next layer consists of a set of classes which call and handle the stored procedures. You will need one class per group of stored procedures which will handle all Select, Insert, Update, and Delete operations on the database. Each class should follow OO design rules and be the result of a single abstraction – in other words handle a single table or set of related tables. These classes will handle all requests to or from the actual database and provide a shield to your application data. All requests must pass through this layer and all concurrency issues can and must be handled here. In this way you can make sure that data integrity is maintained and that no other source can modify your data in any way.
If your database changes for any reason, you can easily modify your data layer to handle them without affecting any other layers. This considerably simplifies maintenance.
Business Rule Layer
This layer is implemented in order to encapsulate your business rules. If you have followed best practices, you will have created a set of documents which describe your business. In the best of cases, you will have a set of use-cases describing your business in precise detail. From this you will have been able to create a class association diagram which will help you create your business layer.
Here we find classes which implement your business functionality. They neither access data (except through the data layer) nor do they bother with the display or presentation of this data to the user. All we are interested in at this point are the complexities of the business itself. By isolating this functionality, we are able to concentrate on the guts of our system without the worry of design, workflow, or database access and related concurrency problems. If the business changes, only the business layer is affected, again considerably simplifying future maintenance and/or enhancements.
In more complex cases it is entirely possible to have several business layers, each refining the layer beneath, but that depends on the requirements of your system.
This is one of the optional layers and deals with data flow to and from your system. It may or may not interact directly with the user interface, but always deals with external data sources.
For instance, if you send or receive messages from a messaging queue, use a web service for extra information, send or receive information to another system, the code to handle this would be in this layer. You may wish to wrap your whole application in XML so that the choice of presentation layer can be expanded. This would also be handled in the Workflow Layer.
This layer handles everything to do with the presentation of your system. This does not just include your windows or web forms (or your user interface), but also all the classes which will help you present your data.
Ideally, your event method implementations within your form classes will only contain calls to your presentation layer classes. The web or windows forms, used for visual representation only interface seamlessly with the presentation layer classes which handle all translation between the business layer/workflow layer and the forms themselves. This means that any changes on a visual front can be implemented easily and cheaply.