It’s pretty common the write a web application in two parts: a frontend, perhaps using Angular or Knockout; and a backend, perhaps using Django or Rails or some similar framework. The two codebases are largely independent, joined only by an API between them, perhaps conforming to REST principles and maybe even a Swagger or Pact defining the API.
But that means three conjoined components already, and we haven’t even considered
the database, or any external components or gateways.
Sure, you could forego a separate frontend and just write everything as HTML templates, but then you’d have to do actual page loads and people would think you were uncool (to be fair: AJAX partial content loads are one of the few things which are actually good about the modern web)
I was originally thinking about this … I don’t know, some time after 2006 which was when I got into Python but before 2011 which is when the idea morphed into Python in the Browser and crawled off to die.
Zombie takes a rather stupider, more direct approach.
The browser loads a dummy page with content suitable for SEO. There’s not much interesting about that page, but it includes the zombie loader:
That’s going to make the browser
GET the zombie loader code, which looks something
This tiny snippet of code creates a function
Z, which establishes a connection
back to the server, passes over a message
args and asks it what to do next.
Those snippets, in turn, can use
Z to send more messages back
to the server. The browser is no longer an independent process with its own mind:
it is a zombie, under control of the server process.
The server could be implemented in just about any language, the messaging protocol could run over POST requests or over WebSockets or whatever technology the browser people come up with next. So long as the zombie messaging protocol is agreed upon, it doesn’t really matter.
Yes, this all sounds horribly inefficient and in a lot of ways it is: your backend is sending chunks of HTML instead of neat snippets of JSON, and there’s some extra chatter back and forth as events occur. But the transport is compressed anyway, and because we have control of both ends of the process, we can choose to only send events we’re interested in receiving, not every keystroke and mouse movement.
And in return for which, we’ve reduced our cognitive load: only one code base, no need for a build pipeline, no need to document or implement an API. The time we would have spent on that stuff we can spend on developing features our users actually care about.
The zombie loader is indeed
eval()ing code (more or less), and that sounds like
a scary thing, but that code is coming from the same server from which the loader
was loaded: you’ve already been bitten, you might as well start staggering around.
So rather than your HTML5 frontends consuming your microservices directly, they talk to their Zombie BFF (Backend for Frontend) which talks to those services on their behalf: easy peasy. The BFF layer doesn’t hold much state, maybe just a little bit of per-user cache and session info, so can be scaled out horizontally, geographically dispersed and killed off on a whim.
At this point, the
BRAINS! jokes are just writing themselves.
For the real inspiration, see
but there’s no way I’m naming a project that.
To be continued … very sketchy first experiments for a Python implementation of Zombie on GitHub