Logo
Logo

Programming by Stealth

A blog and podcast series by Bart Busschots & Allison Sheridan.

PBS 170 of X: The Model View Controller Design Pattern (MVC)

14 Sep 2024
software engineering

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:

  1. The code in the project is written in languages we’ve covered — HTML, CSS & JavaScript
  2. The code uses libraries we’ve covered — Bootstrap & jQuery
  3. 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:

  1. The project uses GitHub Actions for some automations
  2. 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:

  1. Model — the data representation & business logic, think of it as what your app does and how
  2. View — the rendering of the model to the user, as well as the rendering of any UI elements for changing the model
  3. 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.:

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.

Join the Community

Find us in the PBS channel on the Podfeet Slack.

Podfeet Slack