In this post I’m going to cover the default/general architectural structure that I use when building a UI application.
Application Architecture Composition
When designing the architecture of an application I like to break the package down into components. Each component is responsible for providing an interface to a set of cohesive features that can be loosely coupled with other components to provide the full set of features required by the application.
As a general rule and default starting place for a GUI application, the primary components will be an implementation of the MVC architectural pattern. This decision encourages the notion that there should be at least three components in our application:
Controller. In order for these components to be loosely coupled, the application will likely need a few services such as a message broker and a dependency injection service. So I’ll add another component called
Service. All applications need to have an entry point into the package, so I’ll add one more component to the solution that will be called
UI as this is the component that is responsible for providing users access to the application.
Model component, there are two subcomponents:
Model.Command component isolates data structures used to represent user commands sent from objects in the
View to objects in the
Model.Event component isolates data structures used to represent events raised by objects in the
Model changing state.
Below is a UML component diagram that shows the dependency chain of these components. I used UMLetino to create the diagram.
Model and the
Service components are the most important since all of the other components depend on them. Also notice that neither the
Model nor the
Service components depend on any thing.
Model component is responsible for providing the state of the application and encapsulating the logic the application is providing the user the ability to work with. It is also responsible for declaring Command and Event objects that are used to model the behavior the application is modeling. For example, if the application was supporting an Accounts Receivable Clerk’s ability to create invoices, then there would likely be an
Account object in the
Model component, a
GenerateInvoice object in the
Command component and an
InvoiceGenerated object in the
Most applications will require some sort of user security where a user must authenticate their credentials to prove their identity to the system and once their identity is recognized, the system will grant them authorization to access and potentially manipulate resources controlled by the system.
If the application requires tracking the state of a user, they could be modeled in a
Session object. An active
Session would have properties such as an
Identity representing the user’s information such as name, title, contact information, etc.; and a set of authorization
Claims representing the authorizations granted the user. It would also provide a method to end the
Session. The commands and events corresponding to the Session would include objects such as
View component is responsible for providing a visual representation of the state of the objects in the
Model component. Objects in the
View component will use a message broker to subscribe to one or more
Model.Event(s) in order to be notified when a
Model object has changed its state.
Objects defined in the
View component are responsible for translating user interactions into the appropriate
Model.Command objects and publishing those commands via a message broker. Typically, applications display a nameplate/masthead that display the organization’s logo, controls for accessing the user’s profile, as well as the ability to logout, and a menu of links to resources/features of the application. These nameplates come in many styles and each system will require the application’s display stylistically match the organization’s branding. To design an application with this minimal feature, we would need to include
IdentityChallenge objects in the
Masthead would subscribe to the
SessionInitialized event and would handle receiving notification of that event by checking if the
Session that was initialized is currently active and if it is, render the
Profile and itself. If the
Session isn’t active, then the
Masthead would remove the
Profile from view and potentially even change the style of the
Logo to be larger and/or in a different position.
IdentityChallenge would be subscribed to the
SessionInitialized event and would check if the initialized
Session was active. If it is active, the
IdentityChallenge would remove itself from the UI as it is not required. If it isn’t active, it would append itself to the UI in order to allow the user to authenticate/start a new
Controller component is responsible for controlling the state of objects in the
Model. Objects in the
Controller component will use a message broker to subscribe to one or more
Model.Command(s) in order to be notified when a
View object has been interacted with by a user. Objects defined in the
Controller component are responsible for calling the appropriate methods on a
Model object based on the received
Command and publishing the results as a
Model.Event object. In some cases, the
Model object’s method that corresponds with the received
Command will require data that is external to the application. In those cases, the
Controller object will use a service to make a call to the external data source and use the results of that request to fulfill the
As an example, if the
Profile object in the
View component contains a button for logging out, when the user clicks that button the
Profile will publish a new
EndSession command. The
SessionController object will be subscribed to that event and be notified. It will then send an HTTP request to the identity and access management API (examples are Auth0 or Google’s Firebase Auth) to end the user’s session. When it receives a success response it will call the
End() method on the
The Service component is responsible for providing application services to the other components. These services include a dependency injection container and a pub/sub message broker.
Objects defined in the
Service component are responsible for handling the infrastructure duties required by any application to function in its host environment.
The UI component is responsible for providing the entry point of the application. In the case of a browser-based application, the host environment is a browser DOM’s window object. When the window loads, it will fire a load event. The UI component makes use of the
EventTarget interface and adds an
EventListener which will use the
Service‘s dependency injection
Container to initialize the application based on configuration settings. Once the application is initialized, it will publish a
SessionInitialized event via the
View objects subscribed to the
SessionInitialized event will render the appropriate user interface and enable the application to respond to the user’s interactions as described in the View Component section above.
With the basic architectural guidelines defined, when a project needs a user interface application, this architecture can be used to provide a launching pad for defining the product requirements that a developer will need to implement. The next post in this series will be about defining these requirements for a fictional system.