My take on Model View Controller (MVC)
Model View Controller (MVC) is a very well known design pattern. It is utilised within application development across multiple platforms.
The issue that I have always had with it is not clearly defined - the pattern lacks clarity. What I mean by this is that because people define each piece differently, and because different platforms are constrained in different ways there is no strict definition of what the pattern is.
I spend a lot of my time working in Swift, Java (Android), and PHP. These are all fundamentally different languages.
I work with a pattern (that is heavily based on MVC) which I use for my development across all three languages. It is universal and consistent and can be defined.
This post seeks to outline this pattern with examples. My thoughts are that if you can see the reasoning behind the pattern decisions you can adapt and utilize them as you please without having to work to a questionable strict definition.
At the end of the day, design patterns are tried and tested methodologies for common problems. They allow you to avoid reinventing the wheel. That said, they are not a one fits all kind of thing and you should adapt and develop your applications as needed.
Why do people use MVC
MVC is so popular for a number of reasons.
It allows a separation of concerns.
How the software appears to the user is completely independent of the logic happening behind the scenes.
In principle a user interface can be built by someone without knowledge of the technologies powering the back end logic of the application.
In a web app a designer only needs basic knowledge of HTML to develop an interface.
In iOS development, one can simply utilize interface builder.
In Android Development, one can utilize the Android studio GUI or simply build an interface with XML.
Interface testing is hard
Interface testing is often achieved through manual means, or through more involved automated means.
For example we utilize Phantom Mochachino to test our web application interfaces.
iOS and Android offer tools to do interface testing, but for complex interfaces they are arduous to work with and are tough to develop and maintain.
MVC allows you test the logic of your application independetnly of your interface. By seperating the various parts of your application you can easily test them using patterns such as Dependency Injection.
It is more maintainable
- Photos can now have a caption. Model.
- Lets display that caption on screen. View.
- Handling page numbers (GET). Controller.
With MVC everything is intuitively positioned in your codebase. You know where to look when you want to do a specific thing. Because your classes and methods have specific responsibilites the code contained within should be clean, concise, and easy to follow.
How I separate my concerns
A view is an output.. a display.. a visual representation of information from my application.
A UIView subclass. Defined methods allow manipulation of the views on screen.
A class which controls visual representation that may be defined within an xml layout file.
A static html file, a phtml file, or a template .volt file (I do a lot of work with the Phalcon framework).
A controller works with and controls inputs, organizes their processing, and delegates display to a view.
I would describe a controller as controlling the handling of inputs and outputs.
Services do stuff. If i want to get all usernames containing a certain string then a service organizes the execution of the required data gathering operations, processes the data, and returns a response.
The service are the main workhorse of the app.
A service could:
- log a user into facebook
- load all of a users uploads from a database
- write random words to a text file
I would describe a service as a controller of operations.
Data access objects
Data access objects control the access and manipulation of data sources.
Regardless of whether your data is stored in a database, a text file, an encoded image etc.. it is a DAO instance that will be used to manipulate the data source.
A model represents a
thing. A post, a photo, a review - these are all represented by a model. The model defines the properties of the object that it represents.
In Swift, Java, and PHP a model is simply represented by a class with properties.
A view model models my data in a way that I am happy for it to be utilized within my views.
As mentioned above.. in principle a designer with basic HTML knowledge could develop an interface for my application.
I may want to allow them to utilize data from my model (passed through my controller). The problem is that I may not want them to be able to access some properties of my model. I may also simply not want to directly allow access to a model instance (which could for example be part of an ORM and as such expose methods for data manipulation).
The resolution is to encapsulate a model (a 'thing') within a view model which exposes properties and simple helper methods for designers (with limited knowledge) to utilize within their view design.
In addition to this, view models aid in keeping things DRY. For example in one project I have a method which interacts with multiple database tables (and relationships) to produce a complex permalink. I would not want to reproduce this across the application.
An end to end example
To make the implementation of such a pattern patently clear, I will outline an example - an API endpoint for getting a list of users, and the respective clients (iOS and Android) for displaying said data.
On the web
Firstly we have a controller class which receives the request. How this request is received depends on your server setup, and any frameworks you may or may not be using.
In my case i am utilizing Phalcon and have a setup such that a request for http://domain.com/api/users is routed to a particular method of my controller class.
The controller class takes the request variables (page number for example) and passes them to a service. My
UserService has a method called
getUsersList which takes the page number as an argument.
This service method calls my
UserDao (DAO) which interacts with the database to pull my results. These results are returned as a list of
User model instances (thanks to Phalcon's ORM).
These results are processed by the service method into an appropriate form. The model instances may for example be converted to an array of
UserViewModel view model instances which are then passed back to the controller.
The controller passes this data to a view which is displayed on screen.
In this case because this is an API endpoint, the view simply outputs the data as JSON.
iOS and Android
Within my applications (the consumers of the endpoint) I once again have a controller class. This class is connected to a view class which displays the interfaces that I have designed in interface builder/xml respectively.
At the appropriate points in the lifecycle of the respective system frameworks, my controller calls a method on a service class
APIService. This method contains the networking logic which sends a request to my API endpoint to get the user data.
*Were I interacting with a local data source (for example a SQLite database) I would call an appropriate dao to interact with the database and load the appropriate data.
When this data is returned it is processed and an appropriate response is sent to the controller.
The controller then informs the view about the loaded data, and it is then displayed on screen.
* With our iOS and Android development we do not use view models. This is because behind the scenes, the frameworks of the respective platforms control the application lifecycle and view display. The platforms do not offer an appropriate use case for utilization of view models of the form outlined above.
The beauty of a pattern like that described above is that it is highly malleable. You do not need to utilize view models. Likewise if you dont interact with a data source (really..?) then you of course do not need DAOs at all (or models for that matter).
The nature of an architectural design pattern is that it is merely a set of principles for the organization of your project based on your requirements and needs.
Hopefully the above provides some further insight and gives you some ideas on how you might go about structuring your next project.