Here is a simple visualization of keyboard and mouse events within the browser. Please play with it and look at the code:


Number of events recorded: 0N, flag:false

  {}
      

This is a simple, concrete example of an application pattern that is summed up in two lines:

  state = combine(state, event); render(state);
      

Architectures are beautiful when written like this. Whole families of related architectures arise from the smallest change. For example, the assignment in the above pattern implies that state is immutable. But this one implies that state is mutable:

  combine(state, event); render(state);
      

Other details, like the fact that this example was written for the browser, or uses d3, or is written in a single html file hardly using any external resources, don't matter. You may be tempted to infer something about the asymptotic relative size of the sections of the code, but that would be premature. In this case it would imply that the render() will tend to dominate in both size and complexity. It's a promising result, but premature because real code doesn't look like this, and doesn't have as many bugs. (Try resizing your browser window to see a bug.)

(This SVG element is there so I have a safe place to write straightforward SVG, because I always forget attribute names!)

Josh

Notes

The '1+N' Pattern

This code demonstrates what I call the 1+Npattern, which is when a program executes once to register for input, and then subroutines execute many times to handle the input it registered for. The first pass is a transient stateand the subsequent passes is the steady state. The example code is the simplest form of the pattern where the N part is truly a steady state, with no possible changes to input registration. (Most real programs dynamically register and unregister for input, in particular anything that uses the network).

Issues with D3

Even simple code like this highlights the difficuly of working with D3. D3 has a cavalier attitude about state; state is stored in the DOM, and it is often stored in closures, making functions essentially stateful. In this case, the color function is stateful, and behaves differently if it is initialized on each render(), or kept between renders. The fact that data is stored in the DOM results in problems if, for example, you have N rects in the target SVG element, in which case D3 will skip N data elements. None of this is fatal, but it does add complexity.

Software Minimalism

There is no build system, just an HTML file. Front-end build systems offer a great deal to programmers, in particular effortless dependency addition and modularization. But they also add a great deal of complexity, and dramatically slow the BTD loop. Experience shows that as dependencies become easier to add, more dependencies are added, whether they are needed or not. And it happens throughout the transitive list. It is the duty of the programmer to own their code, which means owning all their dependencies. It is possible to write full-featured, powerful applications using only a very small number of well-behaved global utilities, added in the old-fashioned way with a wget invocation and a script tag. Additionally, although they can look very good at first, transpiled langauges only add complexity onto the underlying technology. To use TypeScript you still need to be a JavaScript expert; to use LESS you still need to be a CSS expert, and so on. You are buying featuresat the cost of a very complex system that slows you down every timeyou make a code change.

A final and decisive factor is meeting the duty to maintain the health of the devloper ecosystem: build systems inevitably minify and obfuscate resources, which also obfuscate the wisdom of the programmer that built the system. This is a misguided attempt to fight software bloat: you address the symptom, and not the cause, so pages get ever larger. The right way to fight software bloat is to use less software, and use gzip to compress it on the wire.

Simpatico and combine()

The heart of Simpatico is about data-modelling in general, and dynamic data-modelling in particular. In Simpatico, some distinctions are eliminated, while others are made stronger. For example, I will demonstrate that there is no intrinsic difference between object instantiation and subclassing. There is no intrinsic difference between the input that comes from a programmer, an administrator, and an ordinary user. This makes possible a system that has several unique, desirable qualities:

Simpatico and Redux

Although Simpatico predates Redux, it might be useful to draw a path from there to here. Redux follows the same application shape, and also focuses on the combine() function. Imagine if Redux only had one reducer that you didn't write, and instead you parameterize the given reducer with simple, pure functions. It is a special case of a transducer, recently discovered by Rich Hickey of Clojure fame.

Topics:

  1. Stateful programs
  2. Durable process
  3. One communication primitive: Synchronization
  4. Object patterns and collapse
  5. Friendly functions
  6. Handlers
  7. Message cascade
  8. World Event Tree
  9. Stateless cluster
  10. Simpatico written as 4 reductions