 I'm Joe. I'm super excited to be here. This is my first ever RailsConf. So that's great. And I've come all the way from Melbourne in Australia. I wanted to tell you a story today, and the story starts in Melbourne. It starts with a group of four engineers. They started up a company called Culture Amp, and it's a company that I work for now. They built an online application using Ruby on Rails to run employee engagement surveys, and it provided real-time analysis of the results. Now, today, we have around 50 people working in our product team. We have 10 development teams working on the product, and it's built with a whole bunch of technologies. We still have that Ruby on Rails monolith. We also have some elms, some elixir, and a whole heap of JavaScript. Back at the beginning, though, it was a whole other world. And I want to set the scene a little bit so that this story makes sense. So I'm going to talk about the product and the market where we started out. I'm going to talk about the front-end development scene and what was going on back then. I'm going to talk about the evolution that happened to us, that happened in the front-end development scene, sorry, and then the need to change where we ended up. So the product that we had was offering analysis of survey responses, and it had two main areas of competition. The first one was consultants. They would run a survey, they would go away, and spend a long time producing results in the form of PowerPoint documents or keynotes. And they looked beautiful, but they took a very long time. And then the other alternative was things like Survey Monkey or Google Forms, and these would give you plenty of flexibility and real-time results, but it was very difficult to do anything with the data. You had to do a lot of the analysis yourself. So in this market, it wasn't very difficult for us to create a pretty ground break in front-end. We put in a bit of real-time analysis and some basic interactivity so that you could drill down into the results, and that was enough to beat off these generic tools in the consultants' PowerPoints. Now, back then, the popular tools for front-end development were jQuery and Bootstrap. Now, it was 2011. We weren't talking about the dark ages here, so you could kind of be forgiven for thinking, well, why didn't they use something better? I mean, backbone at that point was pretty mainstream. Angular was gaining popularity. But when you think about jQuery, it was a game changer when it was first introduced. Its motto was jQuery is designed to change the way that you write JavaScript. It was designed to get rid of the JavaScript that people were writing then where they were putting it in line inside their HTML, so they gave you a way to move that JavaScript into separate files. And its current strap line now is right less, do more. It's really unobtrusive. It's really easy to introduce it into Rails. In fact, it was included by default with Rails 3.1, which is where we started. It just makes things really easy. And if you look at Bootstrap, at this time, Twitter had just released their version 2 of Bootstrap. It was a whole library of layout and grid components, so suddenly column layouts were available to the masses. It was easy to add. We could drop it in from the CDN, or we could just put the file into the vendor folder in Rails. And like many startups, we really just wanted to have a reasonably nice UI, some smooth interactions for our users, and we wanted to get something to mark it quickly. We didn't want to waste a lot of time playing around with JavaScript and CSS. These were back-end engineers primarily. So what more do you want than these things that make life easy? So years passed by. We added a lot of new features. We added a lot of back-end features, permissions, data analysis, these kind of tools, and the front-end really... It was something of a means to an end. It didn't get a lot of love. And Rails also makes it very easy to manipulate the vendor files, which is one of those things where, just because you can does not mean that you should, because once you've changed one or two, try and upgrade as a nightmare. So we just had a load of spaghetti. And meanwhile, the JavaScript world was moving on. Some of the early benefits of jQuery, one of the things it had done really well was standardize across browsers. So if you wanted something that behaved the same in Internet Explorer as it did in, I was going to say Netscape there, wow, how old is that? And Chrome and Firefox and so on, then it would give you that. It would let you have those behaviors. But as a result, the library had become really bloated because we're really standardizing. So we didn't need this bloat anymore. Users, meanwhile, were starting to use mobile and surf the web on their mobile devices, which meant they were demanding faster downloads. We had to build smaller JavaScript libraries that didn't more. So JavaScript in this environment started to really become a first-class language. We had to think about how we structured it. We had to start adding in tests. We had frameworks like Jasmine and QUnit that were becoming mainstream. And meanwhile, we were back in this world where we had all this spaghetti code and when we tried to fix a bug, another one popped up somewhere else. I saw this video when I was preparing my presentation. I thought, this is exactly what it feels like when you're trying to fix one thing and it just bursts somewhere else. And this is how it ends. So we needed a change. Now, what was happening at the time, React was emerging, so I'm going to talk a little bit about that. I want to talk about why we decided to go with React, how we evolved our Asset Pipeline to use it, and how we started to build the first components. Now, React was open-sourced in 2013. And at first glance, it really looks like another shiny JavaScript framework, right? There was a slide in the Elm Talk earlier with a lot of different JavaScript frameworks. I don't know if some of you saw that, but people who are starting to learn JavaScript now are really overwhelmed by the number of choices that there are. So React is actually a little bit different. One of the things that really makes it stand out is the idea of one-way data flow. Properties in React only flow down from the initial state through the components. And each individual component encapsulates its own props. It can't modify those props. It can't modify the global state. The only way it can do that is through callbacks. React components are a representation of the UI given the specific state that it's in right now. So we don't, within a React component, try and change the DOM the way jQuery does. Instead, it just renders a representation of the UI. And it uses this language called JSX. When you first come to React, it really kind of makes you want to vomit a little bit because you're now mixing HTML in your JavaScript components and you've just been learning that that's really bad. You should have them in templates, have them separate. But over time, you start to kind of realise that this is actually a much nicer way of working. So JSX looks a bit like this. It's an XML-like syntax, and it looks like HTML. It supports HTML-type components as well as custom component tags. JSX allows us to pass properties down the component tree into the other React components. Now React is also different because every time the state changes, every time we change the data that we're using to display the UI on the page, it re-renders the components. It does this by maintaining a copy and memory of the DOM, and it calls this its virtual DOM. So every time the state changes, it can compare the current version of the DOM with the previous version, and so it knows which of the components need to be re-rendered, and then it will tell them to re-render themselves based on the new state. So by avoiding rendering the whole DOM, it means that users don't necessarily have to re-scroll all the time and it maintains the position of your cursor and so on. It also is a much more performant. If you compare this to jQuery, it turns out that trying to manipulate individual elements in the DOM is much slower than if you just redraw the thing. So if you imagine implementing a to-do list, you have a to-do, the user enters some text, and then hits a button to add a new one. When you hit the button, you would call a callback, which would update the overall state of the page and add the new to-do to it, and React would then know that that to-do list needs to re-render itself and include that new data. One of the other benefits of React is that it's backed by Facebook. It was open-sourced by Facebook, so it's got a big company backing it, and investing in it. Unlike some of the other open-sourced tools, all of which are amazing and built by amazing community members, but having a big company behind it makes it a little bit more reliable and it's being maintained over the longer term. One other thing I meant to mention is very easy to integrate one piece of React into the code base. So with things like Angular, you have to migrate an entire page over. But with React, what we were able to do was pick one small piece and then just put that component on the page alongside all of the other spaghetti JavaScript and leave that alone so that we could just have this one new component. So when we thought about what JavaScript framework we should use, I know DHH talked yesterday about how really we should have gone and tried out seven and done all our due diligence and really done the proper technical investigation, but surprise, surprise we did not, but we did consider a few factors. First of all, our app is a B2B app. The users that we have are primarily people working in HR, and they're usually accessing the app on a desktop computer. So we were able... We didn't have to worry about things like rendering on mobile phones, rendering on small screens. We could be quite targeted in the browsers that we had to build for. And we could restrict our support. So we actually support IE10, but we don't support anything less than that. And we just support the latest versions of the other browsers. So we were pretty lucky in that we didn't have to worry about these older browsers. Another consideration was that we had hired somebody who was a React expert. So we had somebody in the team that was involved with this transition. And I think this is a really important aspect of the decision for us. We also didn't have to worry about SEO. React is known for being able to do isometric JavaScript, so server-side rendering and so on. But for us, we didn't... That wasn't something we needed to do. So given SEO wasn't a concern, it's actually quite difficult in Rails as well to get React to work that way. I don't know anyone who's done it. So not having to worry about that isn't fit all teams. I don't want to try and promote the idea that React is the framework you should all be using. It was right for us at the time. Now, before we jumped into building React components, we needed to have a few things in place. And JavaScript had really moved on from the moldy old code we were trying to work with. We weren't even using any ES5 features, let alone ES6, but out in the big wide world, there were all these amazing things that had been introduced with ES6. It was a really significant update, and we needed more first-class language to establishing it. So it fixed some issues, so block-scoping and immutable constants were introduced with ES6. We also had some syntactic sugar, so arrow functions were introduced, we had string interpolation, and we had the spread operator, all of which made our lives as JavaScript developers much easier. ES6 introduced classes which some people love, some people hate, and it also introduced promises. But now it was part of the core JavaScript code. Although ES6 would be a presentation in itself, if not more, there's a really great repo by Luke Hoban that you should check out if you want to see more information on the features. Now, not all browsers support ES6 features, so we need to choose a transpiler, and Babel is one of the most popular ones. We had to figure out how to get it to run in the asset pipeline, and what the transpiler would do was to use appropriate polyfills when we started using ES6 features, you can tell it which browsers you want to target, and it would introduce the polyfills when they were needed, and backport the new ES6 styles, like the arrow functions, to the older style JavaScript. Babel supports enabling different feature sets, so you can tell it what you want to use and what browsers you want to target. Now, the default Rails asset pipeline uses sprockets. All of your JavaScript, your images, your CSS is processed by sprockets before it gets onto the client. And sprockets uses require trees, so if you've written JavaScript files where you've required another file in it, sprockets goes and gets the content from that other file, puts it in as a bundle, and then that's the one that gets served to the client in production. When it creates these files when you run your asset compilation, it puts a hash of the file contents into the file name. So every time you update and you re-release a new version, it's making sure that because the file name's changed, it's preventing the browser from caching into the file name. Now, sprockets doesn't support transpilers like Babel. There are gems now to do this. It was going back a while when we were trying to introduce it. And so we looked at some of the tools that were being used in the JavaScript world, so Webpack and Browserify were the two most popular. And both of these are written in JavaScript unlike sprockets, which is obviously written in Ruby. Now, we're in a JavaScript environment, process in JavaScript code, to integrate Webpack into the Rails Asset Pipeline looked a bit like this. We had a gem that would run, we needed to run a node process in order to run Webpack, it needed to run inside node. So we wrote a gem that would run a node satellite process alongside the Rails server and the gem was called Ruby Node Task. We then had a separate gem called Webpack Rails and what that would do would run a pre-build process within the node process so that we could incorporate these ES6 features into ES6 templates. It would do all the transpiling within that step. Once Webpack had finished its processing then sprockets would do its processing and bundle these new Webpack bundled files in with the old JavaScript and then output them as normal. Now this was pretty gnarly. I'm not necessarily recommending this as a good solution but it worked at the time as a first step. It got us to the point where we could actually start using React. But it was pretty soon we found we needed to update it. One of the biggest problems we had was that source maps which were supported by Webpack were not supported by sprockets. So we weren't able to debug. When we saw an error we would just get a long back trace and we couldn't figure out exactly where in our original files it was coming from. So instead, what we started to do was we would separate I've got it on the right slide. We tweaked the setup. The files that were processed and bundled by Webpack were then no longer being included in these legacy files that were being bundled by sprockets. So they were treated as a completely separate asset and the impact was then we had two tags in the Hamel. It wasn't too much of a big deal. We tried to avoid that but ultimately this meant we could have source maps we could have hot module reloading in development environments and so that made it much easier. Now we needed a way to introduce our React components onto the page and we were using Hamel for our template language within Rails. So we introduced this method into that we could use in our Hamel files. It's a top level it goes, sorry, it's a method that will add a top level component into the page and passes state from the Ruby side so we wanted to be able to pass props as a Ruby hash into this component. So we just output it with content tag it's output as a div and we used the data attributes we put the component name inside one called data react component and we put the hash inside React attributes. We then had a JavaScript method that would register all of the components we intended to use as top level components in the page this way and so we just registered them as the pages were loaded and this created a map with the component name and the actual component itself and what it meant was that we could then mount them on the page load and the mount components method looks at all the HTML in the page and it picks up any nodes in the HTML that have this data react component attribute it can then pick up the component name and the component props which have been loaded into these data attributes and these get passed into the mount component method so now it knows what the component is it knows what its props are and it knows the HTML node where we want it to appear on the page and we pass all of that to react on render and that does all the hard work of outputting it there for us so after the page is loaded then our react code loads hay presto we had react working in Rails so then we wanted to evolve a little bit move on and do some more interesting stuff with it we added some jest tests we added CSS modules in the end we lost sprockets we introduced react route and redux for some more complex code we introduced animations and we also introduced a mutable state so when we first started using jest we wanted to have with this beautiful clean code that we'd introduced we really wanted to have unit tests from the ground up jest was created to work with react again it's been created by Facebook it's quite different to other frameworks like jasmine and qunit where two we'd been using before when we first introduced it it was designed to mock everything by default and this is really weird it's a really kind of difficult learning curve and a difficult mindset change when you first start using a framework where everything is mocked ultimately I think we got to the point where we actually found that that made us write better code because you could only test the thing that was actually the thing you were trying to test the one unit so the test became much cleaner and just testing one individual thing they have actually changed it now so if you install jest now the default is that it doesn't mock everything they've written a blog post to explain their reasoning but largely it's because so many people just found it such a mind shift and so different and difficult to get to grips with jest has also introduced oh sorry I want to talk about shallow rendering and this was how we were able to test the output of React so given that it's rendering components we had to figure out how we can actually test the output because usually it would render into the DOM it would render into the browser DOM and shallow rendering is part of the React test utilities library what this does is rather than actually rendering the component into the browser DOM it renders it as a kind of an object so it just renders one level and you can then see you can test that the outputs of that rendering are what you would expect and we used it in combination with a package called React Shallow Test Utils and what that allowed us to do was to pick up nodes in the output and test whether the props were correct and whether they were appearing as we'd expected and so this is what you would get from this Shallow Test Utils it would go and find a node in the output and it would have something like this which is a normal JavaScript object if you output it to the console so it's quite easy to just inspect all the different props in it now as I was about to say a minute ago I wanted to briefly introduce snapshot testing and so what snapshot testing allows you to do is that you can save the output of your component and it saves it into a file so that every time you're updating your component you can just compare across versions you can decide if there's a change in the output is that something I meant to have there or is it a bug that I've now introduced what we've done with our components over time we've abstracted a lot of the logic into very small files very small JavaScript components so whether if branches or case statements or actual business logic in the components we try and pull those out so we try and adhere to the single responsibility principle and just have a lot of these very small modules just doing one thing well and this has made testing of the logic of these much much more straightforward and if the component is just rendering a set of props there's really very little value in creating a lot of unit tests around it so the test can be focused just on the modules that need it now we also introduced CSS modules if this is something you haven't come across before it's a smart implementation of names faced class selectors for CSS so rather than having a CSS class that's just global across your application you can have classes within a CSS module that only apply to the one module where it's included and it was created by two prominent Australian front-end developers Glenn Madden and Mark Dalglish so for us we were able to have for each of our JavaScript files a corresponding SAS file so each JavaScript component had ownership over its own CSS styles and it let us avoid the hell of CSS class name clashes when we were using these components in various places on the site now CSS modules uses a tool called post-CSS and what that allows us to do is to process it with our JavaScript compilers with JavaScript plugins so we could use webpack to process the CSS modules and output them as JavaScript fo you can just use them like a JavaScript object the next thing that we wanted to do was to try and get rid of sprockets we were really starting to feel the pain of working with sprockets together with webpack in our development environment especially we wanted originally to try and do things the rails way but we wanted to kind of avoid a change that felt too big at the time but people were getting used to webpack now and we were also finding that if it got stuck compiling something we had to restart the whole rails server because of this node satellite process that we had introduced and the code base was growing in complexity so this was happening more and more often it was a real pain and we still couldn't support source maps in production because ultimately the code was still getting compiled by sprockets so the solution was to entirely replace sprockets with webpack the one problem that we had left to resolve here was that sprockets does this as I mentioned it renames the files with this hash file name so we had to find a way of getting setting webpack up to do that same thing so that our production files weren't being cached by the browsers and the way sprockets does this is that it maintains a manifest file and it maps the original name of the file that's going to be compiled against the name with the hash in it and then when you load your files in development it's going to get them from the local machine, when you load them in production it's going to go and get the file name with the hash so we used an npm package called webpack manifest plugin I think and that does the job of creating this manifest file for webpack and having the same functionalities as sprockets was doing so that then we didn't need sprockets anymore and webpack serve all of our files in production then we wanted to add single page transitions we had all this fancy code we had all these nice new components in React we wanted to use them to create a better user experience and this meant that we had to introduce Redux we needed something more complicated to manage the overall state so at a high level we also introduced React Router at a high level Redux is a state management library and it was heavily influenced by Flux and by Elm in its design so the state of the app is stored in a single global state a single global store and the only way that you can make changes to this store from a component is by emitting actions and actions will contain a payload so to go back to the to-do list example if we had a version for a to-do it would contain the details of the to-do this in turn called a method in the reducer which knows how to produce an updated version of the current state we don't change the state we don't actually edit the object itself we create a whole new version and that gets sent back to the store this then updates all the components React looks at its virtual DOM decides which ones need to change and passes the updated state down to them and that is a JavaScript routing library which allows the URL to stay in sync with what's on the page there's a newer version of it version 4 and it's very very different to the point where there's a lot of stories on the internet about people who've tried to upgrade it matches the components in the URL to the components on the page so that they can decide based on the URL components which pieces to display we're still using the old version we haven't managed to upgrade yet and they are maintaining the old version indefinitely although I think if you're starting a new application now it's probably better to go with the new one now in our world we wanted to implement actions that could be called in response to a user interaction like a click so you click a link to view data for a specific question and you can have actions that trigger actions so the first thing that we did was to trigger an action to say the URL has changed this triggers a second action which checks if you require new data to be loaded which if you're going to view a different question or a different page nine times out of ten you do unless it's the current one so this would change the URL and this would trigger a new action which would go and trigger an Ajax request it uses fetch which returns a promise and then when the Ajax request returns it resolves the promise this triggers a new action again which updates the data or tells us that the data has been updated and finally this goes to the reducer which processes the data the components are then re-rendered with the new version of the data and this is a very simplified overview of how React Router and Redux are working in our application I really recommend if it's something you want to learn more about there's some awesome videos on Egghead and a lot of them are free and they have a couple of series on the React on Redux and on React Router so that's the best place to go we also introduced some animation on our single page transitions we needed some kind of feedback in the UI to show the user that the page was changing the usual way we do this is with animations and so we found this library called React Motion and it did things like shifting the bars from the old value to the new value when the data was changing it's an MPM package it supports a thing called springs which is a way of animating things in the UI but unlike timed animations one of the nice things about springs is that it's interuptible so you get these nice realistic animation curves but if you have to stop halfway through it can then jump from wherever it is to the next place which is better than the usual timed animations that you would have in CSS some issues that we ran into were when we tried to render PDFs we had to make sure that the animations were not running then and in our tests as well we had to find ways around it because we didn't want to check the value of the components sorry, Redux is based on the principle of a mutable state and we wanted to try and use that more across our application so this is one of the libraries that we introduced very early on, Immutable.js which has helped us to think in terms of immutable data and in terms of not changing something in place but returning a new version of it so it provides a number of different objects that we used map and list were the ones we used the most and in normal JavaScript if you edit an object or an array it just edits the object in place but what Immutable.js does is that it will return you a new collection with the changes that you want without changing that original object so it's protecting you against a lot of subtle bugs that can come up in your JavaScript files and it's also highly optimised if you try to implement this on your own you probably end up in a state where you're running out of memory but it uses a lot of shared structures underneath so it's optimised for performance and you can use this a lot more safely in your code and this is an example of what it would look like if you changed a map an immutable map you can see that the original map hasn't changed we also used record types from Immutable.js and we used these to define specific types or data structures that we could pass between our components now there's a move towards more strict type checking in the JavaScript community in general and newer front-end languages like Elm already have static types built in React allows us to define types for each of our components and so what we were able to do was define types of these records that would have specific properties that we knew should be present and we created this strong record class as a wrapper around the Immutable.js record so that it would present us more warnings and we could really check does it have the properties does it not have any that it shouldn't have and then when you pass the prop types to React we could do more checking to make sure whether something was required or not and what props it is expected to have and in a development environment it would give you warnings in the browser so you could see if you weren't passing the right things so again this allows us to identify subtle bugs much more easily so what have we learned on this journey we've learned a lot for a start it's helped us to introduce a lot of new patterns and better ways of approaching and structuring our code React has inspired from functional programming principles so it's something we'll also see happening in Wales world there's more functional programming ideas coming into that so we had a bit of a head start there and it really makes you think slightly differently about how you structure your code in any language for example state never being mutated creating a new object to store in state and passing things through functions to get a new value back instead of modifying them and we've found that we end up creating cleaner code it's easier to test because you're just testing inputs and outputs instead of having to mock behaviours so does this story have a happy ever after? Well legacy JavaScript is still a thing we haven't got rid of it yet we now have a massive library of React components and we haven't given an awful lot of thought so far to the re-usability of those components so that's starting to be an issue we have a number of different components that do very similar things and we do still have a lack of overall consistency in our CSS where we're using CSS modules it's awesome but we also have a lot of global styles still and I never knew there were so many different ways you could make a button appear but I think we've got about 15 so this story has an epilogue we are moving towards more of a shared component library something that a lot of companies are now doing is implementing a living style guide so people like Envato, Lonely Planet, Airbnb and Atlassian are all companies that have published their style guides in Lonely Planet's case they have a gem that they use and Atlassian UI which is a Java package that people can actually use to use their components and styles we're also experimenting with alternatives like Elm we've got about a quarter of our application now which has an Elm UI integrated into the React one and we are starting up a team that's going to own this front-end experience and try and replace all of those 15 different buttons with at least one or maybe two and I think since we started our journey we've really learned a lot about what the system code has moved on and the world around us continues to move on and evolve so it's still not perfect the biggest difference though is that we now treat our code much more as a first-class citizen on the front-end not just the spaghetti mess means to an end that it was before and we hear back from our users that they can really tell the difference because of that so I guess whatever you're doing wherever in your journey you are whatever library you choose to use I hope you may have got something out of our perspective for Wales. Thank you.