Embracing Node.js & Universal JavaScript to power the customer experience

Having worked with C# for at least half my career (and later a Java stack), I initially looked down on JavaScript. From the perspective of a “server-side engineer”, it was always the ugliest part of any codebase - good for enhancing web applications with AJAX calls and other client-side magic, but not for powering core functionality.

Node changed everything, not just from a technical standpoint, but how we work together to reach the customer.

The evolution of the front-end engineer

Most of us have worked in software development teams where engineers were exclusively server-side or client-side in focus, or ‘T-shaped’ - with some involvement in both.

“Organisations which design systems … are constrained to produce designs which are copies of the communication structures of these organisations”
M. Conway, 1968

While cross-functional teams solve many of the problems of functional teams, they are still prone to siloing. On the front-end in particular, they are often constrained by the disparity within the classic web application architecture:

  • Data is bound with a view on the server-side and sent to the client
  • Markup is ‘enhanced’ on the client to improve experience

These two states have typically been engineered using two different languages. In a cross-functional team for example, it might be the person sitting next to you doing the Java work, but what if she would like to pair on a problem with someone who really knows that part of the stack in-depth? She’s either got to go outside of the team to get help, or sit tight and solve it. This scenario represents potential problems for a cross-functional team:

  • If there’s a poor organisational (or team) culture, she could feel isolated or unfairly blamed for team performance — bad for morale
  • She could feel she has to rush and introduce bugs
  • Other team members are blocked from working on related tickets, reducing flow

Above all though, an opportunity is lost — teams get stronger when people can dive into problems, share ideas and help each other out with ease.

By enabling JavaScript to run pretty much everywhere, Node has enabled our front-end teams to completely remove the notion of ‘server-side’ and ‘client-side’ - engineers now work together on not just the complete lifecycle of a request but on the whole front-end architecture. Full-stack engineers (with specialisms) can now code servers, full test suites, build-deployment pipelines and client-side logic in one common language. In effect, a silo has been removed and context-switching reduced.

In terms of the customer experience, this evolution into teams of ‘full-stack engineers’, means we are more able to solve problems rapidly as a unit. At YNAP for example, we regularly monitor the error rates of our Node applications in the wild to ensure the number of unhandled exceptions is zero. Should that change, multiple team members are able to fix problems anywhere in the front-end stack very quickly. More senior members may need to give guidance from time to time — but this is usually down to knowing the anatomy of the http request/response lifecycle or broader architecture than deep knowledge of the application tier itself.

“Imagine an HTML developer who has to ask a Java developer to link together page “A” and “B”. That’s where we were”
Jeff Harrell, PayPal

Our experience is not unique, with big players such as PayPal reporting similar gains in productivity some time ago and others such as Netflix even building out their APIs with Node too.

Node.js at Netfix by Kim Trott

A note on architecture: I feel it’s important to point out that good architecture (not to mention people) makes a big difference to “full-stack engineering” in practise. Node enables our front-end engineers to be full-stack where it makes sense. A good microservices architecture means our Node apps are responsible for data access, rendering and communicating with the client while other services are responsible for heavy data composition, computation etc. Separation of concerns is still important to make sure engineering skills are not being spread too thin.

Customer experience demands faster change

With technology becoming cheaper, more accessible and easier to use there is growing pressure on businesses to not just deliver their product or service on the channels their customers expect, but to truly understand what the customer wants from their interaction with the business. AI is soon to become the driver of UI, which combined with the growing volume and quality of data we gather, means there is more demand than ever for us to build lightweight systems that can be deployed quickly. We are heading in a direction where organisations must not only move away from monolithic IT systems shaped by the business, but to services that are defined by the customers themselves. If you need to build a special interface just for your top customers for example, doing this as part of a monolith will likely mean a competitor or market disruptor will do it better as a bespoke service that can be updated and deployed constantly.

Pace of innovation over technology

Many large organisations have been responding to this by building lightweight microservices to power specific areas of their online offering. You could of course use many technologies to build microservices, however what separates Node from the rest of the pack, particularly in the modern climate, is the rate of progress and change within the JavaScript community itself (and by extension the npm ec0system). There is a scarily-fast rate of advancement, with the open-source community banging out modules, application boilerplate and tooling to get developers going quickly all the time.

modulecounts.com — new modules in last year (to May 2017)

With the customer push for faster change I mentioned earlier, the ‘hacking culture’ where new ideas can be quickly experimented with and prototyped, is more important than ever. Beyond the specific technologies, JavaScript and the Node ecosystem lends itself well to trying ideas out, innovating and getting things into production FAST. At YNAP for example, front-end engineers used to spend a long time getting a Java monolith to run locally before anything could be done. Now we spin up apps in seconds and if a 3rd party tool doesn’t quite work for us, we will build one from scratch in a matter of days, whether it’s a mock API or a monitoring tool.

Less is more

There is little propriety value or competitive advantage in much of the code written for web applications, nobody cares about your date formatter. Node’s modular architecture enables us to write as little code as possible to solve business problems by composing relatively small amounts of open-source functionality to do much of the heavy lifting for us.

By writing less volume of code, we are able to focus more on quality. More specifically, we can shift focus to building more sophisticated levels of automated QA, which is critical to achieve continuous delivery — test suites, benchmarking, automated performance analysis etc. This is the stuff that really impacts the customer as you can spend less time on problems and more time on things that matter. Have a read of this post by Twitter’s Engineering team about Twitter Lite and it’s plain to see how much of their time has been dedicated to performance, data usage and loading times over 2G/3G — things that impact their users significantly. It’s hard to achieve these things without reducing time spent elsewhere.

“The simplicity of this basic architecture has helped us deliver exceptional service reliability and efficiency at scale”
Nicolas Gallagher, Twitter

Keeping it simple

Our servers are thin — it used to take a “release team” made up of people from multiple functions, over an hour to release changes, on a set date, at a set time. A release would usually bundle together code changes from various teams, risking rollbacks and other problems.

Architected well, a Node application should be simple and narrow in focus — meaning releases have more confidence and engineers at the front-end can focus on the customer experience. A problem can go from being reported to being fixed, tested and released in the same day if really needed. All of this means the customer is able to see the benefit nearly as quickly as the problem can be fixed. Automation aside however, a lot of that confidence comes from the fact these applications focus on a specific slice of the customer journey.

High performance needs front-end control

There has been talk of the direct relationship between customer engagement and performance for some time e.g. 40% of users will abandon a site if it takes longer than 3 seconds to load. The fact is, many applications easily hit their 200ms server-response budget and 80%+ of the end-user response time is then spent on the front-end.

Steve Souder’s infamous waterfall — performance is a compound problem

As I mentioned earlier, many front-end teams out there will not have much control over server-side rendering and asset delivery. This is no longer acceptable if you really care about performance at the front-end. Front-end engineers need to be empowered to determine exactly how/when assets are delivered and exactly how the critical-path is rendered in order to deliver best-in-class experience. Optimisation strategies such as code-splitting (for dynamic loading) and service-workers all need direct control over the server-tier. Lightweight Node servers are ideal for empowering an engineering team to really get their arms around all aspects of performance.

At YNAP for example, we server-side render all of our React applications for performance and accessibility. For a next-generation application, members of my team wanted to use styled-components for handling CSS delivery— a module that can render and inject just the required amount of CSS to render the current page. The Node ecosystem allowed them to immediately rip out the whole CSS delivery approach for that application (after some testing) and replace it with something that will be felt by the customer on the front-end (CSS download is a huge bottleneck).

So using JavaScript everywhere is the silver bullet?

No. Technology alone is never going to make your team perform better or bring you closer to the customer. At YNAP, we have been on a journey for several years, evolving through various team structures and agile approaches on top of our move to front-end microservices and Node.

I have always believed that tech teams exist to deliver the value demanded by their customers. Great ones however, are able go beyond that and push customer experience — delivering progressively better performance, features, quality and turnaround in the face of problems. There is no substitute for:

  • Finding the right people (problem solvers)
  • Autonomy and responsibility (ownership)
  • Culture of learning, quality and delivery

I also want to point out that Node isn’t always the right solution to every problem. As I mentioned previously, architecture can play a key role in making its use a success in production — and by that I mean wider architecture, not just application architecture.

Being able to use JavaScript throughout the complete front-end stack however, done right, can certainly help to remove some of the siloing I have seen in the past. It also helps us to get going quickly with new ideas, build tools where they don’t exist and increase the level of ownership engineers have over all aspects of quality for the customer experience - with performance being a huge part of that.