Software Architectures
The 1-Tier Architecture
Figure 2 is a simple diagram which shows a 1-Tier application where the Presentation logic, Business logic and Data Access logic are all contained within a single component:
Figure 2 - 1 Tier architecture
Although this diagram apparently makes it easy to identify the different areas of responsibility, in real life the actual program code may be so inter-mingled, inter-twined and spaghetti-like that it would be extremely difficult to locate the boundaries between each area of responsibility. A blurry mess like this is shown in figure 3:
Figure 3 - Typical program with blurry boundaries
The 2-Tier Architecture
My first exposure to a software architecture which had more than one layer was with a compiled language where all database access was handled by a completely separate component which was provided by the vendor, as shown in figure 4:
Figure 4 - 2 Tier architecture
This was a deliberate feature of the language as it enabled an application to be readily switched from one DBMS engine to another simply by loading a different data access component. No other part of the application was allowed to communicate with the database, so this component could be switched without affecting any other part of the application. This made it possible to develop an application using one DBMS, then deploy it with another.
Note that the presentation logic and the business logic are still intermingled.
The 3-Tier Architecture
This is where the code for each area of responsibility can be cleanly split away from the others, as shown in figure 5:
Figure 5 - 3 Tier Architecture
Note here that the presentation layer has no direct communication with the data access layer - it can only talk to the business layer.
Note also that you should not infer from this diagram that the entire application can be built with a single component in each of these three layers. There should several choices as follows:
- There should be a separate component in the Presentation layer for each user transaction.
- There should be a separate component in the Business layer for each business entity (database table).
- There should be a separate component in the Data Access layer for each supported DBMS.
With this structure it is easy to replace the component in one layer with another component without having to make any changes to any component in the other layers.
- You can change the UI component so that you can switch between a variety of different output formats, such as HTML, PDF or CSV.
- You can change the data access component so that you can switch between a variety of database engines, such as MySQL, Oracle or SQL Server.
This structure also provides more reusability as a single component in the Business layer can be shared by several components in the Presentation layer. This means that business logic can be defined in one place yet shared by multiple components.
The Rules of the 3 Tier Architecture
It is simply not good enough to split the code for an application into 3 parts and call it "3 Tier" if the code within each tier does not behave in a certain way. There are rules to be followed, but these rules are pretty straightforward.
- The code for each layer must be contained with separate files which can be maintained separately.
- Each layer may only contain code which belongs in that layer. Thus business logic can only reside in the Business layer, presentation logic in the Presentation layer, and data access logic in the Data Access layer.
- The Presentation layer can only receive requests from, and return responses to, an outside agent. This is usually a person, but may be another piece of software.
- The Presentation layer can only send requests to, and receive responses from, the Business layer. It cannot have direct access to either the database or the Data Access layer.
- The Business layer can only receive requests from, and return responses to, the Presentation layer.
- The Business layer can only send requests to, and receive responses from, the Data Access layer. It cannot access the database directly.
- The Data Access layer can only receive requests from, and return responses to, the Business layer. It cannot issue requests to anything other than the DBMS which it supports.
- Each layer should be totally unaware of the inner workings of the other layers. The Business layer, for example, must be database-agnostic and not know or care about the inner workings of the Data Access object. It must also be presentation-agnostic and not know or care how its data will be handled. It should not process its data differently based on what the receiving component will do with that data. The presentation layer may take the data and construct an HTML document, a PDF document, a CSV file, or process it in some other way, but that should be totally irrelevant to the Business layer.
This cycle of requests and their associated responses can be shown in the form of a simple diagram, as shown in figure 6:
Figure 6 - Requests and Responses in the 3 Tier Architecture
If you look carefully at those layers you should see that each one requires different sets of skills:
- The Presentation layer requires skills such as HTML, CSS and possibly JavaScript, plus UI design.
- The Business layer requires skills in a programming language so that business rules can be processed by a computer.
- The Data Access layer requires SQL skills in the form of Data Definition Language (DDL) and Data Manipulation Language (DML), plus database design.
Although it is possible for a single person to have all of the above skills, such people are quite rare. In large organisations with large software applications this splitting of an application into separate layers makes it possible for each layer to be developed and maintained by different teams with the relevant specialist skills.
3 Tier Architecture in operation
When an application is developed it is not (or should not be) constructed from a single large component. There are usually lots of small components (sometimes called 'modules', or 'classes' in OOP), each performing a particular function, and the application is the sum of those parts. This allows new functionality to be added without necessarily having any effect on any existing components. The advantage of a layered approach is that a component in a lower layer may be shared by multiple components in a higher layer, as shown in the figure 7:
Figure 7 - 3 Tier Architecture in operation
Here you see that a component in the Presentation layer can communicate with one or more components in the Business layer. A component in the Business layer communicates with the component in the Data Access layer, but may also communicate with other Business layer components. There is usually only one component in the Data Access layer as the application database(s) are usually handled by a single DBMS engine. It is possible to switch to a different DBMS engine simply by changing this single component. It is also technically possible for different parts of the application to deal with different DBMS engines at the same time, as shown in figure 9.
In my largest application I have 2,000 components (user transactions) in the presentation layer, 250 in the business layer, and 1 in the data access layer. I have heard of some implementations which have a separate Data Access Object (DAO) for each individual table in the database, but more experienced developers can achieve the same functionality with just one. In my own implementation, for example, a single DAO can deal with every table in the database. However, I have a separate class file for each of the major DBMS engines - MySQL, PostgreSQL, Oracle and SQL Server - so I can easily switch from one to another by changing a single entry in my config file.
Note also that the connection to the database is not opened by any component within the Presentation layer. This should only be done within the Data Access layer when instructed to do so by the Business layer, and only the moment before an operation on the database is actually required. This is called the "Just In Time" (JIT) method as against the "Just In Case" (JIC) method. When the Business layer decides that it needs to talk to the database it follows these steps:
- Identify which DBMS is relevant for the database table.
- Instantiate an object from the relevant class file, which is usually a shared singleton.
- Pass a collection of variables to the DBMS object which will be used to construct the relevant query. This allows the query to be constructed according to the needs of that particular DBMS engine. The Oracle and SQL Server databases, for example, do not use OFFSET and LIMIT for pagination.
- Execute the query and wait for the response.
- Deal with the response before returning it as an array. Different DBMS engines, for example, have different methods of dealing with auto-increment columns or sequences, so the code to deal with these differences is contained within the DBMS object and totally invisible to the calling object.
This approach allows an instance of my application to access database tables on more than one server, and even more than one DBMS engine.
Aren't the MVC and 3-Tier architectures the same thing?
There are some programmers who, upon hearing that an application has been split into 3 areas of responsibility, automatically assume that they have the same responsibilities as the Model-View-Controller (MVC) Design Pattern. This is not the case. While there are similarities there are also some important differences:
- The View and Controller both fit into the Presentation layer.
- Although the Model and Business layers seem to be identical, the MVC pattern does not have a separate component which is dedicated to data access.
The overlaps and differences are shown in Figure 8 and Figure 8a:
Figure 8 - The MVC and 3-Tier architectures combined
Here is an alternative diagram which shows the same information in a different way:
Figure 8a - MVC plus 3 Tier Architecture
You may think that any implementation of MVC could automatically be regarded as an implementation of 3-Tier, but this is not the case. In every implementation of MVC which I have seen so far there has been one simple but fundamental mistake which makes this impossible, and that is where the database connection is made. In the 3-Tier Architecture all communication with the database, and this includes opening a connection, is done within the Data Access layer upon receipt of a request from the Business layer. The Presentation layer does not have any communication with the database, it can only communicate with it through the Business layer. With all the MVC frameworks I have seen so far the database connection is made within the controller, and the connection object is then passed down to the model which then uses it when necessary. This is a mistake often made by beginners and those who have been poorly educated.
The worst example of this mistake I have ever seen was where a Controller opened up 3 different connections to the same database server instance in order to communicate with 3 different databases in that server. Each of these connections was then passed to a different Model component which may not actually use that connection. An experienced programmer will immediately spot the flaws in this approach, flaws that could have a significant impact on performance:
- Opening up multiple connections to the same server just to access different databases in that server is a waste of resources. A competent programmer will know that once a connection has been established it is possible to switch the identity of the default database, or even to prefix each table name in the SQL query with the relevant database name. It is possible to access multiple tables from multiple databases in a single query, so it is not necessary to have a separate connection for each database. All that is required is that the application be aware of both table names and their associated database names, and that the DAO be smart enough to remember the current database name so that it can switch to another when necessary. Unfortunately most MVC frameworks assume that all tables are contained within a single database, which makes using multiple databases a bit of a problem.
- Opening up a connection before it is actually required is a waste of resources. This is the "Just In Case" (JIC) method where what should be used is the "Just In Time" (JIT) method.
Another mistake I have found with some implementations is that they think that data validation (sometimes called 'data filtering') should be performed within the controller before it is passed to the model. This does not fit in with the definition of the 3-Tier Architecture which states that such data validation logic, along with business logic and task-specific behaviour, should exist only within the business layer or model component. By taking data validation out of the model and putting it in the controller you are effectively creating tight coupling between the controller and the model as that controller cannot be reused with a different model, and tight coupling is something which is supposed to be avoided in order to produce 'better' software. Loose coupling would enable a controller to be shared by multiple model classes instead of being fixed to just one.
When properly implemented, an application which is developed using the 3-Tier Architecture should have all its logic - data validation, business rules and task-specific behaviour - confined to the Business layer. There should be no application logic in the Presentation and Data Access layers, thus allowing either of those two layers to be changed without affecting any application logic.
What are the benefits of the 3-tier architecture?
It is all very well describing something like the 3 Tier Architecture, but nobody is going to make the effort to switch from their current arrangement unless there are benefits to be made, so what exactly are the benefits of this architecture? According to some there are lots of expenses but no benefits at all, as expressed in the following Sitepoint blog:
It's main function (independence of user interface, business rules and data storage/retrieval) only helps when migrating or extending to another script-language/data engine/platform. But this only happens very very few times in an Application Lifetime.
This is a very narrow-minded view from a person of limited experience. The aim of using the 3-Tier Architecture is not just to make it easier only when you change your database engine or programming language. It is also useful when you want to either replace your Presentation layer or create an additional Presentation layer. If you have ever worked on a variety of 3-Tier and non-3-Tier applications you would be able to see the differences, and therefore the advantages, for yourself.
The main advantages of the 3 Tier Architecture are often quoted as:
- Flexibility - By separating the business logic of an application from its presentation logic, a 3-Tier architecture makes the application much more flexible to changes.
- Maintainability - Changes to the components in one layer should have no effect on any others layers. Also, if different layers require different skills (such as HTML/CSS is the presentation layer, PHP/Java in the business layer, SQL in the data access layer) then these can be managed by independent teams with skills in those specific areas.
- Reusability - Separating the application into multiple layers makes it easier to implement re-usable components. A single component in the business layer, for example, may be accessed by multiple components in the presentation layer, or even by several different presentation layers (such as desktop and the web) at the same time.
- Scalability - A 3-Tier architecture allows distribution of application components across multiple servers thus making the system much more scalable.
- Reliability - A 3-Tier architecture, if deployed on multiple servers, makes it easier to increase reliability of a system by implementing multiple levels of redundancy.
Another not-so-obvious benefit which can only come from actual exposure to having developed multiple applications using the 3-Tier Architecture is that it becomes possible to create a framework for building new applications around this architecture. As each of the layers specialises in just one area of the application it is possible to have more reusable components which deal with each of those areas. Such components can either be pre-built and delivered as part of the framework, or generated by the framework itself. This reduces the amount of effort needed to create a new application, and also reduces the amount of effort needed to maintain that application.
Comments
Post a Comment