I think the server-side-rendering crowd are onto something

By David Röthlisberger. Tweet your comments @drothlis.

Published 18 Feb 2022.

At my day job we recently implemented a moderately complex scheduling system for running low-priority “background” tasks on idle “nodes”. I wanted a web interface to visualise the status of the various tasks and nodes. Not all nodes are suitable for all types of tasks, so in the web interface we display several different “queues”, just for clarity of the visualisation — the queues aren’t an explicit concept in our scheduling implementation. Instead of having the front-end (browser/javascript) assemble the information about the various tasks and nodes into different queues/tables, I made the back-end (HTTP server) do it. This decision made it beautifully easy to test the status visualisation, and it was also useful for testing the scheduler itself!

Our back-end queries our database about the various tasks & nodes, and assembles the information into a table-like JSON structure, mimicking the eventual HTML layout:

{"queues": [
    {"rows": [{"task": {...}, "node": {...}},
              {"task": {...}, "node": null}]},
    {"rows": [{"task": null, "node": {...}}]},
    {"rows": [{"task": {...}, "node": null},
              {"task": {...}, "node": null},
              {"task": {...}, "node": null},
              {"task": null, "node": {...}},
              {"task": null, "node": {...}},
              {"task": null, "node": {...}}]}
]}

There are some rows with a task and a node (where the node is running the task), some rows with a task but no node (where the task is queued and waiting for an available node) and some rows with a node but no task (where the node is idle, or busy doing something else, or otherwise unavailable).

Our front-end renders this to actual HTML tables:

Tables rendered in the browser

Our unit tests render the same JSON to a simple text format that’s very clear and easy to work with. We can put our test system into all sorts of different states, and clearly assert on the expected output:

Yes, the server’s response isn’t actual HTML. Yes, I know that’s what people usually mean by “server-side rendering”. Yes, the front-end code still has to assemble the JSON into an HTML table — but that code is dead simple, because the JSON structure was designed to map directly to table rows. The real beauty is in the clarity of the unit tests. If you really wanted to render the HTML server-side, I suppose you could have an intermediate function with 2 consumers: A text renderer for the unit tests, and an HTML renderer for production.

Counter-example: When implementing a different feature that required much more front-end interactivity (a log viewer) I moved the pre-processing to the back-end and now I really wish I hadn’t — I’m going to have to undo it in order to add further functionality in that area. Maybe I’ll write another post about that at some point.