In the first post in this series (table of contents) I explained why agile software development influences the choice of the UI design pattern. For short, changeability and extensibility are must have characteristics.
In this post, I’ll show you the corner stones of a UI design pattern that fulfills these needs.
Principles of Object Oriented Software Design – SOLID
One of the best known set of principles to achieve my goal of a UI design pattern that is changeable and extensible is SOLID by Robert C. Martin (link).
If you don’t already know those principles then please follow the above link and read it before continuing here.
The principle I’m most interestes at the moment is the S in SOLID, the Single responsibility principle:
A class should have one, and only one, reason to change.
Responsibilities in the UI
You may think that the UI has one single responsibility. It simply visualizes the internal structure of the application to the user.
However, there are at least the following seven responsibilities:
- visualize data
- bridge domain model to screen
- react to user input
- drive UI workflow
- interact with domain model
- permission handling
- translation of dynamic data
This responsibility covers the part that the user sees: how is data visualized: TextBox, Grid, ComboBox, Graph, …
React to User Input
This is actually a set of responsibilities. Each user input (button click, text entry, …) is a single responsibility that has to be taken care of.
Bridge Domain Model to Screen
A single screen is only a small section of the complete domain model that is visualized to the user. This responsibility takes care to map the “complex” domain model to a “simple” model containing only the data relevant to the current screen. It isolates the underlying domain model from the user interface, too.
Drive UI Workflow
Somewhere you have to define when a screen is shown, what happens after the dialog is closed and react to events from the domain model. This is the engine of the user interface.
Interact with Domain Model
Some user inputs will trigger changes in the domain model. Each possible modification (e.g. add, modify, save, delete data) is a single responsibility.
Most real life applications have a sort of permission handling that takes care of enabling and disabling functionality depending on the current user’s role.
This is a responsibility of its own, because we don’t want to change anything else when only the permission handling mechanism has to change.
Translation of dynamic Data
In localized applications there are two different kinds of translation:
- static data (e.g. labels)
- dynamic data (e.g. reference codes read from database like a title of an address)
Static data translation belongs to the visualize data responsibility above.
However, dynamic data translation is a responsibility of its own.
There are even more!
The above responsibilities are all generic responsibilities almost all user interfaces have (if you’re lucky then there are no permissions). Normally, there are additional application or domain related responsibilities that have to be handled, too. I’ll come back to that later in the series.
Although the SRP tells us to keep all these responsibilities in their dedicated classes, there is a counter principle that leads to a balanced design: needless complexity. If you have a simple enough UI layer then it may not be reasonable to split all responsibilities into separate classes. However, the design should always allow a transition from simple to complex without much effort. Therefore, I’m going to show you in the next few posts how to design for a very complex UI layer.
The user interface has to implement several separate responsibilities. Only if these responsibilities are kept separate from each other, we get a design that follows the SOLID principles and will help us to keep our software changeable and extensible.