About 5 years ago I was working on a project written in style still common for today:
- python backend serving a REST API (public btw)
- SPA using framework-of-the day
And it was horrible. Not to mention that the framework-of-the-day did not actually take off and we ended up using something very fringe – there were real performance and complexity problems. And to this day I believe all our problems stemmed from the base architecture. There were just too many layers, each contributing overhead. Both in execution speed (aka “app is slow”) and development speed (“our velocity is too low”).
Let’s look at a more concrete example. What happened for a typical page load (assuming navigation, otherwise it starts by loading multiple mb of js)
- JS router detects navigation and updates components
- components fetch needed data
- this turns out to be tens (sometimes hundreds!) of requests because the general API is very normalized (yes we were discussing GraphQL at this point)
- then throw most of this data (95%+) away since we don’t really need all those fields (yes yes, GraphQL again…)
- render templates in JS with the processed data
- shove the results in the DOM
…meanwhile the user is impatiently twiddling their thumbs. Sounds familiar? Because this was by far not the only app I’ve seen with this problem. Surely we can do better…
Luckily I had a colleague with Ruby on Rails background. And he was a big fan. Quite loud about how plain old server side rendered pages were much simpler and faster too. It all made a lot of sense so I made a prototype. The above flow was now:
- flask router directs a request to a controller
- controller constructs a query (we already had a query and serialization layer available)
- exactly the data that is needed (column selection) is fetched
- then passed through a presentation layer that makes the view models
- jinja template is rendered
- html returned to the browser
And I be damned, it was faster! A lot faster. If you think about it it makes a lot of sense. It looks like about the same just looking at the line items but it’s actually performing a lot less work and more importantly there is less communication (and thus latency). And the best part? It was also a lot faster to work with. Mostly due to fewer moving parts, so each change needed to touch less places. After all I managed to cobble the prototype together in a single day.
So we went all in on this approach and shipped (a much better version of this) to production to replace a core component of the product (as an opt-in v2 – I’m not completely insane…). Smashing hit. Feature parity in no time, even new feature were added