Devstack download: migrating from JSF to ReactJS

Laptop showing lines of code

At Bandwidth, our UI front end was originally written using JSF (java server faces). This made sense at the time because we had a lot of Java developers and it was easier for them to work with. As time moved on and we expanded our team we got more front-end developers on board. They were pushing for a more modern front end stack that will help improve efficiency for front-end development. That is how we ended up deciding to use ReactJs.

I think one of the trickiest parts of the change was deciding how to go about it. It takes a lot of time and effort to make the change and we had to convince everyone that it would be worth it. Since there was already a movement to revamp our signup process, it seemed like a perfect opportunity to write that using ReactJs and Redux. It also had the plus side of not needing to be authenticated so you really couldn’t pick a better piece to migrate first.

Break it Down

You don’t have to move your entire application to a new UI all at once. Some teams try and do this and then by the time they are finished migrating there is something bigger and better out there. Break down your applications into logical pieces that can be separated (if you allow people to sign up for your service that piece of the application is a perfect place to start). This is a bit trickier for single page applications but can still be done. So once we decided what piece of the application we were ok with transitioning first we had to figure out how to keep the transition as seamless as possible between the existing Java/JSF UI to the Node.js/ReactJS UI. Our solution was using a reverse proxy from apache. This ended up working quite nicely, and since we were already using apache for the Java/JSF UI anyways it really didn’t require a lot of extra setup. These are the few lines of configuration it took to get working:

ProxyPass "/portal" "http://localhost:{{web_node_port}}" retry=5>
ProxyPassReverse /portal http://localhost:{{web_node_port}}

It will take a lot of time and effort if you try and do too many things at once. With a small team you will never get all the time you need to move everything overall in one shot. Break it down and pick the easiest pieces first, that’s what worked for us.

Standing Up a Node.js Server

One of the first things we decided to do was use a Node.js server to serve up the new ReactJS UI. The tooling is much cleaner in Node.js than it is in java.

Here are some of the key libraries that we used to reach efficiency:

  • Babel for our transpiler. This allows us to use some great new ES7 syntax such as async/await, which has increased readability and code organization by a significant amount.
  • Webpack for our module bundler. All of the configurations can be a bit daunting at first. Make sure you read about best practices first and then you’ll realize how great it can be. Live reloading is a must have for front-end development (check out react boilerplate to see how to setup live reloading).
  • Xo for our linter. It is a preset style that uses ESLint. It does allow you to change some things (which we have done) but having that base to start from is great. I also find that their automatic fix feature is great and always results in the code being formatted as expected.
  • Ava for out javascript test runner. Runs your tests in parallel which forces you to write atomic tests, which I believe is a good thing.
  • WebdriverIO for browser testing. This uses selenium and mocha for driving the testing. While having good javascript unit tests are important, it doesn’t replace full end to end browser testing.

Testing

One of the great things about switching to ReactJS/Redux is how the DOM is abstracted away. This makes unit testing your code much easier! You can now create unit tests that test all of your ReactJS javascript code without having to start a browser. JSF mashes together dom elements and Java code and thus unit testing becomes much trickier.

Always strive for 100% test coverage. This can take a bit longer but it gives you a lot greater confidence that your code is going to do what it is supposed to do. Mocking is one of the easiest ways to do this and is a trivial thing in JS. Here is a sample test that we use to check that password validation is working as expected:

import test from 'ava';
import sinon from 'sinon';
import passwordValidation from '../../api/passwordValidation';
const popsicle = require('popsicle');
const RESPONSE = { status: 200, body: { foo: 'bar' } };
const PASSWORD = 'foo';
test.serial('validating a password', async t => {
  const sandbox = sinon.sandbox.create();
  sandbox.stub(popsicle, 'post').returns(RESPONSE);
  const result = await passwordValidation.validate(PASSWORD);
  t.true(popsicle.post.calledOnce);
  t.deepEqual(popsicle.post.firstCall.args[0], {
    url: '/portal/v1/passwordValidation',
    body: {
      password: PASSWORD
    }
  });
  t.is(result, RESPONSE.body);
  sandbox.restore();
});

The above sample stubs out popsicle (which is the library we use to make ajax requests) so it can be tested in isolation. As you can see mocking something out is just a one-liner, then you can do verifications on it later to assure that the correct series of events happened.

100% test coverage is important but also making sure that you are writing tests that actually test the underlying functionality is equally important. You want to make sure that your assertions are as specific as possible, otherwise, potentially bad information may sneak by and your test will pass when it should have failed.

Overall migrating to a new server allowed us to implement much better testing practices and the library itself (ReactJS/Redux) facilitated much easier testing.

JSF Struggles

One of the major design patterns in JSF is that it highly couples server side logic with front end code. For example you could have something like this:

HTML

<div id="main">#{helloWorld.message}</div>

HelloWorld.java

@ManagedBean(name = "helloWorld", eager = true)
@RequestScoped
public class HelloWorld {
  private String message;
  public HelloWorld() {
    setMessage("HelloWorld started!");
  }
  public String getMessage() {
    return message;
  }
  public void setMessage(String message) {
    this.message = message;
  }
}

Where in order to get that message text updated it has to make another round trip to the server, sometimes causing a page refresh to get the component to pull in the new value. This can really be a pain to manage state in a single page application. Especially when it could be controlled by another front-end component and needs to change on the fly. ReactJS abstracts how it gets the data away from how it presents the data. Something similar in ReactJS might look something like this:

var message = 'HelloWorld started!';
var HelloWorld = React.createClass({
  render: function() {
    return (
        {this.props.helloWorld}
    );
  }
});
ReactDOM.render(
  document.getElementById('main')
);

All you have to do to change the message display is update the javascript variable, message. You could update it on a periodic asynchronous AJAX request, when the user fills out a text field on a different view, or any assortment of other methods. When you want to force JSF to update the display based on the backing bean you may end up writing something like what you see below which just doesn’t feel as intuitive and is something you do in your java code, not your front end JS code.

FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds().add("foo:bar");

One thing that is easier to do using JSF is to directly manipulate the database via actions. For example, when a user clicks a button, it saves information directly to the DB using the underlying java functions. THIS IS BAD!! This design is not modular at all and when things start changing rapidly it’s going to be a pain to manage. This was one thing that worked out great when we created the Node.js server and started using ReactJS. Since we decided that the Node.js server would not be able to connect to the database at all, we had to create API’s on the java server whenever we wanted to manipulate data. This design is much more modular, allows greater reuse, and is much easier to integrate with other services. While you might be thinking, “You could have just used API’s with JSF as well”, this is true BUT it requires better code practices and a different design than what JSF seems to be made for, whereas ReactJS seems to support that paradigm natively.

Conclusion

All your developers will enjoy the switch to ReactJS. Your java developers will be happy because they no longer have to worry about writing the front end code. Your front end developers will be happy because they won’t be coming along and cleaning up the code that your java developers wrote.

TL;DR

  • Switching from JSF to ReactJS/Redux greatly improved efficiency
  • You don’t need to move your entire app over all at once, break it down and do it in pieces
  • There are a plethora of great libraries for ReactJS/Redux ecosystem
  • Babel, Webpack, Xo, Ava, WebdriverIO. Check them out if you haven’t yet.
  • State management is much easier in ReactJS than JSF
  • Testing ReactJS code is much more streamlined compared to JSF