This writing is an answer to the question "why MVVM?" written from an auto-biographical point of view.
Previous experience
I started programming in the mid-eighties. Over the decades I have done a lot of work with GUIs. I have written GUI code in several different programming languages, and for several different GUI frameworks in each language. In Java alone, I have worked with AWT, Swing, and SWT. I have also built an entire windowed GUI framework from scratch, based on just 3 primitives provided to me by a graphics engine: a draw-image primitive, a draw-text primitive, and a measure-text primitive allowing me to implement a layout mechanism. Then, on top of that GUI, I wrote a big part of the application that the GUI was built for. That's a lot of GUI work. Until 2019, all that work had been on conventional (non-MVVM) GUI frameworks.
The noise in the search results
During the first couple of decades of the 3rd millennium I was programming in Java for work, but as soon as Microsoft introduced C#, I started experimenting with it at home, in the evenings. The first GUI framework that was made available for C# was Windows Forms, (WinForms,) and it suited me fine because it was a conventional GUI framework, and I already had plenty of experience with those. Even the terminology used by WinForms was familiar to me, because I had previously worked with Win32 GDI and with MFC during my C++ years.
Then around 2010 I started using Stack Overflow, and I noticed something ugly happening: as I was searching for information on how to accomplish things with C# and --what else?-- WinForms, my search results were being polluted more and more with completely irrelevant, preposterously complicated, and hopelessly incomprehensible noise pertaining to some new GUI framework called WPF, which had been introduced by Microsoft as an alternative to WinForms. Why would anyone want to use anything but WinForms was completely beyond me, so I kept treating those results as noise.
At some point I tried taking a brief look into WPF to see what the fuss was all about, and I very quickly came to the conclusion that if Microsoft wanted people to start using this new framework, they should have made it... understandable. There was also talk about some MVVM thing, which was supposed to be some high level concept that WPF was based on; I did not see any need for any high level concepts. As far as I was concerned, the case was closed, and I never needed to take a second look at WPF and MVVM again.
Little did I know that ten years later I was going to take not only a second look at them, but much more than that.
The 3 major problems
During my decades of working with conventional GUI frameworks I realized that they suffer from certain problems, which have also been identified by others:
- Coupling
- Conventional GUI frameworks require copious amounts of GUI-related code dispersed throughout application code.
- A GUI is not some small and simple API with like a dozen functions that we can invoke to show stuff on the screen; GUI frameworks are complex beasts, with hundreds of functions spread over dozens of classes, often requiring the application to subclass existing GUI classes to add functionality to them; and they are not just things that you call; they also call back, by issuing events, which must be handled, by implementing event handling functions in the application.
- Thus, application code tends to be inextricably mangled with the GUI.
- Even though all conventional GUI frameworks are architecturally very similar to each other, they differ just enough so that one is never a drop-in replacement for another. So, when we say that the application code is inextricably mangled with the GUI, what we mean is that the application is tied to a particular GUI product, and that replacing that particular GUI product with a different one involves rewriting a very large part of the application.
- Incidental Complexity
- Virtually all of the GUI-related code which is dispersed throughout the application represents incidental complexity.
- For example, the application may have a list of items which were fetched from the database and need to be shown to the user; with a traditional GUI framework, the application has to loop over the items, and for each item invoke some
ListBox.AddItem()method to add that item to aListBox. - This is incidental complexity: the application logic already has a list of items, why should it have to add those items to yet another list? The code that copies items from one list to another is not dealing with the problem domain; instead, it is serving the trifling technicalities of using the GUI framework for showing stuff to the user and figuring out what the user wants to do next.
- Testability
- GUIs are famously untestable.
- There exist some frameworks aiming to facilitate the testing of GUI applications by examining screen elements and emulating mouse moves and mouse clicks, but they are onerous to implement, onerous to maintain, yield limited results, and tend to be very fragile, meaning that the slightest change in how the application uses the GUI requires testing procedures to be rewritten. In general, they are severely ill-advised.
- As a result, people do not usually test user workflows of conventional GUI applications; instead, they only test isolated parts of the application logic that lend themselves to testing by offering a single entry point that can be invoked by testing code.
These problems are fairly damning for conventional GUI frameworks, and the only reason why we have been using such frameworks is because for the longest time we have not known any better. Clearly, if there could be a different approach to GUIs, that would somehow solve these problems, it would be the Holy Grail for interactive application development.
The Virtual List Box
During the decades of my involvement with conventional GUI frameworks I noticed a certain pattern: in virtually every GUI framework that I worked with, there was always one control that was my favorite, and that was the Virtual List Box control.
A Virtual List Box works very differently from a regular List Box. Instead of exposing an AddItem() method, the Virtual List Box requires us to supply a callback at construction time, and it will be invoking that callback to obtain items as it needs them. So, as soon as we tell the control that we have a non-zero number of items, the control proceeds to invoke the callback to obtain each item. The trick is that the Virtual List Box only invokes the callback for those items that are at any moment visible; so, we can use it for example to show a database table containing millions of rows, without having to wait for the length of time it would take to fetch all rows from the database and stuff each row into a regular list box using AddItem(). (Assuming that we even had enough memory to do so.)
With every Virtual List Box control that I have come across, I have always applied a few customizations, to make it work exactly as I wanted it to. So, I would subclass the control and add the following features:
- Instead of accepting a single callback method, my Virtual List Box would accept a callback interface with multiple methods.
- Instead of me having to tell the Virtual List Box the number of items, the callback interface would expose an
ItemCountproperty, and also anItemCountChangedevent, to which my Virtual List Box would subscribe, so that it can find out by itself when the number of items has changed. - Instead of me having to tell the Virtual List Box to refresh when the content of some items changes, the callback interface would also expose an
ItemsChangedevent, to which my Virtual List Box would also subscribe, so that it can find out by itself when it needs to refresh.
The Virtual List Box control was my favorite, not because I often needed to display tables consisting of millions of rows; it was my favorite because I noticed that something beautiful happened to the code implementing the callback interface, as well as the code dealing with the control:
The code dealing with my Virtual List Box control was awesome, because it was just a single line of code: All I needed to do was to construct the control, passing it my callback interface, and from that moment on I never had to deal with it again.
- If the control needed items to display, it would fetch them on its own.
- If the number of items changed, the control would find out on its own.
- If the content of some items changed, necessitating a refresh, the control would also find out on its own.
The control had essentially become a fire-and-forget control.
The code implementing the callback interface was also awesome, because it lived in a beautifully abstract world: It did not need to know anything about the GUI framework; all it was concerned with was the items that it was managing. In principle, I could replace the GUI framework with a different one, and that piece of code would not have to change at all. Being GUI-agnostic also meant that it was entirely free from any GUI-related incidental complexity, and it was perfectly testable on its own, without a GUI.
That code was pretty much the only code in the entire application that could boast enjoying such advantages.
An idea begins to form
My observations about the awesomeness of the Virtual List Box inevitably got me thinking: could we somehow extend the principle of operation of the Virtual List Box to the entire application? If we could achieve this, then all 3 of the major problems of conventional GUI frameworks would be solved. That would be the Holy Grail!
I envisioned an application that creates a graph of data structures in memory, in a way which is completely agnostic of any kind of GUI, and then an entirely new breed of GUI that is attached to the application, traverses the graph, discovers the data structures, and renders them on the screen. Essentially, the application would be exposing a User Interface, but it would be an abstract User Interface, not a graphical User Interface.
Unfortunately, the idea was not concrete enough in my mind to start experimenting with it. I could roughly see how I could perhaps create an application consisting of a single dialog with controls on it, but I could not yet imagine how the model could be extended to allow the creation of more complex applications, let alone extended to the point of allowing the creation of any application imaginable.
So, I kept the idea in the back of my mind and went on with my life.
The whoops! moment
In 2016-2017 I happened to be at a workplace where I had a colleague who was pretty knowledgeable about GUIs. He had created an entire GUI framework that was capable of presenting an application either on the desktop or on the web. It was still a conventional GUI framework, so it was not a game-changer, but still, it was quite an accomplishment. Clearly, this guy knew his stuff, so over the course of time he must have had realizations similar to those that I had. So, one day I pitched to him my vague idea about a new kind of GUI that would facilitate applications implementing abstract User Interfaces, and asked him what he thought of it.
His answer left me dumbfounded.
He said:
You should look into WPF and MVVM; they do something similar to what you are describing.
Incredulously, I went home and I searched for architectural information about WPF. Sure enough, it turns out that the architectural design pattern known as MVVM was in fact a fully realized version of my vague idea, and WPF was an implementation of that architectural design pattern.
As far as I could tell, it was the Holy Grail.
Unfortunately, by then I had fully switched to Java, so much so that I did not even have Visual Studio installed on my computer at home anymore; it would have been quite a challenge to bring C# back into my life during that period in time. Besides, even if I was to start experimenting with WPF, there was not much I could accomplish on my own, without any purpose or direction. I decided that what I needed was a job that would hire me to work on WPF, but that was a tough proposition given that I was working on Java and I had no prior exposure to WPF.
So, again, I had no option but to wait for an opportunity to arise.
The second look
Then, in 2019 I happened to be between jobs, and I saw a job advertisement that required C++, embedded systems, C#, and Windows Desktop Development, and in the "nice to have" section it mentioned WPF. I thought that this job had my name written on it. I applied, went to the interviews, passed them, and got the job. That was Demcon, which after a few months handed me over to its subsidiary Dutch United Instruments, where I started working on WPF.
So, I was one of the few WPF programmers who got started with it having full knowledge of the architectural superiority of MVVM, and wanted to get their hands on one of its implementations.
I suppose this was a much better experience than what most other programmers go through, who start with these questions:
What does Microsoft recommend nowadays for Windows Desktop development?
Oh, it is this thing called WPF?
Okay, let us see, how do you write "Hello, world!" in WPF?
...and go on from there, learning how to do things with WPF, one thing at a time, without first having a high-level understanding of why things are done this way in WPF.
Further reading: The MVVM architectural design pattern