You are here

You are here

How to use Node.js to build on-premise desktop apps

Spencer Bruce System Architect, HP

When the application my team built reached its 20th birthday this year, we decided to celebrate by modernizing the app's user interface and re-architecting the infrastructure. It's a desktop application, and we wanted to base it on a framework that would take care of most of the technical details, leaving us free to concentrate on features.

We chose the JavaScript-based framework Node.js over Java for this purpose. We liked the development velocity, its excellent I/O abilities, and its lightweight nature. While many Fortune 500 companies have embraced Node.js to power back-end applications, it hasn't been used to develop enterprise-ready, on-premise applications. But there are good reasons why you should consider it. Here are the factors that affected our decision, as well as a few pros and cons to consider when contemplating the use of a relatively immature technology like Node.js over a more established language like Java.

The problem with Java

It's standard practice to develop enterprise-ready, on-premise solutions in Java, C++, or C#. These languages have been around for a long time—they're stable, well known, and the enterprise developer's no-brainer, go-to solution. In our situation, however, we had concerns in three areas:

  • Development velocity. To get a simple server up and running in Java, you have to bootstrap the application with a considerable amount of code and configuration files, and that's before you even get started on your business logic. You can mitigate that to some extent by using a framework such as Spring Web MVC or Apache Wicket. Once you've dealt with bootstrapping, you can start writing the application code. Java is an object-oriented language, so even simple functions must be created within classes. But with anything more complicated, interfaces, factories, and abstraction come into play. It's hard to code in Java without worrying too much about design principles. The code gets compiled many times, and depending on the environment, deployed to a server. As the codebase increases in size, development time can take a big hit. In the development lifecycle, these changes are usually compiled remotely as part of continuous integration, and it can be a long time before the developer receives full feedback on changes and how they affect the overall system.
  • Runtime environment. In order to bootstrap a Java project, you need to decide on the enterprise server. Should you use a full-on dedicated environment, such as JBoss or Tomcat, or something more lightweight, such as Jetty, Spring, EJB, or Java? What about annotations or configuration files? What are the licensing terms for each of these servers? These may seem like minor considerations, but they can complicate the development lifecycle.
  • System resource utilization. When configured correctly, Java can be very efficient with system resources. To achieve this, you need a good understanding of the runtime parameters and how to monitor Java applications correctly. But if you don't have that, most Java-based applications will use far more system resources than Node.js applications. If you have to run a large number of similar processes on the same machine—a major requirement for us—the resource usage becomes even more critical. In our situation, the ability to run several resource-light processes on the same machine was extremely important. That's also a major factor behind the push to microservices, which are becomingly increasingly popular with developers.

These concerns are counterbalanced by Java's many advantages, which have served developers well over the years. However, even the Java community has recognized that Java can gain from modernization, hence the trend of using the Java virtual machine as a basis for running alternative languages such as Scala.

Using Node.js instead of Java

Using a Node.js-based application can mitigate many of the drawbacks mentioned above, while providing additional advantages in all three areas:

  • Developer velocity. To create a new Node.js server-side application, you only need to write about 10 lines of code. Check out the web server example on the front page of the Node.js website for a simple, fully functional example. You can also create a REST-based server application using freely available modules, such as Express. Any time you need to make a change, you just restart the application, with no compilation required. In addition, the front end of the application is also in JavaScript. That's a good thing because having everything in the same language boosts velocity. The coding styles are the same, the developer doesn't need to switch programming methods or languages, and you can reuse some code, such as third-party libraries.
  • Runtime environment. Node.js enables JavaScript programming for the server. That means that most of the bootstrapping work you need to do to develop a server application requires little overhead. However, you'll still need to choose which framework to use (that is, Express, Hapi, Koa, etc.). You can find many blog posts about which one is better based on performance, velocity, usability, and so on. But ultimately, the choice comes down to the developer's personal preference.
  • System resource utilization. Node.js is lightweight, using around 20 MB of memory and very little processing power. Because JavaScript is asynchronous, it can hand off the low-level work to the underlying operating system, while the application itself can handle more requests. This means that many processes can happily run in parallel on the same machine without hogging too many resources. Nevertheless, you should make sure that the Node.js application isn't used to run CPU-intensive tasks. Node.js lives and dies on maximizing its extremely fast I/O capabilities, but because it's single threaded, the moment the CPU utilization increases all other requests begin to queue up. For developers coming from a multi-threaded environment, this is an extremely sensitive point.

Node.js for the enterprise

Many case studies have demonstrated the value of Node.js in the enterprise. However, almost all these stories have one thing in common: the applications are kept under tight control in a cloud-based or SaaS environment, where DevOps teams can constantly monitor, debug, refactor, and update them to ensure they always run smoothly. Companies such as PayPal, Walmart, and Dow Jones serve millions of requests per day through their Node-based applications. If something goes wrong, issues can be mitigated smoothly, with little impact on their customers.

For an on-premise solution, however, developers have none of these luxuries. After installing software on customers' machines, developers need in-depth, precise information in order to understand how the application is performing. Performance can manifest itself in several different ways:

  • Application crashes. When your application goes down, the customer will contact support and expect a prompt solution with minimal disruption. To understand the issues, developers normally need several files, including log files, heap dumps, and audits.
  • Performance monitoring. A bug that affects performance can be even worse than sporadic crashes. You need a way for developers to determine why the application is performing as it is so they can provide a solution.
  • Bugs. When customers encounter a critical bug, they report it to support, which passes it on to the developer, along with an expectation of a quick fix by way of a patch or new release. Unlike SaaS-based applications, however, there's no easy way to roll back to a previous release.
  • Security and licensing. This one is more of an issue for software providers than for the customer, but JavaScript doesn't let you protect intellectual property in the code. Minification and obfuscation can only do so much, and they can be reverse-engineered. Developers must ensure that the software is legally protected so intellectual property isn't easily compromised.

When developing in Node.js, these and other problems need to be carefully thought through. There's no compilation with JavaScript, so full testing is necessary. For example, something as simple as misspelling a function name won't be caught until you run the code. Extensive automated testing can mitigate this, however. Also, logging needs to be extremely thorough so developers can determine the true problem. You should run performance tests that accurately mimic the types of environments on which the application will run, and licensing should be watertight.

Despite all these caveats and potential pitfalls, Node.js was the right technology for what we wanted to achieve. Developer velocity is one of the most important factors in the era of agile programming and continuous delivery, and with Node.js our velocity increased significantly. We developed a complex state machine in just four weeks, about half of what we estimated it would take to develop the equivalent code in Java, and we saw similar gains after rewriting large sections of the product's back end.

Another huge benefit of coding in Node.js, and in JavaScript in general, is that developers spend all their time actually writing and testing code, rather than having to wait for the codebase to compile first. Most of the work we needed to do was ultimately suited for asynchronous, I/O-based, single-threaded processes. Our developers are now able to switch from client to server development smoothly.

Yes, we worry about our intellectual property being stolen, and we minimize this by coding our most secret algorithms in C++. But the rest of the code enjoys the convenience and flexibility of Node.js, which was the right decision for us.

Image source: Flickr

Keep learning

Read more articles about: App Dev & TestingApp Dev