I’ve seen this question posed about EWD.js, something along the lines of:
Why should the VA and others put their faith in and backing behind EWD.js, a framework developed and supported by a small UK company, when there are plenty of well-known and community-supported Node.js frameworks for web application development?
I’d like to try to answer that question fully in this article.
It is quite true that the Node.js community has created a large number of frameworks for Web Application development. Natural selection has tended to whittle them down, and the most popular and well-known are Express and Meteor.js. Here’s a more complete list.
InterSystems have included a native Node.js interface for Caché, but you can, if you wish, use a TCP-based connection: the Node.js “Net” module makes it very straightforward to make such a connection.
So why indeed should the VistA development community use EWD.js instead of one of the more well-known frameworks, and why use the InterSystems interface instead of a simple TCP-based connection and a Mumps-based socket-server?
The simple answer is that there’s nothing to stop anyone having a go and “rolling their own”. But before you do, I’d encourage you to stop and think. What you get from using EWD.js is:
- a framework that has been built on my 30-plus years of experience of Mumps and Caché, and my 20 years of experience in integrating them with web technologies, working with some of the very largest developers of Caché-based web applications to create internet-facing applications that are fully secure, highly scalable, highly performant and easily maintained (not, as it happens, a simple combination of requirements!).
- my extensive experience of using Node.js in conjunction with Caché and GT.M since early 2011 when Node.js was just over a year old. I was the first person in the Caché and Mumps community to work with Node.js, and have used it to create a number of non-trivial applications, learning what works well and what doesn’t work well when integrating with Caché and Mumps and what techniques are required for rapid application development.
- a standardised way of working and developing browser-based Caché and Mumps applications, based on tried and tested techniques that allow team collaboration, rapid development and easy maintenance. Rather than promoting a free-for-all of different techniques and approaches to the use of Node.js, Caché and Mumps, wouldn’t it be better if everyone conformed to a single approach?
Let me drill down into these issues a little more.
The Benefit of Experience
You can read more about my experience in the About section of this blog site.
Securing the Future for Mumps and VistA
I’ve been concerned for quite some time about the dwindling pool of developers with Mumps expertise and the disdain with which the wider mainstream of IT views Mumps as a technology. The situation is unsustainable and approaching a critical state where there will, quite simply, be insufficient people with the knowledge and expertise to understand VistA’s Mumps internals, let alone continue to support and develop it. The stark and unpalatable truth is that without a viable strategic solution, VistA’s days are numbered, no matter how good an EHR it is. One of the core design goals of EWD.js is to provide a strategic solution to this critical issue.
I’ve not seen or read about any other alternative that is workable in the longer term or has any chance of success.
- work properly and efficiently with the Mumps technology stack in a way that makes the best of the features it provides. Only someone with broad and deep understanding and many years of experience of the Mumps technology can do that. The Node.js community does not have the necessary understanding of Mumps and their frameworks were not designed with Mumps in mind. Indeed, from my experience, there’s barely anyone in the Node.js community who has even heard of Mumps or Caché.
Asynchronous Logic: Callback Hell!
One of the features of Node.js is the use of asynchronous logic whenever any resource is accessed that is not already in memory and that will take time to fetch, for example, files, external web services or data held in a database. The truth is that asynchronous logic is hard to deal with. I bear the scars! It’s difficult and non-intuitive to write, particularly for developers who are used to the more usual synchronous style of coding seen in most other programming languages. Even more importantly, asynchronous logic is also extremely difficult to maintain.
I have a great deal of practical experience of this: I re-wrote using Node.js an emulation of Amazon’s SimpleDB database that I had originally written in the Mumps language. Whilst the Mumps version took less than a week to write, the Node.js database took a lot longer and was actually quite an unpleasant task in the end: indeed I had to give up even attempting to re-write the SimpleDB SQL-like query interface logic that had been easy to express as synchronous logic.
Even though I wrote it, I can barely understand how or why my node-mdb project now works!
This experience made me realise just how difficult it would be for a non-trivial Mumps application such as VistA to be integrated with Node.js and what an unmaintainable result would likely ensue even if we could find developers to do it. What node-mdb proved to me was that whilst simple file access and web service access is pretty simple to express using asynchronous logic, handling the complex business logic that goes hand-in-hand with database access (involving multiple combinations of conditions, loops and recursion) becomes a completely unworkable nightmare very quickly.
The standard Node.js solution to this is to use syntactic tricks that allow asynchronous logic to be expressed in terms that have a synchronous appearance, eg Promises, Streamline etc. My experience of these techniques is that whilst potentially helpful, they have kinks and aren’t entirely intuitive, and are still a far cry from standard straightforward synchronous logic that the average application developer understands.
Exploiting CPU Cores in Node.js
Node.js applications run in a single process as a single thread of execution. This means that a Node.js application cannot make use of multiple CPU cores. Additionally, CPU-intensive logic can kill the performance of a Node.js system. The standard Node.js solution is a built-in module called Cluster which hives off incoming requests to child processes that share the load. This would work fine against Mumps systems provided you used a thread-safe, asynchronous interface.
Before the native InterSystems Node.js interface to Caché became available, I experimented with asynchronous TCP-based interfaces (eg node-mwire). Whilst these worked, it turned out that such interfaces were far too slow for large-scale production systems, mainly because they relied on indirection within the underlying Mumps server code. Of course, they forced me to write all my database-handling logic in asynchronous code.
The native Intersystems Node.js interface uses Caché’s very low-level call-in interface and is therefore significantly faster than a TCP-based interface backed by Mumps indirection. It also provides a synchronous version of its APIs. Unfortunately, Caché is not thread-safe, so simultaneous access from multiple requests from within the standard Node.js Cluster module cause pretty spectacular crashes! Getting the benefit of the InterSystems Node.js interface plus full utilisation of your server’s CPU cores isn’t so simple!
WebLink’s Architecture Revisited
Not only does EWD.js therefore allow full use of the available CPU cores by the child processses, it also allows use of the synchronous, high-performance APIs provided by the InterSystems Node.js interface. Because each child process connects to Caché via its own instance of the InterSystems Node.js interface, and because only one user’s requests is serviced at a time by each child process, thread safety is not a problem. Furthermore, because each child process is servicing just a single user’s request, any miniscule delays waiting for a synchronous API to return data from the Mumps or Caché database affect only the user in question. Meanwhile the core EWD.js process is fully asynchronous, so continues to handle the receipt and queuing of other incoming requests and returning completed responses from other child processes.
EWD.js: The Best of All Worlds
And so, if viewed as a whole. what EWD.js provides is the best of all worlds:
- You don’t need to use pseudo-synchronous syntactical tricks. All your database-related business logic can be expressed in true, standard synchronous terms, making it fast to write, simple to understand and quick and easy to maintain. . You can nevertheless use any standard asynchronous Node.js module for file handling, external web site and web service access etc.
- You can use all your server’s CPUs to the maximum
- The front-end of EWD.js that handles incoming requests and returns outgoing responses is, however, fully asynchronous and runs in a single process: it’s standard Node.js stuff that gives you all the performance expected of Node.js.
EWD.js: Goodbye Ajax, Hello Client/Server
EWD.js has one further trick up its sleeve. Rather than being a simple HTTP(S) / Ajax-based framework, EWD.js is based around WebSockets and allows you to create what are, in effect, event-driven client server applications that run in the browser. They are akin to CPRS, except that instead of a thick client, the UI is provided by a standard browser. Unlike an HTTP/Ajax application, it’s completely event driven, meaning no more inefficient or ineffective polling by the browser when it needs to react to changes on the server or database: the back-end can send a message to the browser at any time of its choosing. This changes everything as far as the design of browser-based applications is concerned.
Oh and by the way, just to in case anyone has concerns about the high-end scalability of WebSockets, EWD.js provides an option to allow messages sent from the browser to server to be handled using Ajax. Of course, in doing so you lose ability to autonomously send messages from the server: you’re back to Ajax polling.
Still Interested in Express?
So before trying out something like Express, remember the following:
- you’ll be limited to HTTP / Ajax
- all your back-end database-handling logic will have to be asynchronous: good luck with that!
- you won’t be able to take advantage of the Cluster module if you want access to the high-performance Intersystems Node.js interface to Cache because it isn’t thread-safe, so you’ll have to revert to a much slower TCP-based interface
EWD.js is Available Today, and Works
Meanwhile EWD.js is available today, it’s working in production Mumps environments such as at Oroville Hospital. It’s tried, tested, fast, scalable and even includes a secured web service interface and accompanying REST server module. It allows you to implement and support as many simultaneous applications as you wish. It allows you to control the run-time environment from a browser (via an EWD.js application named ewdMonitor). It allows you to debug using the standard Node-inspector toolset.
Critically, EWD.js looks after all the underlying infrastructure of browser applications, leaving you to focus on your application’s logic: the UI logic and back-end database logic. That’s all you need to write: leave EWD.js to do the rest.
It’s super-fast to develop in, and the code you write is easy to understand and maintain.
Putting All your Eggs in the M/Gateway Development’s Basket?
What about the fact that EWD.js has been written by a small UK company and you’d be putting all your eggs in their basket? What if Rob Tweed get’s run over by a bus whilst he’s out on his favourite road bike?
Well that’s the very reason it’s been made available as an Open Source project.
- the core process is just 1650 or so lines of code
- the child process logic is just 880 lines of code
Avoid Fragmentation and Let’s not Reinvent Wheels
The more people who use EWD.js, the less reliant you become on support from M/Gateway. I’ve already set up the community site for EWD.js support.
And if everyone uses EWD.js, then everyone is building on top of VistA in exactly the same way, and the VA will be able to share applications and VistA extensions with the Open Source community and vice versa (EWD.js applications run identically, without any change, on GT.M).
I’m passionate about ensuring that the Mumps database that I’ve had such fun working with throughout my career continues in the hands of the next generation. I’m also passionate that we don’t lose hugely important Mumps applications such as VistA.
Now, let’s start modernising VistA!