MVC is a famous architectural pattern for building software applications. It was first used for building desktop GUIs and now it’s one of the most popular ways for building web applications and mobile applications.
MVC decouples a software application into three components:
- Model – Represents the shape of the data in our application
- View – The part of the application that the user interacts with. It represents the UI of your application
- Controller – The brain of your application. The controller is responsible for most of your business logic. If your application is a web application, the controller will handle the requests coming into your application. If your application is a mobile application, the controller will handle the state of your application for your views
Now that we have had a brief refresher about the MVC framework, in this article we will be zooming in on a component of the MVC that is underused or rather not being used to its full potential in most use cases.
Model
Although the MVC architecture is known to a lot of web developers, using each component to their full potential and architectural intent is still not quite understood and one of the most underestimated or underused of these components in MVC is the model.
Most definitions say the model represents the data in your application. However, the model which represents the underlying data structure of your application, by design, should also contain:
- Properties to represent specific data
- Business logic like validation rules
- Logic that will be performed on the data
Properties to represent specific data
This part is the easiest part to grasp as most web frameworks emphasize defining properties here. For example, let’s take a web application using Sails, an MVC Node.js framework, we can have a user model defined like this:
// api/models/User.js module.exports = { attributes: { id: {}, name: {}, EmailAddress: {}, } } }
You can see that our model is represented in Sails as a JavaScript module exporting an object. In this object, there is an attributes
key in which we define the specific data this model represents.
Business logic
The model in MVC should also be able to implement business logic on the data it represents. For example, common business logic for web applications includes validation rules.
Validation rules enforce that data coming into the application meets the constraint of the design of the system required. A misconception is to do this validation on the controller level. However, this is the job of the model.
Taking our Sails model above, let’s see how the model should address business logic like validations:
// api/models/User.js module.exports = { attributes: { id: { type: 'string', required: true isUuid: true }, name: { type: 'string', allowNull: true }, EmailAddress: { type: 'string', isEmail: true, unique: true }, } } }
You can see that our model following the principles of MVC provides validation properties for the data that it will be representing. Let’s look at all of the logic implemented:
type
– Enforces that the data type (in this case, it should be a string)required
– Enforces that when creating new instances of this model, the data with this value set to true should always be providedallowNull
– When this is set to true for a particular data, the model will know to let instances be created with this particular data value set to nullunique
– Setting this to true informs the model to make sure that only one instance should be allowed to have a particular value for that data. That means the value for that data must be uniqueisEmail
– Most times we do checks like this in the controller, but in using the model to the full capacity, we set this in the model to make sure a particular data is an emailisUuid
– If this is set to true for model data, the model ensures the data is of a UUID form (v1, v2, or v3)
Logic that will be performed on data
Models should contain logic that deals with manipulating data. For example, say we have a post model, the model should contain methods that get the comments of a particular post.
In Sails models, each model has static methods like find
, findOne
, update
, etc. This helps in data access which you can call from the controllers.
Benefits of using the model to its full capacity
In a well-implemented MVC architecture, the models normally host the bulk of the business logic because this logic is closely coupled to data manipulation and models are responsible for that data level.
Utilizing models to their full capacity encourages lean controllers, controllers that are more focused on connecting the models to the views and vice-versa than actually implementing business logic.
Best practices with models
- Models should not use variables that are tied to end users’ inputs or requests. This should be left for the controller to pass to the model
- Avoid embedding presentational code in the model. This is because presentational code varies based on end users’ input so this should be left to the view of MVC
Conclusion
Although we used Sails as an example of an MVC framework to see how to use the model in MVC to its full potentials, these principles are framework agnostic and should apply to your chosen MVC framework of choice. Here are the key takeaways:
- Define your business logic on your data, like validation rules, in your model
- Define logic that will be performed on your model that is inside the model
- Have your controllers be lean