JavaScript

A Tale Of Wwo MVC's

A Tale Of Wwo MVC's

by Yehuda Katz

The video, titled "A Tale Of Wwo MVC's," features speaker Yehuda Katz at the GoGaRuCo 2013 event, where he delivers a technical talk exploring the concept of Model-View-Controller (MVC) architecture in GUI programming. Katz aims to clarify the differing interpretations of MVC and GUI across various programming frameworks, emphasizing its relevance in today’s programming practices.

Key Points Discussed:
- Katz begins by addressing the confusion around the term MVC and its applicability in different contexts, referencing a quote from DHH regarding ‘double MVC’ within JavaScript solutions that require both server-side and client-side MVC stacks.
- He emphasizes the need for a unified model of GUI programming to understand how various systems handle components of GUI applications, including bootstrapping objects and updating application states.
- The evolution of GUI programming paradigms is discussed, starting with manual UI programming typical in early frameworks like jQuery, where developers handle everything in event handlers, leading to reduced structure and organization in code.
- The talk transitions into separated presentation as demonstrated in frameworks like Backbone, where the UI, model, and view are decoupled and communicate via observer patterns, highlighting a clear division of responsibilities.
- Katz explains the Rails framework and its approach to MVC, noting its limitations and challenges in managing UI hierarchy and application state without overwhelming the browser with full-page reloads.
- The discussion then explores innovations from the Smalltalk and Cocoa frameworks, such as the mediating controller, which separates concerns and manages broad application functionalities, redefining user experience design in GUI programming.
- Finally, Katz hints at Ember as an evolution of these paradigms, simplifying routing and client-side management, thereby enhancing the development process and providing a clearer GUI methodology.

Conclusions and Takeaways:
- The discourse reveals that despite varied implementations, all GUI frameworks engage in fundamental tasks like bootstrapping, translating user input, and updating the UI.

- A clear MVC structure is essential for enhanced maintainability and efficiency in application architecture, influencing how developers tackle complex web-based interactions.

This talk serves as a boundary-crossing exploration for developers interested in understanding the underlying mechanics and evolution of GUI programming techniques across different frameworks.

00:00:20.519 If there's anyone who doesn't need an introduction here, it's Yehuda. He’s pretty much on the core team of every project I care about or has been at one time.
00:00:31.400 So, Yehuda kept wondering what he should do a talk about because there are so many things you can discuss. This talk idea is actually something that Sarah May and I came up with, and Yehuda thought it sounded like fun. So, I present to you, Yehuda Katz, with a tale of two MVCs.
00:00:52.800 Thank you. Am I on? Looks like I am not mirrored after all those technical difficulties. What is going on? Okay, seems good. Present.
00:01:07.759 So, what I'm going to talk about today is MVC, broadly, and GUI programming. I apologize in advance if this ends up being dry; I'm doing my best to avoid that, but I think I will fail. So, just a warning ahead of time. This talk is an attempt to unpack what people mean when they say MVC and what they mean when they say GUI. As a result of that, there's a lot of technical detail. Hopefully, people will find it useful or interesting.
00:01:27.400 Other than Sarah May and Josh asking me to give this talk, one of the motivations for me was this quote from DHH: 'Current JavaScript solutions suffer from double MVC. You need both server and client-side MVC stacks.' The thing that frustrates me about this quote, and many others who know anything about MVC, is that the amount of unpacking you have to do on that sentence just to get to a point where you can even understand it is significant. Once you've done that, you realize the whole sentence is pretty nonsensical because it says the word MVC twice, but they mean different things in different contexts.
00:01:55.159 Unless you're doing it really poorly—which I'll get to later—this resonates with a lot of people. I think many people looked at this and said, 'Yes, that sounds right.' It indicates that people don't really have a good understanding of what the Rails model of GUI programming is and what the Ember model is, or what the Backbone model is, or what the Smalltalk model was. I see many people referencing the Smalltalk model, but not really providing a lot of value in those discussions.
00:02:35.360 So, I wanted to unpack what it means to do GUI programming and then how these different models work. The first thing is I don't want to talk about MVC at all because MVC is kind of a meaningless term. What I want to do is present a unified model of GUI programming that I think can be used to understand pretty much all these different systems. We can look at how these various systems handle each part of this.
00:03:00.720 To understand GUI programming, there are several steps. Step one is that when you come into the system for the very first time, the user wants to look at a screen. You need to bootstrap whatever objects you have and put them into the state that will be useful in the future. Once you've done that, you need to take those objects and use them to draw the initial UI. If you're doing a very simple global state kind of thing, it can be very small, but as the systems get more complicated, bootstrapping objects becomes more complex. After that, you draw your initial UI on the screen.
00:03:40.799 As the user starts clicking around, you want to take the thing that the user actually did—like mouse down at position (12, 57)—and convert that into user intent. This becomes especially important when you want to support touches, clicks, and maybe keyboard events, which all mean the same thing. You want to have a part of the system that says the user touched position (12, 15), the user was focused and hit enter, or the user tapped it—all these things should be converted into a single meaning.
00:04:44.600 Then, the next thing to do is to update the application state. For instance, if the user clicks ‘Log out,’ I would like to log the user out, so I will update the application state. There’s a notion of application state; this is not necessarily persisted anywhere—it's just what the application is doing right now. Then there's updating domain objects. If I delete a to-do, I want to actually remove it from the system. After doing these things, I want to notify the UI that there's some new stuff for you to draw.
00:05:04.919 I think these basic processes happen regardless of whether you're using MVC, MVVM, MVP, Smalltalk MVC, Rails MVC, or Ember Backbone. Each of these systems has places for each of these states, and I want us to think about the whole story in those terms. The first attempt that people had in the 70s and then again in the 2000s on the web was to do everything manually. The easiest way to understand this is through jQuery. What I mean by 'all manual' is that bootstrapping objects is straightforward; I'll do that when the DOM is ready. Drawing the initial UI is also no problem. I want to translate some raw input into user intent—I'll do that in an event handler with application state just being global variables.
00:06:01.440 Thus, I’ll update domain objects in event handlers as well. To save them, it will just be some AJAX in an event handler. Persistent ad hoc means that there's no need to notify anything; I just do everything in my event handler. I want to update the UI in the event handler. This works really well for extremely simple things. This is basically where GUI programming was in the '70s and also where it was in 2005.
00:06:54.080 In the 80s, and around 2008, people realized it was a bad idea to have the view logic—the logic that draws things—and the logic dealing with domain objects in the same place. The concept of separated presentation was created. The two easiest ways to understand this are Backbone and Smalltalk. Many people have used Backbone, but probably fewer have written Smalltalk. So, I’ll stick with Backbone for now. Essentially, it looks like this: The UI acts as a graphics context. The UI takes raw input, figures out what to do with it, and updates the model. The model then notifies the view. Importantly, this is an observable relationship so that the model doesn’t know anything about the view—it just notifies the view.
00:07:45.600 Then the view observes the model changes and updates the UI accordingly. This is the Backbone model; it’s quite simple and straightforward. It's what I will call 'separated presentation' for the purpose of this talk—separating the presentation and the model. The view has access to the model, but the model does not have access to the view. However, the model has to notify the view, so there’s another system called observers in Backbone used for updating the view.
00:08:41.760 Separated presentation works similarly to MVC. In fact, the concept of separated presentation came from MVC. The small tweak is, in separated presentation, the view and model exist, but in MVC, the raw input goes to one object—the controller—and drawing occurs in the view. Previously, there was one object in Backbone responsible for both receiving events and updating the UI. In MVC, there’s a controller object that receives raw input, and the view manages drawing.
00:09:22.120 Importantly, in Smalltalk MVC, the view and controller have access to each other as instance variables on themselves, which is heavily used in practice because the observer pattern doesn't work well in more complex situations. Practically speaking, separated presentation and the MVC model are roughly equivalent, except for code organization. The code for updating the UI belongs in the view while the code for receiving events belongs in the controller. However, as they have access to each other, they often end up coupled.
00:10:23.240 So, when we talk about MVC, how do we get objects into the system in the first place? MVC does not tell us the answer; it states that you bootstrap objects however you see fit. Who draws the initial UI? The view. Who translates raw input into user intent? The controller. You’ll see a pattern here in MVC: the next four actions are handled by the controller—updating application state, updating domain objects, notifying the UI of changes through observers, and then updating the UI.
00:11:03.720 We have a few objects, but the controller is doing a lot of work—many things. It’s important to note that application state and domain objects are managed by ad hoc objects, and there’s no clear structure in the system for how they operate. People develop patterns when writing Backbone or Smalltalk code, but the MVC pattern itself doesn’t dictate where to place your application state or domain objects.
00:12:11.680 What problems do we encounter? In my view, there are three significant issues with the original MVC pattern, most notably bootstrapping—how do you actually get the objects in the first place? It's possible to create patterns, but many people develop different methods for managing such processes.
00:12:50.000 Smalltalk MVC developed efficient patterns while Backbone did much less. The hierarchy in the UI is crucial, and not having a fixed pattern for it will lead to various approaches for managing the hierarchy. This makes it challenging to build additional abstractions on top of that hierarchy. Finally, application state is stored willy nilly within these systems.
00:13:46.080 You could potentially create an object that manages it, but in the original MVC system, every widget has its own MVC. This essentially culminates the story from the MVC perspective.
00:14:36.760 Now, obviously, I'm here to talk a lot about Rails. An important starting point for this discussion is that many say Rails has nothing to do with MVC; it’s a different pattern entirely. However, the term MVC doesn't concern me. Rails is a GUI design pattern that bears similarities with the other GUI design patterns we will discuss today.
00:15:09.200 Here’s how I would draw the Rails pattern: we have a browser, which from our perspective, is a black box. The view supplies the browser with HTML, and the browser manages the UI context. When the user clicks something, the browser interprets that raw input and labels it as a semantic event for the user actions like transitioning to another place or a form submission.
00:16:10.720 The browser relies on the pre-calculated information that we established when rendering the UI to determine how to translate raw user events. Once the browser has assessed what it means, it sends the event over HTTP, packaging it into a request that goes to the server. The server picks it up in the controller. The controller updates the model, which sends data back to the view, and the browser effectively redraws the entire page.
00:17:03.200 What's crucial to realize here is that this UI pattern is standard along with everything else. However, there are peculiarities that require us to precompute the meaning of every potential user event. It also limits us to the few things the browser can execute, and transmission of events occurs over HTTP, often requiring full page refreshing.
00:17:52.320 This can be seen in examples where applications are designed using Java, where a change to a checkbox reloads the entire page. Bootstrapping objects in Rails is a nice touch, as both the router and the controller give us a dedicated space to do it—eliminating ad-hoc methods. The initial UI is produced in the view along with pre-computed actions that convert raw input into user intent. The controller receives the request to update application state.
00:18:44.460 Rails suggests that application state goes into the session while updating domain objects occurs in the controller using Active Record. After all that work, we notify the UI that there’s something new via HTTP, and the browser updates the UI. This method showcases a similar structure to how we transition from the initial UI to interacting with events before reloading the interface.
00:19:34.480 What are the problems? Rails provides no mechanism to address UI hierarchy. There’s basically one significant component: the entire page. Whenever there’s a change in the hierarchy, you essentially render all of it. Rails represents one controller and one view, which resonates with a simplistic MVC structure but often overlooks the deeply nested hierarchy that must be modeled.
00:20:15.280 Another problem arises during a page reload. Elements like which button has focus or the ability to undo are stored in the browser state, which is miles apart from the Rails application state. At times, you have to choose between updating the browser's state or the entire application state, which is frustrating. This can lead to latency issues—every interaction involves a round trip to the server.
00:21:13.280 In the standard Rails approach, you must limit the user interaction to what the browser recognizes and can translate into semantic events, such as links and forms. Many people trying to enhance that experience incorporating JavaScript see that adding such features requires Ajax requests to the server.
00:22:04.080 This all results in working fine; yet limits the user to full page updates, which allows for reoccurrences of the earlier mentioned problems: latency, loss of browser state, and difficulty managing hierarchy. With Rails frozen in place for years, we now proceed to discuss improvements from the Smalltalk and Cocoa worlds that are absent in Rails.
00:23:03.000 In earlier frameworks, the controller would directly update the model, which created interdependencies. However, we want to avoid that, whereby the model does not need all information to represent itself. An example could be representing a number and then needing a visual representation—this type of conditional related to the GUI shouldn't reside in the model.
00:23:41.920 It’s best to have another object that looks at the model and provides states that govern the GUI, enhancing separation of concerns. This way, we can produce cleaner logic, such as defining styles based on values—without muddying the model. Rails developers have adopted this concept, termed presenters, for similar reasons.
00:24:23.200 The goal of a presentation model is to separate preparing the view from drawing and maintain a clear distinction between GUI concerns and raw event handling. We can have attributes associated with specific visual requirements without obligating the controller or model to handle them.
00:25:05.760 Addressing application-wide concerns, let’s discuss logouts. It doesn't seem sensible for a view or a controller managing a specific view to handle this. Instead, an overarching application controller manages such state, taking charge of application-wide events. Cocoa adjusted MVC to accommodate this separation, but still with its intricacies.
00:25:44.560 Cocoa merged the view and controller into a single entity while creating a mediating controller. Therefore, logic that intertwines inputs and rendering maintains a coherent approach to user experience design.
00:26:30.080 A coordinated controller manages broader functionalities beyond views—allowing for streamlined responses to higher-level application actions like logout events. Ultimately, this unbundling provides greater flexibility during transitions and ensures that views remain uncluttered.
00:27:11.720 We can visualize the Cocoa method: objects are bootstrapped solidly. The initial UI is rendered using views, transferring raw input into various user intents. Input passes to the mediating controller for domain state updates, while UI changes are communicated through observers or controllers, maintaining structured coherence.
00:27:52.680 As we progress into Ember discussions, we'll acknowledge its similarities to Cocoa but also note its distinct alterations. Instead of mediating or coordinating controllers, we refer simply to controllers and routes. Ember formalizes the routing system, resolving many earlier complexities and presenting a seamless experience.
00:28:42.000 Final thoughts reflect on how Ember embraces the GUI pattern. Rails generates HTML and responds to UI events, while handling persistence. Each state machine and determined relationship offers a well-articulated GUI methodology that allows for smooth transitions and adaptability.
00:29:17.360 MySQL might be implemented via MVC, but it’s not a significant issue. Ultimately, as we segment these elements into their proper MVC constituencies, we create client-side structures that alleviate workload on Rails—allowing it to function purely as a persistence mechanism, streamlining the entire process.