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 fundamental engineering principle of separation of concerns, which helps in managing complexity by breaking a system down into smaller, functionally defined parts such that their interdependencies are minimized, keeping the more fundamental parts independent of the less fundamental parts. Such an architecture also makes it easier to develop, or source, and update certain system parts independently of others.
1.1. The Model-View-Controller (MVC) Architecture Metaphor
The most popular and most widely used approach in software application architecture is the Model-View-Controller code 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 basis for all other parts of an application, and in particular for the user interface, is the model. 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.
According to Wikipedia, the first MVC architecture was introduced to application programming with Smalltalk-76 by Trygve Reenskaug in the 1970s. In a later article about Smalltalk-80, 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. Notice also that in this early 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 original 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 Architectures (2006), Martin Fowler summarizes the main principles of the original MVC approach in the following way:
- Separation between UI and model
- Divide UI into a 'controller' and 'view'
- 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 pre-dominant 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 HTML-forms-based user interface, and the "controller" is in charge of mediating between the "view" and the "model", which is often tightly coupled, via an object-relational mapping (ORM) approach, with the underlying SQL database technology, violating the principle of minimizing interdependencies.
For instance, in the Active Record 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 data storage 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 JavaEE 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 code, thus making the model dependent on the ORM technology used. All these frameworks use the Data Mapper approach for performing CRUD operations based on ORM annotations.
1.2. The Onion Architecture Metaphor
The term “onion architecture” was coined by Jeffry Palermo in a series of blog posts 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 I don't think that's 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.
1.3. The Model-Storage-View-Controller (MSVC) Architecture Pattern
It should be clear that the three most important parts of any software application involving data management are:
- the model classes, which implement the application's data model, defining data structures and constraints;
- the data storage system, which is typically, but not necessarily, an SQL database system;
- the user interface (UI), including 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 MSVC architecture pattern follows the basic principles of the onion architecture metaphor by separating the model layer not only from the UI layer, but also from the data storage layer, and by making the model the most fundamental part, which must not depend on any other part. The MSVC architecture pattern also follows the good parts of the MVC architecture metaphor and its widely used terminology by using the term view interchangeably with user interface (UI), and the term controller for denoting the glue code layer needed for integrating the UI code with the underlying model classes and storage management code, or, in MVC jargon, for integrating the view with the model.
Using a model-based approach, the model classes of an app are obtained by coding the app's data model, which is typically expressed in the form of a UML class diagram. Since it is the task of the model and data storage layers to define and validate constraints and to manage persistent data, we need reusable model code taking care of this in a generic manner for avoiding per-class and per-property boilerplate code for constraint validation, and per-class boilerplate code for data storage management.
1.4. The "View Model": Distinguishing between "Logical" and "Physical" User 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 Model in 2004, where he stated that the view model "pulls the state and behavior of the view out into a [view] model class". Ths 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 Apps 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 beend 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: (1) they facilitate UI design, (2) they facilitate the testing of the UI logic, and (3) they facilitate the maintentance of the UI.