loading...

Ceremony vs. Essence Revisited

yysun profile image yysun ・5 min read

Introduction

Recently I found a Youtube video about AppRun, in which the author built and compared the character counts between two similar apps using AppRun and Svelte.

The comparison reminded me of the 'Ceremony vs. Essence' discussion happened about ten years ago. At that time, Ruby was on the rise. People compared Ruby with C#.

The fundamental idea of the Ceremony vs. Essence idea appears to be that, all other things being equal, programming languages should attempt to allow programmers to clearly express the essence of their programs without being caught up in excessive ceremony provided by the programming language. -- From this post.

Let's take a look at some of today's frontend technologies from the Ceremony vs. Essence point of view. We will use a simple button click counting application as an example.

Svelte

The Essence

The essence of the application is to display a button which adds the count by one and shows the count. Also, it will log some messages in the console to mimic effects after the rendering cycle.

The concept is as simple as below.

<button onclick="count+1">
  Clicks: {count}
</button>

console.log(count); // upon very click
console.log('mounted!'); // upon mounted

We will use the 95-character essence code above with a few frontend frameworks, such as AppRun, Svelte, React Hooks, and the Vue Composition API.

A framework defines a skeleton where the application defines its features to fill out the skeleton. -- you can find this quote from googling.

When using the frontend frameworks, we need to write some code to plugin the essence code into the frameworks. The code required to plugin into the framework is the ceremony. We don't want them. Less of them is better.

The Ceremony

AppRun

Application logic is broken down into three separate parts in the AppRun architecture.

  • State (a.k.a. Model) — the state of your application
  • View — a function to display the state
  • Update — a collection of event handlers to update the state
import app from 'apprun';

const add = count => count + 1;

const view = count => <button $onclick={add}>
  Clicks: {count}
</button>;

const rendered = count => console.log(count);

app.start(document.body, 0, view, null, { rendered }); 
console.log('mounted!');

In the example above, the application state is a number that has a default value to be 0; the add function is the event handler to update the state. The view function displays the state. The rendered function runs after the DOM is rendered. The app.start function ties them all together to the document.body element.

Now, we identify and cross out the ceremonies.

AppRun

AppRun code ceremony is mainly required by the JavaScript syntax, like the module import and the arrow functions. The only thing needed from AppRun is the app.start function.

Overall, it has 226 characters, which means 58% of code are ceremonies.

Svelte

Svelte uses a single file for a component. The file consists of a script section for code and the UI template. It requires a compiler to turn it into the runnable JavaScript code.

<script>
  import { onMount } from 'svelte'

  let count = 0;    
  const add = () => count + 1;

  $: console.log(count)

  onMount(() => console.log('mounted!')
</script>

<button on:click={add}>
  Clicks: {count}
</button>

Behind the scene, the svelte compiler creates the component class boilerplate. Then, the compiler extracts the script block, wires up the reactivity ($:), and adds the rendering template into the boilerplate. The boilerplate does not exist in our codebase. Therefore, the svelte application has very little ceremonies.

Svelte

Svelte code ceremony is also mainly the JavaScript syntax requirements. Only the script tags are required by the Svelte compiler, which is worth of trading with what the compiler saves.

It has 217 characters, which means 56% of code is ceremony.

React Hooks

The React code is a slightly modified version from the React Hooks Docs.

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  const add = () => setCount(count + 1)

  useEffect(() => {
    console.log(count);
  });

  return (
    <button onClick={add}>
      Clicks: {count}
    </button>
  );
}

The React code has more ceremonies than the AppRun code and Svelte code above. It has 272 characters and a 65% ceremony.

React

The setCount, _useState, and useEffect functions are the code the deal with the React framework itself. They don't help us to express the essence of the application. They are framework ceremonies.

Vue Composition API

The Vue code is a slightly modified version of the Vue Composition API Docs.

<template>
  <button @click="add">
    Clicks: {{ count }}
  </button>
</template>

import { ref, watchEffect, onMounted } from 'vue'

export default {
  setup() {
    const count = ref(0)
    function add() {
      count.value++
    }

    watchEffect(() => console.log(count.value))

    onMounted(() => console.log('mounted!'))

    return {
      count,
      add
    }
  }
}

The Vue code has 355 characters and a 73% ceremony.

Vue

The ref, watchEffect, onMounted, setup, _count.value, and returning an object of count, and add are all required by the Vue framework. Sometimes, they may make writing code more difficult.

Expression Comparison

We are not stopping at only comparing the character counts. What is more important is how do you express the business logic. How many extra boilerplates are forced to you by the frameworks?

Let's see how do we increase the counter as an example again.

// AppRun
const add = counter => counter + 1;

//Svelte
let count = 0;
const add = () => counter + 1;

// React
const [count, setCount] = useState(0);
const add = () => setCount(count + 1);

// Vue
const count = ref(0);
const add = () => count.value++;

You can see AppRun uses a pure function, which can easily be strong typed if you wish. Svelte is also easy to understand. React and Vue are more difficult.

Conclusion

Both the AppRun code and the Svelte code express the essence well and have less ceremony. I am biased toward AppRun because I am the author. But, I like the Svelte compiler.

React Hooks and Vue Composition API are cool. However, they both add a lot more ceremonies to our codebase. Remember, the ceremony has no business values but more challenging to understand and, therefore, more costly to maintain.

Posted on Mar 18 by:

Discussion

markdown guide