Zero framework frameworks and making the web fun again.

Making stuff should be fun!

It is my belief that when we work we can sometimes get caught up in producing a result and kind of forget about the process. We pride ourselves on being able to “tough it out” or “grind through it”. And there’s a lot to be said for being able to grind through things, but there’s also a lot to be said for arranging work so that it isn’t a grind.

Pleasing patterns

If you’re a modern developer these are largely things you’ve observed, in which case this is a campfire story, fun but already known. But if you’ve stepped away from the web perhaps this will encourage you to come back and play:

  1. WebComponents. React has both functional components and Class Components — which are reasonable ways to express a bit of layout. But I prefer having nothing at all — using only built in features. WebComponents do lack some event handling capabilities — I have found myself trying to listen to MutationObservers to circumvent this. As well, separately the shadow DOM can be a bit tricky. But overall at least you can package up a widget as a single file that includes layout, styling and code in one blob that can move between applications and frameworks.
  2. MobX is a third party framework for responding to state change, so perhaps it breaks the aspiration of a zero framework goal. React is often paired with Redux and it brings along ideas of reducers and defining what the events are. What I find with Redux is that one tends to want to “design ahead of time” and this requires more thinking for me than MobX. That said, the React/Redux pattern can be done in an incredibly elegant and terse way that separates concerns.
  3. Google Firebase provides fairly seamless back end persistence with real time updates. That means that for lightweight game interaction (messaging, the movement of characters on a map and so on) you don’t need to setup any kind of custom high performance websocket. In previous apps quite a bit of energy was spent first writing a client side state wrapper — and then having that state wrapper talk to server side persistence. I wanted client side state replication for speed; and synchronization of all this, especially in a multiple client situation was a big hassle. Applications are mostly state, so being able to use off the shelf pieces here is a big deal. I will say however I tend to not directly work with raw database objects on the client side but rather with composites that are the results of queries. And I’ve found in practice that state synchronization isn’t that much of a hassle to maintain by hand between distributed client instances — so the older Google product ‘datastore’ is often fine as well. This speaks to the ‘API wall’ point below as well.
  4. KISS philosophy on managing state. I tend to avoid anything more complex than vanilla javascript hashes. POJO or Plain Old Javascript Objects are an eminently reasonable way to manage client side state. It’s true that we can think of state as “classes of behavior”, and we can wrap up that class into some kind of class abstraction with methods… but that gets heavy and requires pre-planning on how to partition your universe. Also, inhaling and exhaling assets requires transmogrifying them into class objects — might as well just stick with hashes as they are. This also speaks to the ‘API wall’ point below.
  5. Simple API wall — a library of methods that pass vanilla hashes in and out. I’ll discuss this in more detail below.
  6. Rich clients. Nowadays all my apps are single page apps. The server simply delivers the app to the client once, and then all future interactions are pure queries of an API wall. The server simply services database transactions (mediated by the security of an API wall). Much simpler than building pages on the server with a layout grammar.
  7. Routing. I do tend to write my own in browser routing — I will discuss that at the bottom.

Pulling the pieces together

Here’s one trivial component I wrote recently that pulls several of the above patterns together:

API Walls

We’ve been taught that classes and class abstractions — where a class has methods that encapsulate and act on state — are a useful pattern. Many of us try to define rich classes, class hierarchies, and then manipulate objects by calling class methods. This training can be hard to undo.

Routing

Web designers and developers often break up the user experience into pages. If a user asks for a login, then bit of routing logic finds the login page and serves it to the user.

  1. Event relationships → the wiring between objects. For example an upvote button might be wired to some logic that does some database checks and repaints a display. Or a button could be wired to a fresh page transition.
  2. Object kinds → Often developers arrange objects into class hierarchies. For example a game may have an “animal” page that can show a view of a “cat” or a “dog”. I do prefer to use prototype based categorization but generally speaking there’s often a pattern of prototypical objects and then either instances of those objects or variations of the prototype.

Concluding thoughts

What makes work fun for you? For me programming is an enjoyable quiet contemplative act; perhaps similar to playing the piano or knitting. I want to be able to put something down for a month, and come back to it later and easily pick it up again. It’s especially nice when the sketch or initial framework I have built is one that others can contribute to easily (even if that ‘new person’ is myself later on in time). Often I’m working with novices or designers who have their own ideas, and empowering them to go in and make changes themselves can give them a sense of agency. In sum, to keep work fun I tend to avoid some of the power tools, complicated process and structure and lean towards being more playful in my work.

SFO Hacker Dad Artist Canuck @mozilla formerly at @parcinc @meedan @makerlab