6Application Architecture

Web application systems, like any other complex engineering artifacts, need an architecture that helps master their complexity by breaking them down into smaller parts with manageable inter-dependencies. Software application architecture is concerned with the following issues:

  1. The state structure of the application system to be designed is defined in the form of information models describing its information architecture.
  2. The goal of a code base architecture is to structure and partition the overall program code of an application in such a way that the fundamental software quality goal of maintainability is achieved.
  3. The distribution of the application system’s runtime components within a computer network is defined by a deployment architecture. A web app is distributed on the Web, which is a world-wide client-server network system with HTTP-based communication.

As in all cases of designing a complex system, no matter if a new building, a new space shuttle, a new computer or a new software application is to be designed, an architecture provides a kind of master plan for defining the structure of the system. Any good architecture is based on the following three principles:

  1. separation of concerns,which helps managing complexity by breaking a system down into smaller, functionally defined parts such that their
  2. interdependencies are minimized,
  3. keeping the more fundamental parts independent of the less fundamental parts (the onion principle).

Complying with these principles makes it easier to develop, or source, and update certain system parts independently of others.

The three most important parts of the code base of an app are:

  1. the model, which implements the app’s data model in the form of model classes, defining suitable data structures and constraints;
  2. the data storage management procedures, which set up a connection to a storage management system (typically, but not necessarily, an SQL database system) and use it for storing and retrieving persistent data;
  3. the user interface (UI) code, taking care of both information provision (or output) to the user, e.g., on the computer screen, and user input provided by user actions in the form of UI events, e. g., keyboard or mouse events, such that all required user interactions are supported.

The onion principle requires to keep the app’s model classes independent of

the UI code because it should be possible to re-use the same model classes with different UI technologies;

– the storage management code because it should be possible to re-use the same model classes with different storage technologies.

However, in many web application frameworks (e. g., in Java EE) the onion principle is violated.

6.1The Model-View-Controller (MVC) Architecture Metaphor

The most popular and most widely used code base architecture approach is the Model-View-Controller code base partitioning pattern. Although it has not been precisely defined, and has been implemented in many different ways, especially in web application frameworks, it is based on the principle of separation of concerns and on the fundamental insight that the model is the foundation for all other parts of an application, in particular for the user interface. Consequently, even if the MVC approach doesn’t provide a precise definition of what a ’model’ is, we can consider it to be a model-based approach.

Figure 6.1 The MVC code base architecture with the model as the foundation.

According to Wikipedia, the first MVC architecture was introduced to application programming with Smalltalk-76 by Trygve Reenskaug99 in the 1970s. In a later article about Smalltalk-80100, MVC is explained as a “three-way division of an application” that entails “separating (1) the parts that represent the model of the underlying application domain from (2) the way the model is presented to the user and from (3) the way the user interacts with it”. The authors, who also use the term “MVC metaphor”, point out that their approach would allow programmers to “write an application model by first defining new classes that would embody the special application domain-specific information”.

Notice that the model is defined to consist of classes that capture the required domain information. We call them model classes.

In this original MVC approach, there is no well-defined concept of a user interface (UI). The ’view’ is defined as comprising the output side of a UI, only, while the user input side is separated from it and subsumed under the term ’controller’. This does not reflect how a UI is really organized: by combining certain forms of application output with certain forms of user input like two sides of the same coin. A general UI concept includes both the output (the information output provided to the user, as well as system actions) and the input (including information input provided, as well as actions performed, by the user).

The Smalltalk MVC metaphor was developed for (monochromatic) text-screen-based user interfaces with no general notion of UI events. This may explain why they did not consider an integral concept of a UI. While they distinguished between the state of objects in the model and their state in the UI, which are both in the scope of a user session, they did not consider the distinction between the model state and the database state.

In his web essay GUI Architectures101(2006), Martin Fowler summarizes the main principles of the original MVC approach in the following way:

  1. Separation between UI and model.
  2. Divide UI into a ’controller’ and ’view’.
  3. Views are synchronized with the model (by means of a data binding mechanism).

While the first and third principles are fundamental for the architecture of software applications, the second principle has just a historic meaning and was soon abandoned by the developers of Smalltalk.

Compared to the 1980s, computers, human-computer interaction and software application architecture have evolved. In particular, the establishment of the Web as the predominant computing platform has made web browsers to be the most important infrastructure for user interfaces.

The MVC terminology is still widely used today, especially by web application frameworks, but with different meanings ascribed to “M”, “V” and “C”. Typically, the “view” denotes the app’s code for the HTML-forms-based user interface, and the “controller” denotes the code that is in charge of mediating between the “view” and the “model”.

In many MVC approaches, the “model” is tightly coupled with the underlying database technology, often via an object-relational mapping (ORM) approach mapping classes to tables and objects to table rows. This tight coupling between model classes and database tables violates both the fundamental principle of minimizing interdependencies (because there is no need that model classes depend on database tables) and the onion principle discussed below.

For instance, in the Active Record102 paradigm of the influential Ruby-on-Rails framework, which has been adopted by many other web application frameworks (such as by CakePHP), the “model” is a direct representation of the schema of the underlying database system, where each entity table of the database is represented by a “model” class that inherits data manipulation methods for performing Create/ Retrieve/ Update/Delete (CRUD) operations. In this table-to-model-class mapping approach, the “model” depends on the schema of the underlying database and is therefore tightly coupled with the underlying ORM technology. While this may be a suitable approach for a database-first development methodology, where an SQL database is the foundation of an application, it is certainly not a general approach and it turns the model into a secondary asset.

Also in frameworks based on ORM annotations, such as Java EE with JPA annotations, the C# framework ASP.NET MVC with Entity Framework and Data Annotations, or the PHP framework Symfony with Doctrine annotations, the “model” is coupled with the underlying ORM technology through the ORM annotations woven into the model class code, thus making the model dependent on the ORM technology used. All these frameworks use the Data Mapper103 approach for performing CRUD operations based on ORM annotations.

6.2The Onion Architecture Metaphor

The term “onion architecture” was coined by Jeffry Palermo in a series of blog posts104 in 2008. The main principles of this architecture metaphor are (1) to use a hierarchy of dependencies, where less fundamental (or central) parts depend on more fundamental parts, but never the other way around, and (2) the most fundamental part is the model, which implements the application’s data model in the form of model classes while data storage is a separate and less fundamental part that must not be coupled with the model.

In fact, Palermo and his followers put a lot more into this architecture metaphor, such as using “repository interfaces” and “service interfaces”, but this is not really essential for the onion metaphor. Also, they are using a different terminology. When they are using the term “domain model” instead of simply model, they are confusing the term “domain model” with “implementation of data model”,which is what model classes do. A data model is derived from an information design model, which may itself be derived from a domain information model. This is the basic development chain in model-based software engineering.

In principle, a Data Mapper approach, if it is not based on a platform-specific ORM (annotation) technology, but rather on some form of platform-independent mapping logic, can be used for storage management in an onion architecture.

6.3LogicalversusPhysicalUser Interface

The idea of a logical UI model, also called view model, was first proposed (under a different name) by Martin Fowler in his post on the Presentation Model105 in 2004, where he stated that the view model “pulls the state and behavior of the view out into a [view] model class”. This means that the logical content of a UI is abstracted out from a concrete “physical” UI, which has specific renderings of the logical UI fields and “commands” (user actions). Logical UI fields are rendered in the form of UI widgets that may have their own state, while logical UI commands are rendered in the form of suitable UI events.

Later, in 2005, the view model concept was adopted by John Gossman (from Microsoft) in his blog post Introduction to Model/View/ViewModel pattern for building WPF Apps106 and popularized under the architecture pattern acronym “MVVM”.

In a user interface for a Create/Retrieve/Update/Delete (CRUD) data management operation, a view model class would be bound to exactly one model class, but could support more than one view (class). A view model class would have properties that are bound to the widgets of the supported view(s), using either one-way or two-way data binding, and methods that are bound to corresponding commands (command binding).

Typically, most view fields directly correspond to properties of the underlying model class, although they may have a different name. For these fields (or view model properties), a data binding to the corresponding model properties is needed. But a view model class may also have additional properties, some of them may represent view fields that are not bound to a model class property, while others may represent auxiliary fields that are not shown in the UI.

The methods of a view model class are invoked when a corresponding command has been issued by the user through creating a UI event, to which the command has been bound.

Dividing up the overall UI code into a view model part and a view part creates a certain overhead that may not be justified in certain cases. While the use of a view model is justified for all apps with CRUD data management operations, it may, for instance, not be justified for visualization user interfaces.

The main benefits of view models are that they facilitate: (1) UI design, (2) the testing of the UI logic, and (3) the maintenance of the UI.

6.4MVC Web Applications

The MVC terminology is still widely used today, especially by web application frameworks, but with different meanings ascribed to “M”, “V” and “C”. In some approaches it is extended by adding another layer, called “view model” abbreviated by “VM”, which we will discuss later in the course.

In the original MVC proposal, the “model” consists of model classes implementing the app’s data model, while today many MV(VM)(C) frameworks do not include any concept of model classes, but rather refer to data objects (or records) as “models”. Also the term “controller” is ambiguous today. In the original MVC proposal, the term “controller” referred to the handling of UI events including user inputs. Today, it typically refers to all the glue code needed for mediating between the model and the view, including the code for routing.

In summary, in today’s frameworks, the term “model” vaguely refers to the data sources of an app, while the “view” denotes the app’s code for the user interface, which is based on CSS-styled HTML forms and DOM events, and the “controller” typically denotes the (glue) code that is in charge of mediating between the view and the model. There is widespread agreement that

  1. the model should be independent of the view and the controller, implying that the model must neither invoke the view nor the controller (in the model code, there should be no calls of any view or controller procedures);
  2. the controller may invoke both the model and the view;
  3. the view may invoke the controller.

However, as shown in the following diagram, it is not clear if the view may also invoke the model, or if it needs to route any calls of model procedures via the controller. Both approaches are being used in practice. The first approach, where model procedures can be called from the view, is simpler and leads to a leaner controller.

The second approach, where the view is decoupled from the model by routing all calls to it via the controller, is called the mediating-controller MVC approach, shown in the following diagram. It has the advantage of fewer dependencies and providing better support for model-view synchronization based on data-bindings.

In many MVC web application frameworks, the model is tightly coupled with the underlying data storage technology, often via an object-relational mapping (ORM) approach mapping classes to tables and objects to table rows. This tight coupling makes model classes dependent on a specific database technology or even on corresponding database tables. It therefore violates the onion principle, since the model is the most fundamental part of an app, so it must not depend on any other part.

6.5Deployment Architectures

In addition to an information architecture and a code base organization architecture (like MVC), we also have the cross-cutting issue of how to distribute the different parts of an app when it is deployed, so we also need a deployment architecture.

Traditionally, most parts of a web app have been executed on back-end computers, while only its HTML/CSS user interface code has been executed on the front-end (or client) side, within a web browser. Today, with the rise of modern JavaScript, we have the option to replace traditional back-end web apps with JavaScript front-end apps, where most parts of the app are executed within a web browser on a front-end device. Such a front-end web app may use either local storage or a (remote) cloud storage service, as illustrated by the two architecture diagrams shown in Figure 6.2.

Figure 6.2 Architectures for front-end web apps

In both cases, the JavaScript code of the front-end app is loaded together with its start web page. While using local data storage (with JavaScript’s localStorage or indexedDB APIs) does not require any connection to the Internet after the initial loading of the app, using cloud storage via HTTP messaging with the XMLHttpRequest (XHR) API does require an Internet connection.

Typically, but not necessarily, a front-end web app is a single-user application, which is not shared with other users.

A back-end web app is a web app where essentially all work is performed by the back-end component, including data validation and user interface page creation. It does not have any front-end component, except the HTML-forms-based, and possibly JS-enriched, user interface pages sent to the user’s front-end computer for being rendered by a web browser.

One important task of the controller, especially in back-end apps, is routing: mapping incoming HTTP request messages to a use case of the app, typically represented by a method of a class, such that either the corresponding user interface is provided in the form of a web page or the request message represents the corresponding form submission, which can be directly processed.

Today, with NodeJS, we have the option to deploy the JavaScript components of our app either on the back-end or on the front-end, or on both. In the future, due to WebAssembly, the same options may also be available to other programming languages. Web apps that run the same JavaScript code both on the back-end and front-end have been called “universal” (or “isomorphic”). This is especially useful for data validation code because in a responsive constraint validation approach, as discussed in Chapter 7, we validate user data immediately on input in the user interface, but we also validate it on the back-end before save. Modern JavaScript allows truly distributed apps.

The two diagrams shown in Figure 6.3 illustrate the distinction between the traditional back-end web app architecture and the new architecture of a (truly) distributed web app.

Figure 6.3 Architectures for back-end and distributed web apps

8_mvc_krasner_and_pope.pdf

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset