[This post is part of the developer's manual preview published on this blog. You can find temporary TOC here.]
The very first question we should answer when talking about the new Sitefinity backend architecture is: why? The second one is what do you get if you embrace it. This topic will answer these two questions.
The problems of the old architecture
The old architecture that Sitefinity developers used to work was initially designed to allow rapid development of very simple modules. To an extent it did this job well. Over the time, modules become more and more complex; the need to base new modules on already existing ones grew and this is where we have started to see the first major drawbacks of the old approach.
Let’s take a look at the following diagram describing the old way of doing things:
So, as you can see the architecture was extremely simple. We would have a module class which would instantiate an instance of Control Panel class. Control Panel was your user interface - this was where you would define all the controls and then show them or hide them based on the current mode. Control Panel this in addition to this instantiate also an instance of Command Panel class, whose sole purpose was to provide user interface for switching the modes of Control Panel.
It is easy to see, where things got complicated with more complex modules did. Let’s take Images & Documents module for example. The module has around 15 different modes, which results in a hard to maintain implementations with switch statements and countless event handlers all packed inside of one class. The complexity started to take over.
Another significant problem that appeared over the time was the difficult and timely process of extending and reusing certain modules. Generally, most of the developers saw an opportunity to reuse certain parts of Generic Content module. With all logic tightly coupled inside of the Control Panel class, and ever expanding set of features of the Generic Content module, the process of basing one’s module on Generic Content became more and more cumbersome.
Since there was only one class you could inherit from, you were destined to inherit from a large and complex class such as Control Panel, even if all you wanted to do was something minor. With numerous dependencies of the base class, this process slowly turned into a nightmare on a large scale projects.
Pinpointing the main problems and setting the goals of the new architecture
Once the problem has become apparent we have decided to pinpoint all the problems and come up with a unified theory of Sitefinity module development. What we wanted to achieve with the new backend architecture was following:
The new backend architecture introduced in Sitefinity 3.6 has brought the solutions to these fundamental problems.
- Modules should be split into single maintainable units
- The units of which modules are to consist should be arranged in hierarchies, so that when needed, certain nodes and it’s children can be replaced, reused or manipulated in any other way
- Developers should have the ability to reuse these units in their own modules without being forced to reuse whole module
- The common tasks such as templating controls, referencing template controls, navigating between different modes of the module should be abstracted and developers should not worry about them on a daily basis
- Creation of typical backend user interface, such as commands, breadcrumb and titles should be automated, but modifiable if needed
- Developers should be able to enrich or modify existing templates without overriding them entirely, but rather injecting the modified bits
Solutions brought by new backend architecture
Sitefinity 3.6 has introduced the concept of Views in the modules, which roughly represent what used to be Control Panel modes in prior versions of Sitefinity. While we will talk in more detail about Views in the subsequent topics, here we will examine what kind of problems has this concept solved.
Views are classes, based on ViewModeControl or ViewModeUserControl base classes, therefore representing single maintainable units of a module. Every View can have one or more child Views, thus creating a hierarchy. Every View is aware of its parents.
Views are designed to be unaware of its hosts (parents) therefore making them ambivalent about their place in the hierarchy. This is achieved by using generics. On the other hand, views can also be designed in such a way that they always have to have a certain parent. Depending on a development scenario and requirements it is up to developer to decide which way to take. For example all views of Generic Content module are generic, meaning that they can be plugged easily in any other module. On the other hand, more specialized module may stray away from such approach if the chances of another module being based on it are slim.
New backend architecture also introduces base classes, such as ViewModeControl, ControlPanel, CommandPanel, CommandItem, ProviderControlPanel, AdminBreadcrumb that automate common tasks and expose methods for commonly performed tasks.
Finally, the introduction of the ControlsConfig file has enabled developers to cherry pick the views which they want to modify, thus providing a way to alter the appearance and behavior of an existing module without actually overriding and reimplementing it. So, for example, it is possible now to provide custom implementation of the view for editing news items, without overriding the news module. All one has to do is to create the custom view for this purpose and replace the built-in view with its own implementation through ControlsConfig file.
As we have seen, the new architecture has solved all the problems it has set to solve. Throughout this topic we will see practical samples of all of these principles.
Before we wrap up this article, let’s take a look at the diagram roughly describing the module composition so that we can juxtapose it with the diagram from the beginning of this article.
As you can see, Control Panel class plays a minimalistic role in this new architecture as opposed to its all-encompassing role it used to have before. The accent now is on the views and their composition. If we are to reuse View 2-1 or View 1-1 (and it’s children View 1-1-1 and View 1-1-2) in our custom module we could simple add those views to our module, or alternatively create new views and inherit from those - if we are to modify the behavior of these views.
This new composition also allows us, to simply replace View 1-1-2 with our custom View 1-1-2-custom through ControlsConfig configuration file, without actually reimplementing the module itself.