Year 1 / Module 2 Programming interactive systems / Unit 5 / Keeping state and view apart

Keeping state and view apart

HCI1102 · Unit 5 of 10

Separating application state from its rendering removes the class of bug in which two copies of the same fact disagree, but it relocates rather than removes the risk of untested logic, so the separation is a dial and not a rule.

Keeping state and view apart

An interactive program holds facts: whether a panel is open, which row is selected, how many items remain. Those facts must appear on screen. A program that keeps the fact in one place, and a picture of it in another, can hold two versions that disagree. This unit argues that separating application state from its rendering removes that class of bug. It also argues that separation is a dial rather than a rule. Each step along the dial moves risk of another kind, into mapping logic that nothing tests until a test is written. The strongest counter-argument, taken up below, is that this benefit has never been measured the way it is claimed. No study holds the feature set constant and counts defects per feature, and the evidence that does exist measures speed.

Talk of model-view-controller has circulated since 1979. The literature agrees that some separation helps, and disagrees about how much, where the seam should fall, and how the benefit is measured. Unit 6 moves the state further out, onto a machine the program does not own.

The class of bug the separation removes

The bug is the default arrangement of a form. Fowler describes a client-server screen as holding three copies of the same data: record state in the database, session state in memory, and screen state in the controls (Fowler, 2006). Data binding is tricky, because a change to a control can update the record set, which updates the control again (Fowler, 2006). When the copies drift, the interface shows one value and the program acts on another.

Where the separation came from

Reenskaug's 1979 note names the models, views and controllers of a user interface, and argues that each view should be associated with its model and its controller (Reenskaug, 1979). The teaching form arrived a decade later. In the Smalltalk-80 cookbook, model-view-controller is a three-way factoring in which different classes take over the application domain, the display of the application's state, and the user interaction (Krasner and Pope, 1988). The mechanism is a pattern, not a framework: Gamma and colleagues catalogue Observer, Composite and Strategy, so that a view is told when its model changes (Gamma et al., 1994).

Decomposition should hide a decision likely to change

Parnas supplies the criterion for where the seam should fall. He argues that decomposition should improve a system's flexibility and comprehensibility. By worked example he shows that dividing by processing steps is worse for those goals than hiding a decision likely to change (Parnas, 1972). Separating a fact from its display hides how the fact is presented, which is what changes when a designer, a device or a user changes their mind. His worked example is the KWIC index, a program that prints every circular shift of a title in alphabetical order. Arrange it in the order the data flows, and a change to the input format or the output style ripples through most of the modules. Arrange it so that each module hides one decision likely to change, and the same change touches one. The seam, not the module count, sets the cost of the next change. The route has a limit: Kiczales and colleagues argue that some concerns cut across classes, and cannot be cleanly modularised by classes alone (Kiczales et al., 1997).

Separation is a dial, not a rule

How much separation is enough is where the advice stops being a rule. Fowler finds not one pattern but a family: forms and controls, model-view-controller, the VisualWorks application model, model-view-presenter, presentation model and the humble view (Fowler, 2006). Model-view-controller, he warns, is much misunderstood, and systems carrying the name display important differences (Fowler, 2006).

Feathers turns the dial from the practical end. In the humble dialog box he builds the smart object first and drives it test-first against a stand-in view, and creates the dialog last. Gestures then delegate to commands, and the smart object answers with simple setter calls (Feathers, 2002). His example is a chain composer for a list of audio filters, and his counter-example is a conventional tax view. Its getters and setters let computation accumulate until, he writes, you would have to hire a lawyer to find the logic.

The dial has measured stops. Passive view makes the widgets entirely humble, removing the small mapping risk that presentation model carries, at the price of a test double that mimics the screen and must be kept truthful (Fowler, 2006).

What the separation relocates

Moving logic out of the view removes the two-copies bug for the fact that moved. The mapping between state and view is new code, and so is any derived value. Feathers' concession is careful: the only untested code left is a thin wedge at the interface, simple delegation and value setting (Feathers, 2002). Fowler's test double sharpens the point: the stand-in is itself a second description of the screen, so a double that stops matching it is a new pair of copies that can disagree.

Reactive programming puts the propagation in the language

If manual propagation is a source of bugs, one response is to stop writing it. Bainomugisha and colleagues survey reactive programming, the paradigm in which computations react to changes in their dependencies, and classify the approaches along six axes, including glitch avoidance and multidirectionality (Bainomugisha et al., 2013). Czaplicki and Chong present Elm, in which signals describe time-varying values and updates are asynchronous. They argue that the model removes a class of handler-order bugs (Czaplicki and Chong, 2013).

Standardisation is moving the same way. The TC39 signals proposal defines a writable state signal and a derived computed signal, with automatic dependency tracking, lazy evaluation and memoisation, and aims to decouple the reactive model from the rendering view (TC39, 2024). It reached Stage 1 in April 2024, with a polyfill and no engine implementation when it was checked for this course. Automating propagation removes the manual synchronisation bug, but correctness is not free. Glitch avoidance is a named problem, so a derived value can be computed from a partly updated graph (Bainomugisha et al., 2013). The smallest case has a source value, two values derived from it, and a fourth that sums them. A naive engine can recompute the sum after the first has changed but before the second, reporting a total that belonged to no consistent state. A signal graph can still be wrong; it is wrong in a new place.

Model-based routes derive the interface from a model

Paterno argues that task models should drive the design, development and evaluation of interactive applications (Paterno, 1999). MARIA carries this to a concrete form. It is a declarative description language with several abstraction levels and transformations, used at design time and at runtime to generate interfaces adapted to the devices at hand during migration (Paterno et al., 2009). The same seam lets one state be shown as larger text or a linear reading order on a low-bandwidth page, so separation serves access as well as testability.

Souchon and Vanderdonckt review the XML-compliant interface description languages against an analysis grid. The field needs an in-depth analysis, they argue, of what makes the proposals distinguishable and appropriate for a given purpose (Souchon and Vanderdonckt, 2003). Without agreed criteria for what an interface model is, the route turns separation into a coordination problem of its own. Model, transformation and target form are separate artefacts, and agreement among them is untested logic of the same kind.

Contested question: how much separation is enough, and measured against what?

The literature agrees that some separation is good, and disagrees about how much, and about what would count as evidence of the benefit. The separation camp holds that more separation buys testability. Its case is practitioner reasoning rather than experiment. Feathers moves logic into a smart object so that most of the interface's risk can be tested without the hard-to-test widgets (Feathers, 2002). Fowler records that passive view removes even the small mapping risk that presentation model leaves, at the cost of a test double (Fowler, 2006). Neither source reports a controlled comparison, so the position rests on the mechanism and on the examples.

The measurement camp accepts the mechanism and doubts the accounting. Its evidence is that the field measures the wrong quantity, and that where it does measure, the numbers are small and local. The reactive survey names glitch avoidance and multidirectionality as open problems, so an automated graph can still hold a derived value that belonged to no consistent state (Bainomugisha et al., 2013). The one recent quantitative comparison reports an average reduction in execution time of about 17 per cent against Redux, MobX State-Tree and Recoil, on its authors' own scenarios (Oleshchenko and Burchak, 2023).

A third strand explains why the argument will not close on definitions. Fowler's caution that model-view-controller is misunderstood means the parties disagree about what the separation is, not only about how much of it to use (Fowler, 2006). What would settle it is a comparison the field has not run. Hold the feature set and the team constant, vary only the point of separation, and measure defects per feature and the cost of a specified change, with the Oleshchenko benchmark replicated independently. Until then a designer should prefer the smallest separation that makes the logic testable, and keep the mapping in one place with a test of its own. Judge the result on defects and the cost of the next change, not on speed.

Where the argument is heading

Two lines of named work point the same way. The TC39 signals proposal would make the derived value a language primitive, moving the propagation seam into the platform, where glitch behaviour can be specified once rather than per project (TC39, 2024). The evaluation problem Souchon and Vanderdonckt identified is still open: how to compare the architectures that result (Souchon and Vanderdonckt, 2003).

The sources this unit rests on

  • Reenskaug, T. (1979). MODELS-VIEWS-CONTROLLERS. Xerox PARC technical note. https://web.archive.org/web/20100919072311/http://heim.ifi.uio.no/~trygver/themes/mvc/mvc-index.html Names the models, views and controllers of a user interface and argues each view should be associated with its model and controller. The primary source of the separation.
  • Krasner, G. E. and Pope, S. T. (1988). A cookbook for using the model-view-controller user interface paradigm in Smalltalk-80. Journal of Object-Oriented Programming 1(3), 26-49. https://www.lri.fr/~mbl/ENS/FONDIHM/2013/papers/Krasner-JOOP88.pdf Defines the pattern as a three-way factoring in which different classes take over the application domain, the display of the application's state, and the user interaction. The canonical statement of what is separated.
  • Gamma, E., Helm, R., Johnson, R. and Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Reading: Addison-Wesley. https://web.archive.org/web/2023/https://www.oreilly.com/library/view/design-patterns-elements/0201633612/ Catalogues recurring design patterns, including Observer, Composite and Strategy, each with a name, an intent, a structure and consequences. Observer is the mechanism by which a view learns its model changed.
  • Parnas, D. L. (1972). On the criteria to be used in decomposing systems into modules. Communications of the ACM 15(12), 1053-1058. doi:10.1145/361598.361623 Argues decomposition should improve flexibility and comprehensibility, and shows by worked example that decomposition by processing steps is worse for those goals than hiding a decision likely to change. The criterion that makes state and rendering a seam.
  • Kiczales, G., Lamping, J., Mendhekar, A., Maeda, C., Lopes, C., Loingtier, J.-M. and Irwin, J. (1997). Aspect-oriented programming. ECOOP 97, Lecture Notes in Computer Science 1241. doi:10.1007/BFb0053381 Introduces aspects for concerns that cut across classes, arguing some cannot be cleanly modularised by class decomposition alone. It limits what one object split can capture.
  • Fowler, M. (2006). GUI architectures. martinfowler.com. https://martinfowler.com/eaaDev/uiArchs.html Surveys GUI architectures, from forms and controls through model-view-controller and model-view-presenter to presentation model and the humble view, and names the record, session and screen state a form holds. It maps the design space.
  • Feathers, M. (2002). The Humble Dialog Box. Object Mentor; republished by Martin Fowler. https://www.martinfowler.com/articles/humble-dialog-box.html Argues interaction logic belongs in a testable smart object rather than the interface class, worked through a chain composer for a list of audio filters driven by tests against a stand-in view, and concedes that a thin untested wedge remains.
  • Bainomugisha, E., Carreton, A. L., Van Cutsem, T., Mostinckx, S. and De Meuter, W. (2013). A survey on reactive programming. ACM Computing Surveys 45(4), 52. doi:10.1145/2501654.2501666 Surveys reactive programming as the paradigm in which computations react to changes in their dependencies, and classifies approaches along six axes, including glitch avoidance and multidirectionality. Establishes the family and its unsolved correctness problems.
  • Czaplicki, E. and Chong, S. (2013). Asynchronous functional reactive programming for GUIs. PLDI 13, 411-422. doi:10.1145/2491956.2462161 Presents Elm, a functional reactive language for graphical user interfaces in which signals describe time-varying values and updates are asynchronous, and argues the model removes a class of handler-order bugs. The strongest alternative to hand-wired listeners.
  • TC39. (2024). JavaScript Signals standard proposal. TC39 proposal, Stage 1. https://github.com/tc39/proposal-signals Defines a signal primitive with a writable state signal and a derived computed signal, with automatic dependency tracking, lazy evaluation and memoisation, and aims to decouple the reactive model from the rendering view. Reached Stage 1 in April 2024.
  • Paterno, F. (1999). Model-Based Design and Evaluation of Interactive Applications. London: Springer. doi:10.1007/978-1-4471-0445-2 Argues task models should drive the design, development and evaluation of interactive applications, and presents notations and methods with worked case studies. Introduces the model-based route in which the interface is derived from a task model.
  • Paterno, F., Santoro, C. and Spano, L. D. (2009). MARIA: a universal, declarative, multiple abstraction-level language for service-oriented applications in ubiquitous environments. ACM Transactions on Computer-Human Interaction 16(4), 19. doi:10.1145/1614390.1614394 Presents a declarative user interface description language with several abstraction levels and transformations, used at design time and runtime to generate interfaces adapted to devices during migration. Shows separation when the interface is generated.
  • Souchon, N. and Vanderdonckt, J. (2003). A review of XML-compliant user interface description languages. DSV-IS 2003, Lecture Notes in Computer Science 2844, 377-391. doi:10.1007/978-3-540-39929-2_26 Reviews the XML-compliant user interface description languages against an analysis grid and argues the field needs an in-depth analysis of what distinguishes them. The model-based route lacks agreed criteria.
  • Oleshchenko, L. and Burchak, P. (2023). Web Application State Management Performance Optimization Methods. ICCSEEA 2023, Lecture Notes on Data Engineering and Communications Technologies 181, 59-74. doi:10.1007/978-3-031-36118-0_6 Proposes an atomic, fragment-based approach to client-side state and compares it with Redux, MobX State-Tree and Recoil, reporting an average reduction in execution time of about 17 per cent on its own scenarios. A case of the field measuring speed rather than defects.

Check your understanding & apply it · 4 questions, 1 essay

1A reporting form keeps the selected date range in a script variable, in two input fields and in a text label, and repaints the chart by reading the fields and the label back. Users occasionally see the label show one range while the chart and its query use another. Following the unit's account of the bug, what class of fault is this?
2Parnas (1972) shows by worked example, the KWIC index, that dividing a system by processing steps is worse for flexibility and comprehensibility than hiding a decision likely to change. How does the unit use that criterion for the state-and-rendering split?
3Feathers (2002) builds a smart object first, tests it against a stand-in view, creates the dialog last, and concedes that the only untested code is a thin wedge of simple delegation and value setting. What does that concession establish for the unit's second claim?
4Oleshchenko and Burchak (2023) report an average reduction in execution time of about 17 per cent for their state layer against Redux, MobX State-Tree and Recoil. What does the unit say the finding does and does not establish?
5Essay A team builds a reporting dashboard. The selected date range is held in a script variable, and the chart is repainted by reading the values back out of two date input fields and a text label. Users report that occasionally the label shows one range while the chart and the underlying query use another. Using the model in this unit, name the class of bug at work, explain the separation you would introduce and where the seam should fall, identify the new untested logic that your separation creates, and state how you would test it and what would remain hard to test. Refer to the unit's sources where they bear on your answer.