In that film, an architect was used to “design a labyrinth of landscapes” to ensnare their the dreamer in a maze. Well, sometimes we do that at if we disregard good layered designs in our bigger projects. Small ones you can wake up from the nightmare, but dreams within dreams are good analogies for larger systems. The pattern or architecture should work for us and not against us and our dream projects should not turn into nightmares as they grow more complex.
At the start of projects we prototype and develop extremely fast (at the speed of thinking), but further care should be made in the long term. Best practices like peer-review or code-review should be in place to put the original prototype code in a structure that is maintained/documented in the long run, but we should also use some form of layered design if multiple features are developed for the same project.
What MVVM in Mendix is proposing to accomplish, is to separate UI and Domain model concerns using a View-Model, which creates an augmented view of the original domain model. This allows us to layer our application with different concerns, namely the domain model, the view and a view-model.
MVVM is a pattern that facilitates separation of the front-end model from the business logic or domain model. The view-model can be seen as the converter/mediator/aspect/augmentation of your original entity domain model. It exists so that we can easily customize our model for UI representation without contaminating or constricting our domain model. We imagine Mendix will come up with more ways of allowing elegant design, but as of this writing, MVVM could be used to alleviate some of the stress.
Analogous to MVC
Traditionally the pattern most developers are familiar with, is MVC or model-view-controller but cannot be achieved in the way Mendix modeling works. Since Mendix itself implies the model in the view, it is important to layer our app with different Modules to achieve a pattern where we separate our domain from the UI.
For example, virtual attributes are usually a UI concern, or a conditional visibility has no real benefit at the Domain Model level from a DB-point of view and we should avoid bringing that into our core Domain Model; there are other advantages for security, performance, quality and maintainability reasons too:
- BI typically is only interested in data Domain models.
- Extending applications functionally tends to snowball/grow the overall size of the project.
- The domain model’s performance can be impeded by XPaths access rules, virtual attributes etc on large datasets
The Model is your data access layer. This uses mostly Domain Specific concepts (DSL). It should describe a pure uncluttered Business model without Application Logic
Like MVC, the view is your UI layer. This is almost exclusively bound to forms, snippets and other UI elements, grids etc
This abstract model exposes parts of your domain model and synchronizes the data back to your domain model. This contains Application Logic*, which is different from Domain Logic
*Business logic usually can be grouped into domain logic, and application/UI logic.
Benefits of MVVM
- Clean Domain Model
- Clearly defined aspects (View Models)
- Fast data processing on domain model
- Removed calculated attributes
- Move XPath security constraints to ViewModel instead of model
- Demarcated concerns make better discerning models
- Searchable attributes on ViewModel replaces Virtual attrs on Domain Model
- Control Entity state outside of the Domain Model
- **Save points are now possible
- Secure domain model from XAS exploitation
**Save points are when you can save your entity without committing them to your Domain Model, ie save-continue and then final-save
You will need the MVVM module package from the Appstore or Github.
- Model entities need to specialize the MVVM.Model entity
- View entities need to specialize the MVVM.View entity
- A 1-1 association needs the be created between the Model and the View and a Model can have multiple kinds of View-type Entities
- Now you can customize your views to suit the needs
Copying attributes from Model to ViewModel
I’ll cover this in a video, but you can copy-paste fields from the Model to the View-Model and have automatic reuse. This is the most straightforward use case.
You can now add application logic like validation on the attributes of the VM.
Flow of updates
Using copied-fields from the Model on the ViewModel automatically propagates it’s values to the domain model and back. When you want to control dataflow however, you will use your own names and commit them on a Before Commit Event Handler of you ViewModel.
Using ViewModels entity allow you to save the ViewModel before finally committing it to the Model entity. For example, when you have to enter 40 fields in a form (yes it’s an impractical example but you get the idea), you entered 20 and then hit save before validation occurs, then the user comes back to it and “submits” it when the form is complete; in other words, commit the data to the Model entities.
Once the domain Model is successfully saved, this triggers updating all the ViewModels except the ViewModel that triggered the save to prevent infinite recursion.
Rules of MVVM
As you can guess, using a new pattern implies certain rules be kept in order for it to work. They are:
- Never use the Model on forms, except when reading data by association from the view and you don’t care about XPath security rules for read. Rather use the ViewModel on pages/snippets
- A ViewModel should have a 1-1 association to a single Model, but a Model can have many different kinds of ViewModels. The ViewModel can be associated to other Non-Model entities with any multiplicity/cardinality.
- Views cannot be specialized (Generalization)
- Apply careful View Models with cross-concerns, if you use multiple views on the same form
Manual updating of Views Models
In some cases you might want to retroactively update views or models when committing without event handlers, or when bulk data was loaded outside of Mendix.
In that case, 3 API microflows are created to this purpose:
- RefreshModel : Refreshes the Model from a single view
- RefreshViews : Updates views from the model
- ReinitializeViews : Creates views for a model that was created without it’s views
Get it at Git
The MVVM module still needs polishing before uploading to the Appstore, but you can get the code at Git.
Nothing illustrates an idea like a Youtube vlog. So, that’s why I’ve created a couple of small videos to demonstrate how to use the MVVM pattern, using a basic CRM application where we have a core domain model, but 2 different aspects (or feature sets), namely Contact-ability via phone and Contact-ability via email as different views on the same core data or domain model.
Stay tuned for the videos as they will be in separate posts following this one.