PBS 170 of X: The Model View Controller Design Pattern (MVC)
This instalment is a real change of pace from our recent explorations of jq and YAML. Those series were very practical, this instalment is purely theoretical, or perhaps even philosophical!
Matching Podcast Episode
You can also Download the MP3
Read an unedited, auto-generated transcript with chapter marks: PBS_2024_09_14
Why Now?
The community has been making great strides in the re-implementation of XKPasswd in JavaScript, and the intention was always that there would be a kind of harmony between this series and that project. People interested in the series could choose to put their new skills to practical use by contributing to the project, and people interested in contributing to the project could use the series as a kind of tutorial for any of the tools the project uses. As we record this in the autumn of 2024 the community has been making amazing strides on the project, and it has actually gotten a little ahead of this series.
At first glance, you might imagine we have all our bases covered because:
- The code in the project is written in languages weâve covered â HTML, CSS & JavaScript
- The code uses libraries weâve covered â Bootstrap & jQuery
- The code is managed, documented, tested, and deployed using developer tools weâve covered â GIT, ESLint, JSDoc, Mermaid, Jest & Webpack
But, as the project has evolved, itâs become clear that weâre missing two pieces of the puzzle, one philosophical, and one quite niche and practical:
- The project uses GitHub Actions for some automations
- Large codebases need to be structured carefully, and the project is using the Model View Controller (MVC) framework to do that.
People who want to contribute to the project donât ever need to interact with GitHub actions, so while we will cover those in a future instalment, theyâre not hindering participation at the moment. But what is starting to raise some barriers to participation is the way the code is organised, so thatâs what weâll focus on in the next two instalments.
In this first instalment weâll focus on the philosophy of MVC, and then weâll follow that up with a conversation with Helma where weâll look at how that philosophy has been applied to the new XKPasswd web interface.
Why do we Need a Framework at all?
Code organisation is a curious thing because it doesnât scale linearly, leaving most people with an initial dislike of frameworks.
Every code organisation framework comes with overhead â you need to define a bunch of data structures, functions, classes, modules, and what not to define the structure, and that all requires code. That structural code doesnât actually provide any of your appâs functionality, itâs just a scaffolding onto which that useful code will be hung.
What causes a lot of resistance to these kinds of organisational frameworks is that the amount of structural code you need for the absolute simplest of projects is not much different to the amount you need for massive projects, so the ratio of tedious structural code to useful feature implementation code is at its worst for smaller projects. Teaching examples are inevitably small and budding developers usually start on small projects, so you end with a lot of people thinking frameworks are just academic nonsense, and that in the real world theyâre just a waste of time.
So, budding developers start off avoiding frameworks because the overhead doesnât seem worth it, and then, inevitably, the real world will teach them a valuable lesson â those frameworks were created to solve very real problems!
When you donât use a framework for a project youâll initially make fantastic progress, much faster than those silly people wasting time on structural code! But as the project grows, the chaos will come home to roost, and it will become ever more difficult to add new features, or, to change existing ones. Why? Because the code is all mixed up, so changing one thing involves finding little pieces randomly scattered throughout the codebase. Adding something new means finding lots and lots of places to insert some extra logic.
Inevitably, you soon end up with monster megafunctions spanning hundreds or even thousands of lines. Soon, only the people who wrote the code will have any chance of ever understanding it, so as those people move on, the codebase becomes effectively unmaintainable.
The solution is to think about the structure of the codebase before you start. To carefully build an appropriate scaffold for your needs, and only then to start adding the first features, with all the code starting in just the right place on the scaffold so that everyone will know exactly where to find it should it need to change. Similarly, anyone can add new features by simply connecting them to the appropriate points in the scaffold.
There is no single right way to organise codebases, and just about any consistent structure is better than nothing, but of course, after decades of experience, some frameworks have earned the respect of developers, and risen to the top.
The Model View Controller Framework
One of the strange things about computers is that old ideas often come back. Is cloud computing really all that different philosophically from the mainframes that preceded our personal computers?
MVC is a great example of this â itâs proven extremely popular for web apps, but thatâs actually its second life, MVC was developed to help build the very first GUI apps in the 1970s!
Command line apps work very differently from GUI apps because they are inherently sequential. The user enters a command, the app interprets the command, executes the requested action, and returns the result. With a GUI things can easily happen in parallel, and thereâs a need for the visual representation and the underlying data to always be in sync â how useless would a spreadsheet be if the values actually stored in the file were ever different to what you see on the screen?
The early internet was much closer to the command line than to a GUI app. Sure, you had a visual representation, but what you got was always static â you went to a URL, it showed you something, and until you clicked a link to leave and go to another page, or you clicked a submit button to send information to a server, nothing happened. When you clicked that submit button it was like hitting enter on a command line interface â your request went to the server, it interpreted your request, carried it out, and then sent you back a new page with the answer. It was completely serial.
That all changed with what we called the Web 2.0 revolution. With JavaScript and AJAX, we have web apps that behave like regular GUI apps. When you send an email in a webmail interface or use a chat box on a webpage your whole page doesnât refresh every time you click a button, no, you are sending single commands back and forth to some kind of back end and your view is updating in response. Things happen in parallel all the time, and we need to be sure that our visual representation stays in sync with the backend. Imagine if Gmail showed a mail as sent when it actually wasnât!
So, modern web apps have become just like regular GUI apps, so, web developers started to apply a design pattern they knew worked well elsewhere, MVC, and it worked!
Separation of Responsibilities
The MVC framework separates the code responsible for different aspects of the appâs functionality into different parts of the codebase. As the name suggests, there are three areas of responsibility:
- Model â the data representation & business logic, think of it as what your app does and how
- View â the rendering of the model to the user, as well as the rendering of any UI elements for changing the model
- Controller â the plumbing that connects the view and the model
Remember, this is a philosophical construct, not a rigid standard, so different implementations will vary. On the web, we tend to consider the UI buttons part of the view, but in early GUI implementations, they were part of the controller. The important thing is to be consistent within a single project.
The other thing to note is that in reality, you wonât necessarily have one of each. You might have a few models because your app does multiple distinct things â an online office app might have three models, one for email, one for contacts, and one for calendaring. Within even a single feature you may need multiple distinct views â one for viewing an inbox, one for viewing an email, one for composing an email, and so on. Youâre likely to break your controller into manageable pieces too â maybe you have a master controller for your whole app that manages navigation between major features, then separate midlevel manager-like controllers overseeing each feature, and those could then delegate to controllers for each view.
The point is that you want to do it to keep the code that describes your data model & business logic completely separate from the code for the interface, and you use controllers to connect the two.
The Advantages of MVC
The most obvious advantage of using the MVC framework is that when you need to make a change to an MVC app the type of change you need to make tells you where to find the code, e.g.:
- âI need to make this button biggerâ â view!
- âI need to add an extra field to our currency representationâ â model!
- âI need to change how we calculate the interestâ â model!
- âI need to add a confirmation step before this button actually changes thingsâ â Controller, and if there isnât already a confirmation view ready to be used, you may have to create one of those too.
- âI need to add a new featureâ â needed data model & business logic in the model, the UI in the view, and the connection between the two in the controller. Note that the separation MVC brings means these three tasks can easily be done by different developers.
Another big advantage is that the controller completely decouples the model from the view. You can rebuild the entire model and simply update the controller to connect the existing view to the new model without needing to touch the view. You can also completely redesign the view without touching the model, and, you can have many views connected to the same model. For example, before the rise of the iPhone, many large websites had two views of their pages â a view for the browser on the www
subdomain, and a view for primitive phones on the m
subdomain.
Applying MVC to JavaScript Web Apps
Many of the popular MVC libraries for the web are based on the client/server model, where the model is on the server, the view is in the browser, and the controller straddles the two.
However, weâve not done any server-side programming yet in this series, so our web apps are all 100% client side, or as theyâre generally referred to in the industry single page web apps. That means that for us, MVC applies differently.
Our models will be JavaScript modules that only represent data and implement business logic, and do absolutely no UI or plumbing. For the XKPasswd rewrite, the model is the JavaScript port of the Crypt::HSXKPasswd
Perl module. It contains all the code for generating passwords, but nothing else. That same module could power a web app, a command line interface, or a desktop app.
Our views unfortunately will be a little more complicated because theyâll be spread over two technologies â the HTML markup for the static anchored parts of the view, and JavaScript modules using jQuery for the dynamic parts of the view.
Our controllers will be JavaScript modules with access to both the JavaScript view and model modules. Note that the controller JavaScript will never interact with the HTML parts of the view, only the view modules do that.
Final Thoughts
Hopefully weâve convinced you to at least give frameworks a chance, and, that MVC is a good fit for this series and for the XKPasswd rebuild.
Weâve ended here with a very high-level description of how MVC is implemented in the XKPasswd beta, so next time Helma will join us to share the details.