Way back near the turn of the century, Winamp was one of the coolest things around. One of the things that made it cool was plugins, and one of the coolest plugins was one that provided a Web interface. Not only did it let you control your Winamp remotely, but it also had decent interactivity, like a nice indicator of remaining track time, etc. To get the client-side job done, it used plain old HTML, CSS, and JavaScript rather than Flash. And this got me thinking: Why not use HTML, CSS, and JavaScript for the UI for apps in general?
Now I’m sure I wasn’t the first or only person to think this, but the idea of using Web technologies to build desktop apps didn’t really begin to gain much traction until fairly recently. Frameworks like NW.js and Electron, on which GitHub’s Atom and Microsoft’s Visual Code are built, do just that. But they’re not not quite the same thing as what I had in mind: implementing an app as a server that all sorts of different kinds of UI clients might interact with, including those built with Web front end technologies.
Here’s what I mean. Below is a diagram of what Electron and similar frameworks do:
In this model, the user interface is rendered inside a dedicated environment provided by the framework using whatever HTML, CSS, and front-end JS frameworks you desire. The UI is tightly bound in a one-to-one relationship with the app engine. The app engine is implemented with a Web back-end language, typically Node.js, and it makes system calls through the engine’s baked-in features or, if the baked-in features don’t do what you need, through generic child_process.exec()
-like calls that then invoke custom functions written on the host.
What I’ve got in mind looks like this:
In this model, the tight UI↔app engine binding is replaced by a flexible REST API binding, and the app engine is simply a REST server embellished with whatever libraries are needed for accessing the required host resources.
The UI can be implemented with any kind of client that can speak the API, including HTML/CSS/JS clients, native mobile clients, terminal clients, etc. The REST server can be implemented in any language on which a REST server can be built. Thus the language the “app” is written in can be one that most easily supports the necessary system interactions or is otherwise best-suited to the app’s requirements. Also, unlike the conventional architecture, the client need not be local, which makes remote-controlled apps almost trivial to implement. As with any network-based communication, adequate measures must be taken to assure secure communication with the REST server.
So a few vacations ago, I set out to see whether this approach was actually workable. Because I have a high threshold of abuse, my test case wasn’t going to be some self-contained desktop app. Instead, I created a mini research project to study this architecture in the context of real-time control of a physical appliance. (In reality, this was relevant to some other research I was doing. My tolerance of abuse had little to do with it.) The appliance I decided to prototype was an audio preamp with screen-based control.
This is where I ended up:
It’s not much to look at, but there’s a fair amount going on under the hood — which I’ll talk about in a future post.
But for now, that’s all my stories.
Update: An updated description of the system architecture is available in my wiki.