Reactive RadPad

RadPad made the switch to Facebook-created React.js framework and Flux architecture for our experience of “Finding a Pad”. At RadPad, we are always trying to improve the process of finding a home to rent and React/Flux aligned with our main technical goals. It was a 3 month journey to transition our Angular framework and add additional features in the process. In this article I hope to enlighten those exploring the differences between the two frameworks and convince you why in some cases, Angular (1.X) doesn’t cut the mustard.

Origins  

RadPad’s original web product was well suited for what’s colloquially known as a thick Front End framework. The reasoning is simple in principle; if the browser loads an entire application on a first page load, then there is no need to ever refresh the page. Instead, elements will get dynamically inserted based on API responses or alternatively when we change routes and swap templates. In this situation we don’t have huge concerns about the weight (or thickness) of the application. Sure, there is some pain for our users on the initial page load, but that quickly dissipates into joy when the smooth transitions to new content feels seamless. This single page application architecture, or SPA, has been a recent pillar of modern web development and is something AngularJS does exceptionally well.

Limitations in the Wild  

SPA architecture is a great ideal for user experience, but in practice there are barriers to it being awesome. One of the biggest issues that SPAs still haven’t adequately addressed is Search Engine Optimization (SEO). SEO for these types of sites was horrendous before 2014(1). Previously, Google crawlers were not able to execute JavaScript on a page to do web crawling. This meant that Angular SPAs ironically would not be friendly to the same Google behemoth that created the framework. To become SEO friendly, we were forced to have our Rails backend render the markup per page and have our Angular JavaScript attach itself to whatever was present. This choice unfortunately meant that Angular would not handle the routing and thus no longer technically be a SPA! The delightful sense of smoothness that comes with routing changes is a big loss. The biggest disservice to the end user is that they have to endure the time it takes for Angular to read in and attach itself to the markup every page load. It was the reason for our front end page performance woes and it made our loving customers perceive RadPad to be slow.

The difficulty in scaling Angular is another issue that plagued the old RadPad. Angular CAN be scaled with a lot of resources. You can see examples of highly trafficked sites like vevo.com or msnbc.com scaling it beautifully and effectively. These sites show how powerful Angular can be, but if Spiderman has taught us anything its that great power comes with great responsibility. The power is that Angular permits the developer many ways to accomplish goals. This comes with the extra responsibility of clearly defining the purview of Angular components. Angular has documentation that hints at how you should modularize components. The official documentation examples allow a developer to gradually, through osmosis, understand how components are intended to be used. When you hear developers speak about organizing code you might hear language like “that doesn’t feel angular-y” or “that doesn’t seem like the Angular way to do things.” This intuition is something that is picked up over time, but is not something made explicit by the Angular framework. The hazy overlap of what different components should do causes the burden of component architecture to be placed on the developer. Startups don’t have the bandwidth to constantly weigh these decisions. What happened over time for RadPad is the components’ logic were used in a variety of ways. Angular watchers were scattered in different components, controllers and directives weren’t clearly separated, and the scope of which directive controls which functionality became blurred. It caused the code to become difficult to reason about and challenging to modify. While the permissiveness of Angular is great for making things quickly, it eventually becomes a flaw as your application grows and evolves.

New Framework Decisions  

Revitalizing the user interface of the Find a Pad experience was a great opportunity to also address new user behaviors and refine our technical goals. We wanted to be friendlier to opening tabs to view listings, improve page speed performance, and increase development speed. To give the reader some perspective, in the past we opened single pads dynamically in modals. It caused the information to feel cramped and inaccessible, but most importantly, didn’t really allow users to compare different pads. This behavior turns out to be essential for empowering people to make a renting decision. Opening a single pad in a new tab window would allow our customers the ability to compare the benefits of different pads and allows RadPad the extra real estate to tell the narrative of moving to a new home. Our main goals suggested React with Flux was the best way to approach building the site. It could give us the ability to lighten each perceived page load time while also mitigating the complexity of our application architecture. It had the added benefit of allowing future optimizations by rendering React server side to improve SEO and page speed. We don’t want to make it seem like this was an easy decision to make. It meant a majority of the code base would have to be rewritten and that many programming perks Angular give you for free could not be directly translated. The team had a sum total of 3 weeks of past React experience largely dedicated to watching Pete Hunt (@floydophone) YouTube videos about React.

The Pains, The Joys  

We believe React is clearly the better framework for RadPad’s “Find A Pad” goals, but the development process of translating an Angular site to React wasn’t as clear cut. Digging into old code meant we were effectively relearning how components did things on a case by case basis. Since Angular is somewhat of an MVC-ish structure we couldn’t directly translate the components to Flux which has a unidirectional flow of data. If we wanted to abide by Flux’s clear architectural pattern, we had to use Angular merely as a blueprint and extract pieces of code when appropriate. It wasn’t fun because a majority of time we were refactoring legacy Angular code while simultaneously processing how it fits into a new Flux paradigm. Often times we would completely rebuild a feature because this process was too convoluted to reason about.

During this translation we had a renewed appreciation for how Angular structures asynchronous API calls. Anything REST heavy Angular is a pro at tackling. Using ngResource or http service is wonderfully simple. Deferred promises created in a factory are then immediately passed back to the original component that requested them. This is pleasant because you handle the different responses within the domain of the call. It also allows for tidy modularization because the component can easily identify the current state of the API request and response of the promise. We wrestled with a comparable way to do this with the Flux architecture. After a lot of research we determined that there was no agreed upon best practice for how to handle this. Anything resembling Angular’s promised-based system led to smelly code. We ended up using what we termed a “resource component,” a modified immutable store, that would handle any API actions. It’s callback would be a “setter” action creator that changes an application state. It feels somewhat impure to do it this way, but still follows a unidirectional data flow. This topic still needs some more exploration.

There was also some initial pains in the verbosity of Flux. For example, it was taking twenty lines of code for a click on a button to send an action through the application, change the application state, and reflect the state change in the UI. It’s a long-winded process that would make some jQuery enthusiasts smug about the fact it could take them only one line of code. Over time, however, the irritation of more code relents to the beauty of interface composability. You structure the needs of the components only once. The components rely on pieces of information called properties to be passed to them. All they care about is the properties they receive and then handle how to interpret this data within the interface. Setting up one action creator change and one component with expected properties lays the groundwork for future reduced code. The next time you want to change the user interface you can piggy back on the previous action pipeline, having the state change already reflected within the component. This arrangement turns out to be an incredibly easy way for developers to build a mental model of what is happening in the application. Although Flux is more forcefully restrictive in how data is moved throughout the application, this becomes a godsend as things get complex because you intuitively follow the data flow. What you are trading for with React/Flux is convenience for conceptual understanding that can be shared across multiple developers.

Conclusion  

With the influx of JavaScript frameworks over the past few years, it has been increasingly difficult to choose the best tool for a website’s needs. RadPad’s goals were more practically aligned with the benefits of the React framework, but there were huge tradeoffs immediately felt during the switch. The pain of translating an Angular site that was feature-rich and structured very differently from a React/Flux site was a reoccurring source of discomfort. We didn’t fully anticipate the difficulty of this. As a result, we often had to balance code translation with a complete functional rewrite which risked overlooking the smaller features and functionality. This was a constant source of anxiety. Overall, this pain was worth enduring for the ultimate goal of a better user experience and being more agile with future features. The fact is that React/Flux requires less reasoning and cleverness to structure the code. Familiarity with how a code base works should never be a substite for clarity on how a system works. This intuition that comes inherently with React/Flux allows the developer more leverage in building complex applications.

Angular and React are tools that excel at different things. The decision to choose one over the other shouldn’t be based on what’s in vogue, but should be analyzed based on what aligns with the technical goals you have. One of the great things about RadPad’s startup culture is we are able to pursue different technologies and ideas for the ultimate goal of improving our customer’s experience. If you want to feel this excitement for yourself, checkout some pads at www.onradpad.com. Also, we are always on the lookout for people that share our passion. If this article has piqued your curiosity in any way and sounds like something you would want to involve yourself in— check out our jobs board a www.onradpad.com/jobs.
Footnotes
(1) Google started to crawl and interpret JavaScript in 2014. This makes sites that rely on JavaScript to show content indexable and better for SEO, but there is still a ways to go for this to be comparable to straight rendered markup. Also, it’s good to be reminded from time to time that people still use Bing. There is discussion about the topic of “precomposing” a single page application that might be more effective at solving this. It is worth exploring, but outside the scope of this article.
http://googlewebmastercentral.blogspot.com/2014/05/understanding-web-pages-better.html
http://www.analog-ni.co/precomposing-a-spa-may-become-the-holy-grail-to-seo