Transitioning from jQuery spaghetti to clean React/Redux

The scene upon arrival: two JavaScript files with all functions in global scope... a CSS file with cluttered selectors... overwritten rules everywhere.

With only a couple of months before the release, Sigient was brought in to whip the front end into production shape. Long story short: we made the release date. Since then, it's been two years — the project has evolved, new features were added, and we moved to a unit-tested React/Redux front end that's approaching 85% code coverage. Here's how we did it:

Initial Housekeeping

With the initial front end code for every page all in a couple of files, our initial task was to introduce some sane separation of logic between different components and pages. A rewrite was out of the question due to the project timeline, so we just muscled ahead through the refactor. After separating out and removing the majority of JavaScript from the global scope, we separated the CSS into different files and converted over to SASS. This allowed for nesting of selectors and got rid of a good amount of complexity throughout the styles.

From there, we picked out the more offensive portions of the JavaScript, and completely rewrote them. At this point we brought in a little bit of Backbone.js to bring separation of logic on the front end and introduce templating. Around the same time, we migrated the existing code to use the Grails asset pipeline instead of the resources module, allowing us to get minified assets on production.

This got us to the point where we could have an actual release, while being prepped in the future for refactoring and adding new features. We would have loved to refactor more but with the release date pending, we got the site into a stable spot with some help from the lovely QA team... and released!

Post-release clean up, adding in features, and a responsive MVP

After the release (and a long sigh of relief), we started doing more refactoring in earnest. We introduced Marionette.js into the mix to help with some of our Backbone code and future features. During the next few months, we added a good amount of new features, which really allowed us to refactor good portions of the app.

While adding features like permission checks and more feature flags into the site, we cleaned up duplication in the HTML and added more SASS conversions. The major feature we worked on during this period was working on making the entire site responsive. This allowed us to gut entire portions of the global styles from before the release, and rewrite them in a sane way.

Other new features we added allowed us to make more use of Marionette.js and enabled us to introduce unit testing via Jasmine and Karma. This was actually quite popular with the backend developers because we were able to integrate this with the Grails framework in order to have it work with our continuous integration systems. Though we had testing in place, it was still quite a pain to test components using Backbone and Marionette. So we decided to search for other options that could help. Meanwhile, we updated the front end build system to include Webpack, and Babel, which allowed us to use some really convenient ES6 features such as the spread operator, destructuring, and the new Array helpers.

The Promised Land

We had all heard good things about React, and with the discovery of Redux, we decided to build a couple components to test it out. At first we only rewrote portions of the Billing page and added a new Services page using React, but we were already falling in love with the new technologies. Not only was it easier to build and reuse components and separate business and view logic, but it was also easily testable. By introducing enzyme.js we were able to further test React components and, due to the functional nature of Redux, testing state changes and business logic had never been easier.

One of the pivotal moments of introducing React was demoing the new technologies to TWC and really showing off the features. The engineers at TWC loved the way we could finally fully test our front end components (that had been a major request for quite awhile) and product managers appreciated the re-usability and fast development of components using React.

At this point we had been on the project for around a year and a half and the powers that be decided that it was time for a redesign. This gave us our biggest opportunity since the start of the project to do things right. We took this time to basically start from scratch and rewrite the app as we saw fit. We learned the ins and outs of React/Redux, introduced code coverage, introduced redux-saga for managing side effects, and started writing unit tests in earnest. In fact, we started getting so many unit tests that we had to switch from Karma to ava.js in order to run tests faster.

Now the redesign is complete and the project is moving on to the next stages. The foundation is set for new features and fast future development without too much need to refactor any of the existing codebase.

Wrap up and more reading

Something that should be mentioned is the role that the project owners played in allowing the team time to find these solutions. Once we realized how much work was needed upon reviewing the initial code base, the team had ample opportunities to get workable solutions up and running. While developing new features, we were allowed the leeway and time to refactor and introduce new technology where needed. The process wouldn't have been possible with good project leadership.

A lot of technologies were mentioned in this article. If you'd like to read more about how the technologies work together, I'd recommend following the links to technologies and going through the documentation. There are ample tutorials online for everything related to testing, React, and Redux. If you'd like to see more in depth discussions on any of the technologies used, please feel free to contact us and we'll put together a series!