Designing extensible modules - best practices: Following single responsibility principle

April 21, 2009 Digital Experience

[This post is part of the developer's manual preview published on this blog. You can find temporary TOC here.]
 

One of the main ideas behind the new backend architecture introduced in Sitefinity 3.6 was reusability. We have seen in versions prior to Sitefinity 3.6 that - how modules grew in complexity reusing certain parts of these modules or basing entire modules on an already existing one was becoming harder and harder. All the different functionality crammed into one single control, which would then turn on or off certain part of the UI was becoming hard to maintain and almost impossible to reuse.

 

Recognizing this problem, which became apparent with large and more complex modules, we have decided to provide a framework for building modules which would inherently provide for reusability. The key piece of this new architecture is a View. We have been talking quite a lot about Views in this manual, so we will not go back to the details; however, let us consider some of the promises that Views pledge to us as developers:
  • Views provide functional units of the larger modules
  • Views can be arranged inside of hierarchy
  • View should be able to change its place in the hierarchy of the module
  • View should be able to be reused or completely transplanted to another module
  • View should be able to be modified either by adding new functionality or removing old functionality
So, from these ideas we can see that a properly designed View should be almost completely independent unit of functionality, which when combined with other Views creates a module. The best way to design a View which holds to all the points mentioned above is to design a View which does only one single thing.

 

Let us consider built-in Generic Content module for a second. The module itself has about dozen or so Views. Each View does only one single thing: for example, ContentItemEdit View  is responsible for displaying the form for editing content. Because the View has only this one purpose, we are able to create a new View from it (ContentItemNew View) which is in charge of creating new content. We know that the ContentItemEdit View does only one thing (save changes to existing content), which is extremely similar to what the View for creating new content does (save changes to the new content). With this tight focus on the functionality, we are able to reuse View without worrying about anything else (e.g. categories, displaying list of the content, tags, comments and so on).

 

This simplistic approach to the View design also allows us to port the View from one module to another. For example, editing content is almost identical to editing blog posts. Now, blogs module itself is rather different than the Generic Content module (e.g. concept of parent/child relations between blogs and posts), but since our Views are designed to do one isolated thing, we can port only those that we need (like the view for editing content) and leave other Views intact.

 

Finally, we could decide that every time content is saved we should run the content through the web service for translation. Whereas built-in ContentItemEdit View does not provide this functionality, we are at freedom to simply enhance this one View and replace the original View with the enhanced version through the configuration - meaning that we have a highly maintainable application at our hands.

 

So, as it was demonstrated on the example of ContentItemEdit View, benefits of designing Views with single responsibility are numerous. Our modules will be easier to maintain, we will be able to reuse the already existing functionality and finally, we will be able to build more and more complex modules through the composition of Views - each one responsible for one piece of functionality.

The Progress Team