Web Application Design: Layered Architecture

Web Application Design: Architecture

Layered Architecture

Layered Architecture and Managing the dependencies

Less connections (Interfaces)

Unidirectional Dependency

Single-Dependent Dependency

Interface Injection

Adaptation of the Generic Pattern

Where to start?

 

In software applications, Architecture is the organization of highest-level design elements. Or according to Wikipedia:

The term software architecture intuitively denotes the high level structures of a software system. It can be defined as the set of   structures needed to reason about the software system, which comprise the software elements, the relations between them, and the properties of both elements and relations.

Among the different architectural patterns, the Layered Architecture Pattern has emerged as the most widely used pattern, particularly for web applications. Most web applications use some kind of variation of this pattern.

Layered Architecture

The goal of Layered Architecture is to achieve Separation of Concerns (SoC) and modular design in a special and optimal way.

Let’s review some of the general properties of layered architectures.

 

Layered Architecture is a pattern that separates application concerns into separate modules called layers. In a layered architecture, modules are organized as layers in a stackwise fashion (in a logical sense), hence the name layered architecture.

 

Layered Architecture and Managing dependencies

In a system composed of modules, these modules have to interact with each other in order to achieve the goal of the system. These interactions will inevitably result in some sort of dependencies among modules. Dependencies, if not managed properly, can result in inflexible software (e.g. hard to modify, hart to extend etc) with tight coupling between modules. There are different ways for managing dependencies to avoid tight coupling. At the architectural level, one such way is to organize the modules into layered pattern.

 

Layered architecture pattern is a type of modular design pattern, that is specifically aimed at reducing software complexity by reducing and simplifying dependencies – increasing module autonomy. Modules in layered pattern are arranged in a stackwise form, hence the name layered pattern.

 

Let’s see how layered architecture pattern achieves this goal.

 

Lesser connections between modules

When two modules are connected or interfaced, it means that they are using one another’s services, or at least one of them uses the services of the other one. That is one module’s functionality depend on the service provided by the other module – a case of dependency. This situation, obviously, increases the chance for tight coupling between the modules, which makes it difficult to change one module independent of the other. Consequently, the more connections among the modules in a system, the more complex and less flexible the system will be. Hence, one of the goals of any good design strategy should be to minimize dependencies in terms of the number of connections between modules, thus reducing complexity and increasing flexibility.

 

 

For example, if there are n modules in a system, in the worst case, there can be n(n-1) dependencies between the module (counting boths sides of the dependencies). And in the best optimal case, only n – 1. In terms of number of connections (hence dependencies) between layers, Layered Architecture closely approximates this optimal limit.

 

Unidirectional Dependency

Another important feature of layered architecture is that it allows only for unidirectional dependencies. That is, in a dependency relation between two modules/layers, only one of them depend on the other, typically higher layer depending on the lower one(s). For instance, the Service Layer (a higher level layer) depends on Persistence Layer (a lower level layer), but the persistence layer does not depend on the service layer. Ideally, it should not even know that service layer exists at all.

 

If on the other hand, two modules are both depending on each other (bi-directional dependency), in that case, if module A is changed, module B may need to be changed as well. But, changes in module B, may further require changes in module A, in circular way, making the task of modification difficult.

 

 

Without even seeing any concrete implementation or example, we probably agree that a unidirectional dependency is better – easier to manage – than a cyclic dependency.

 

Single-Dependent Dependency

Another feature of a layered architecture is that each layer knows only about the layer immediately below itself. Thus, if one layer is changed, it may only affect the layer immediately above it. For example, in the architecture shown below (on the right), if layer A is changed, it may only affect the layer above it, B, leaving layer C unaffected, which does not depend on A. While on the left design, if layer is changed, it may require both layers B and C to be changed.

 

 

This way of organizing modules allows for the parts of the application to be changed in a localized way, in isolation, without affecting other parts of the application.

Interface Injection

Interface Injection is not a requirement of Layered Architecture. But, using with Layered Architecture usually results in a more flexible design.

 

Interface Injection is a technique for reducing coupling by making the dependent module depend on abstractions, not on implementation. The technique is implemented by injecting an interface between two modules. The diagram below shows going from a case of direct dependency to depending on an interface.

 

In general, a module’s implementation is a lot more likely to change than its interface, and Interface Injection makes use of this fact to reduce coupling of the dependent module to the service module. In this way, if implementation of Module B changes, Module A will be unaffected by this change.This rule can be applied at various levels of design: from designing larger modules at the architectural level, down to class level design. In fact, it is one of the important principles of object-oriented design called (SOLID).

 

Applying Interface Injection to layered architecture, we will get something like in the following figure, where a layer is composed of two sublayers: interface sublayer and implementation sublayer.

 

 

Interface sublayer consists of the set of interfaces (in the sense of Java interface) and the implementation sublayer consists of the set of concrete classes implementing those interfaces, plus other classes needed for the workings of the layer. For example, if this pattern is used with Data Access Layer (DAL), if at some point the data source changes and we need to change the implementation to reflect that change, the clients of DAL who depend on interfaces, will be totally unaffected by this change.

 

Layered Architecture for Web Applications

So far, we discussed layered architecture in a more general sense. Now, lets explore the adaption of this pattern for web applications.

For Java EE applications, a typical layered architecture may look like the following.

 

 

  • Domain Layer (DL) encapsulates the business logic of the application.
  • Service Layer serves as a mediator between the Web Layer and Domain Layer.
  • Data Access Layer handles the task of saving and retrieving data to and from data source, while hiding data source access details from the rest of application. This allows the rest of application (the layers above it) to operate within their object-oriented world without concern about communication with the external data sources such as a relational database.
  • Web Layer: front-end, responsible for handling user interactions: receives user actions and presents information to the user.

 

We will discuss each of the modules/layers with some details, dedicating a section to each.

 

The layered architecture shown above, nicely matches the stackwise formation of general pattern. But, a rearranged representation of it may be closer to the actual organization of the modules in a web application. This representation is shown in the figure below.

 

 

According to this model, more than one layer depend on Domain Layer. Although, this breaks the single-dependent-dependency rule, discussed above, this is a fact that stems from the nature of these applications. This topic will be discussed under domain layer heading.

 

This is the archicture used in the Quiz Website application.

 

Web Application Design: Introduction

When it comes to Java EE applications, there are not many online sources available out there that present the subject of core application design in a unified and coherent manner – especially at an introductory level. Or at least, there is not a source like Microsoft’s MSDN for Java EE. Although, there are myriads of online materials on Java/JEE topics, they are mostly focused on technology side of things; not so much on architecture and design.

In this series of articles, we will look at some of the main design patterns – employed in designing web applications – such as Layered Architecture, MVC Pattern, Domain Modeling, Repository pattern, DAO pattern, Object-Relational Mapping (ORM), Dependency Injection etc.

One thing is important to note: most of these patterns are not specific to web applications; they are generic and can be (and are) applied across variety of applications including desktop and mobile ones. Taking this fact into account, whenever a pattern is generic, we will treat it as such, without limiting it to a particular use case such as web applications.

Often, it is easier to speak of a design pattern in isolation, but in practice, developing real-world applications involves integration of several patterns. Hence, beside understanding each pattern, we also need to understand their relations to other patterns. To demonstrate both of these aspects, a demo application is presented that integrates all of the discussed patterns in a complete end-to-end web (Java EE) application.

The application is built with Spring and Hibernate frameworks and MySQL database. Although the discussion of most patterns, as was already mentioned, is independent of these technologies. Whenever something technology-specific is presented, such as Spring’s dependency injection or Hibernate’s object-relational mapping, it will made obvious to the reader.

Now, let’s quickly review what “design patterns” is.

Design Patterns

Design patterns are common solutions to commonly occurring problems. The emergence of design patterns stems from the very nature of software systems. That is, although there are countless number software applications out there, there are a number of patterns – from a design perspective – that appear and reappear in almost all of them. Mastering these patterns not only adds to one’s arsenal of tools while practicing software design and development, it also gives one a much deeper insight into the nature of software systems.

Most of the patterns are solutions that have evolved over years, or decades in some cases. Learning, and hopefully mastering, them have great benefits. For instance, instead of trying to invent an artifact that already exists, one can use that which has gone through many processes of trial and error and has been relatively perfected as a result.

Another advantage of using common design patterns is that it provides a somewhat common artifacts and language to the developers, making their communication and exchange of ideas easier.

For a full treatment of the subject of Design Patterns, you may refer to what is now being called The Bible of the subject, Design Patterns: Elements of Reusable Object-Oriented Software.

Resources

  1. Design Patterns: Elements of Reusable Object-Oriented Software
  2. Design Patterns (Wikipedia)