Pete Hunt: React: Rethinking best practices -- JSConf EU

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
you you hey I'm Pete I'm going to talk to you about a library for creating user interfaces that we call react and we open source this at Jas conf us a couple months ago and we got some kind of sarcastic responses on Twitter a little bit of snickering that kind of thing we weren't really communicating what we were doing so I'd like to talk to you today about the design decisions around react what we're doing differently than other frameworks and kind of the implementation that lets us make these decisions and make it really fast so it's not a tutorial it's not an introduction you're not going to learn how to build react acts today but you might be able to use some of the stuff that we've discovered in your own work so I ask that you please just give it five minutes some of the stuff that I'm going to say flies in the face of some established best practices but we found that there are certain best practices that deserve to be challenged so meet react it's a library for creating user interfaces specifically we render your UI and we respond to events a lot of people think of us as the V and MVC maybe we're the controller to really depends on how you use it but we try to play nicely with your stack whatever it may be so for example we're not opinionated about how you fetch data people use us with you know backbone or whatever you use for managing your data client-side so I'm going to talk to you about kind of the initial principles behind react which is all about building components then I'm going to talk about the design decisions that we made that make react a little bit different from other frameworks and finally I'm going to talk about the implementation and how we're able to make our implementation of this framework really really fast so I'm going to start with building components not templates if you want to think about this cynically we're talking about mixing markup and display logic and a lot of people completely disagree with that so this is a much sure if you can read it but this is kind of what react code looks like this is from our to-do list example on the home page react is org it's all about building reusable components that know how to render themselves into the DOM um but like I said I'm not going to go through this line by line because this is not a tutorial this is about design decisions but we all like separation of concerns right this has kind of been a fundamental tenet of building apps on the web ever since like the PHP pocalypse of 1999 where we were putting my sequel fetch row in the middle of our table rendering code but let's talk about what separation of concerns actually means we're talking about reducing coupling and increasing cohesion coupling and cohesion they're very they're two very important principles of software engineering here's the definition I pulled off of Wikipedia about coupling and it's the degree to which program modules rely on each of the other modules now that's kind of like a fluffy definition but more concretely if you want to implement a feature or fix a bug and you make the change to one module be it like a class common j/s module function a packet of functionality how often do you have to go to other parts of your code base and make changes in order for it to work and these sorts of cascading changes are symptoms of coupling and that's what makes software hard to maintain cohesion is somewhat related as well and that's the degree to which elements of a module belong together so if you've heard of the single responsibility principle basically grouping related functionality into modules and not putting extra crap in there you know the kind of the witness' test is like does this class make sense or does this function make sense or is it doing a lot of stuff and can you refactor it into other pieces so I think that templates encourage a poor separation of concerns and it's not just templates specifically it's anything that tries to augment the Dom or HTML with some sort of functionality to make it better at building apps so I think angular directives also fall into this and it's not just client-side either it's some server-side systems as well like Jinja and kind of traditional templating solutions now how can I possibly make the argument that this is a bad separation of concerns right you've got your display plate code in one place like your template and you have other code in other places that does that do different things now normally your controller and your they are tied together with something called a view model and some some frameworks actually the controller is almost the view model so you pull some data out of your database or with like an AJAX call or something and you construct a data structure that looks something like this so if I wanted to show a product grid with the example that everyone uses which is alternating row colors in some templating systems you have to add a table row color attribute to your view model and we say that that's fine because it's a view model it's not the model and it's not the view it's in view model now the problem is this tightly couples your controller to your template so if I want to make a change to how I render those row colors while it feels like I'm making it change the template there's an implicit dependency between the template and the controller because they both agreed on that template row color attribute in my example so you actually have to make cascading changes throughout your modules so it's not real decoupling and I think that the display mod the display logic and markup are inevitably tightly coupled so if you're building apps on the web that manipulate the Dom you have to figure out where in the Dom you're going to change and what parts need to be updated and what nodes are receiving events but the good news is is that this is highly cohesive logic so the the JavaScript code that that drives your UI and the markup that displays it to the user are both doing basically the same thing they're handling user events and the rendering data to the to the user so I would like to argue that templates separate technologies and not concerns it's not a real separation of concerns the separation of technologies you're using to implement the same concern and unfortunately the way that we're doing this today they tend to be deliberately underpowered so I'm going to show you a couple of examples of what I mean by being underpowered and the first technology I'm going to pick on is handlebars sorry Tom so first of all handlebars is an excellent implementation of templating it's really fast it's really easy to understand and it drops right into a lot of different frameworks but it's an implementation of kind of a classical way you build templates so they actions you have available are fairly primitive so the the easiest one to think of is partials if you want to reuse a template you tend to use partials and a partial basically takes one template and embeds it in another template now that embedding puts all of the puts that template in the parents scope so if you want to make a change to a child template or a partial you need to track down every single call site that uses that template and make sure that you don't break anything because there isn't a strict contract between the partial and the template that includes it this is going to be a recurring theme of my talk another example of an underpowered technology and here is each it's like oh it's like doing functional programming but you only have map you don't have filter you don't have reduce it's it's hard to do branching and frameworks have solved some of these problems that I've mentioned but they're kind of hacking around the idea that we want to pull certain parts of our display logic apart and artificially separate technologies another symptom is if you're continually inventing new concepts so JavaScript is based on a rich history of Vonn demand based programming model language aming languages and has kind of battle-tested philosophies right like we understand how functions work it's very clear prototypical inheritance most people understand but when you start to build abstractions on top of you know HTML you start to have to invent a lot of things in order to get to the level of expressiveness you need to build real applications so now I'm going to pick on angular and I just pulled this this quote out from the angular docs and I've highlighted every concept that they've created that I'm not I'm either not really sure what it means as a new user of angular or it sort of exists in JavaScript and it's based on the idea that they want to augment HTML to support two-way data-binding and in order to do that you have to rethink the idea of scopes and if you think the idea of scopes you have to rethink the idea of composability and modularity and you start building directives and train lucien and all this other stuff but i think the framework cannot know how to separate your concerns for you it should only provide powerful and expressive tools to let you do it what I mean by that is that a lot of frameworks force you into this MVC style of development and MVC is great however your controllers tend to get really fat or maybe your models get really fat if that's your style of building or maybe even your views the reason for that is the framework is telling you how to separate your components and the vocabulary you're speaking is that of the framework and not of your application so we want to change that and we think the best tool for this is a react component which is a highly cohesive building block for you is that's loosely coupled with other components coupling and cohesion constant theme here so we want you to use components to separate your concerns with the full power of JavaScript and not a templating language so I'm going to pull up that example I showed earlier briefly and just highlight a couple of things we wanted to reuse some functionality so in react we created a function which is how you reuse functionality in JavaScript we wanted to reuse um we wanted to reuse some code and pass different parameters in each time and have it render to the Dom so we used composition and we composed a to-do application out of a to-do list object component again this is just regular JavaScript software engineering principles and we also have the full expressive power of JavaScript so for example I wanted to add 1/2 to the length of this list when I render it I didn't have to jump through any hoops I just put a javascript expression in there reusable components are great code reuse we all we all we all can recognize how awesome could reuse is composability another big one you build the component once you reuse it you can build more and more complex components and it actually you get kind of a linear increasing complexity then you know that giant curve of complexity because you isolate your complexity into separate components it's kind of implied but these are unit testable when you break your application down into small units you can just unit test them like you would unit test any other piece of code you don't need some sort of big you know test harness or dependency injection framework unless that's how you prefer to structure your application so you're probably thinking about spaghetti code right now I've talked about mixing JavaScript expressions in the Dom I've talked about co-locating or display logic with it the logic that generates the mark-up that sounds like it's going to be a mess right my answer to that is just don't write spaghetti code we're software engineers we can shoot ourselves in the foot and I'm sure that everybody's taken down something in production before you can keep your components small because we're trained to do it we do it all the time with our other JavaScript code why can't we do it with our front end code only put display logic in your components I'm not advocating putting all of your your model validation code and fetching and data access in components you might want to put them in third-party libraries that have some sort of bridge to your components but only put you know logic that makes sense in your components and this kind of reminds me of that Spiderman quote that is always repeated at software conferences with great power comes great responsibility another thing that people think about when you're talking about generating DOM and JavaScript is cross-site scripting vulnerabilities so a lot of times people do string concatenation to generate markup and then insert that in the Dom we've created a very lightweight library that we call react Dom to make generating a description of the Dom very easily this is calling a method called a which generates a link you pass your JavaScript object of attributes in and then a child which is the second argument that can be you know other react components other react Dom calls strings collections that kind of thing and this makes it really safe for us to generate descriptions of the Dom the next thing you're thinking about is probably what about working with designers we're not the first people to come up with the idea of generating Dom using function calls but a lot of times it's a little bit cumbersome to work with you know we've actually found that if you're just trying to balance parentheses visually it can be kind of annoying to do that and also designers tend to not like that so we built JSX which is an optional preprocessor it's a syntax extension that lets you write code that looks like this and translates it into code that looks like that and that's all it does we're not reinventing a 4x there's no runtime that supports this we're simply taking expressions that look like HTML and turning them into function calls so you get all the semantics of JavaScript you get the same line numbers as you would before the transformation so you can actually run your linting tools on your markup and you know get all the same rich debugging information that you otherwise would and with JSX we've just found that it's very easy for designers to contribute code I personally don't want to spend hours tweaking the box-shadow of all of my elements I'd like to just have my designer come in there and tweak them for me and so we've actually had found that this is very successful and we think of it like this it's the accessibility of templates and the power of JavaScript the accessibility of templates in the power of JavaScript you can use all the regular JavaScript code to generate these because they're just function calls but it looks kind of like markup so you can go in there and kind of still have your flow so react is all about components and it's not about templates and that's how we want you to separate concerns so I'm going to talk to you about what I think makes react awesome and the key design decision that makes react awesome is that we basically rerender your entire app every on every single data change we all know that building UIs is hard and that's because there's so much State you've got lots of UI elements designers can't make up their mind you ship one one version the a/b test comes back and you want to ship another one crazy environments if a dom is up for a long time you may write to the dom somewhere and forgot that you wrote there and then you know you forgot to keep track of it and we've identified that data changing over time is the root of all evil and it's really hard for us as engineers to reason about this and you know we're not the first people that think this up actually Dijkstra thought it up first our intellectual powers are rather geared to master static relations and our powers to visualize processes evolving in time are relatively poorly developed what he's basically saying is that it's really hard for us to think of processes over time but it's fairly straightforward for us to trace the flow of a program he continues with for that reason we should do our utmost to shorten the conceptual gap between the static program and the dynamic process to make correspondence between the program and the process as trivial as possible now Dijkstra's advice is that we should take processes that go over time and build abstractions that make them look like programs that execute in a single point of time and that's what it was like in the 90s when we were building server rendered apps we hit the database and we'd render a page and let's say it's a you know a to-do list example because that's the another theme of this presentation I guess you render the list of items and account and when you submit another to-do item you just select from the database again your account and your list are up to date and you just refresh the whole page very simple we don't have any of these problems with data being out of date and stuff so when the data changes react does this react tree renders the entire component this basically makes it really easy for you to think about what state your application is in set another way react components are just item potent functions that describe your UI at any point in time just like a server rendered at again because they're just functions that take some parameters and output a description of the UI they're very easy to unit test so here's a here's a very brief example this is a link that I can click and the count goes up we've isolated the mutable state in a get initial state method and we've isolated all the state transitions in state and set state methods and set state is basically how you tell react that the data has changed and it doesn't matter where your data came from we've done bindings for meteor that are 14 lines bindings for backbone that are 5 lines that kind of thing but you'll notice that render describes how the UI looks at any point in time so no where do we look in the DOM and find where we should update the count or where that node lives or do we we don't even set up a binding between the state variable and the Dom and this is actually really simple because it's so declarative every place we display data is guaranteed to be up-to-date and we do it without magical data binding without dirty checking the model which can be expensive and of course this is a modern framework there's no more explicit Dom operations and everything is declarative this seems like a pretty bad idea right it'd be great if we could do all this declarative work but re-rendering all of the the dom nodes on your page is way too expensive so we decided to build a virtual Dom to make rear-ending on every change fast you can't just throw at the Dom so if I'm typing into a text field and another piece of data updates I don't want to lose what I'm typing into the text field I don't want that flash and reflow of my UI I don't want to use lose my scroll position all that stuff so what we did is we built this virtual DOM and virtual event system that's optimized for performance and memory footprint so I'm just going to walk you through how this works so on every update which we get from that state that set state call that I mentioned earlier we build a new virtual dom subtree and we dip it with the old one so if you guys caught that talk on brackets there'd actually doing similar things with how we do the diffs we compute the minimal set of dom mutations and we'd like drop them into a queue and then we back to execute all of the updates together this looks a lot like the doom 3 engine there's a great series of blog posts about how the doom 3 engine works but you start with a game state and user input so network events user input events your knowledge of where everybody is on the map what gun you have open you know that kind of thing and then that gets passed into the the front end of the Dhoom 3 engine which executes the game logic so there are scripts in the levels there are certain rules about how you can move throughout doom and that's all in the front end and that creates an intermediate representation of the scene that intermediate representation gets passed to the back end of the renderer which generates the OpenGL operations that then get flushed to the graphics card here's how react works you have your application state you have browser events those go into your react component tree which describes how your application should work it's the business logic of your application just like the front-end of Doom three is a business logic of Doom three we create rather than a scene intermediate representation we create a virtual Dom which is an intermediate representation of how your app should eventually look we pass that to our back-end which computes the operations that we need to perform and then we flush those to the Dom at the appropriate time and that's actually pluggable how we flush it if you want to use your own strategy you can do that and this is actually extremely fast primarily because most Dom operations tend to be slow and there's been a lot of performance work on the Dom but you most operations tend to drop frames because we can reason about the global state of your application at any point in time we can compute the minimal set of Dom operations and use heuristics to do optimizations that reasoning about it at a incremental level you can't and because you're building components and we enforce a strict life cycle on those components we batch reads and writes for the optimal performance so you're never going to get in a situation where you do a read do a write to the Dom then do a read from the Dom again which triggers a reflow now this is all stuff that you've probably already heard about but enforcing this at scale with a large number of engineers building a large number of components is actually extremely difficult and react enforces that for you and we found that this is usually faster than manual Dom operations so react is not magic just like you can drop into assembler with C and beat cm beat the C compiler you can drop into raw Dom operations and Dom API calls and beat react if you wanted to however using C or you know Java or JavaScript is an order of magnitude performance improvement because you don't have to worry about you know in Java or JavaScript managing memory and in C you know the very specifics of the platform and so with react you can build applications without even thinking about performance and the default state is fast and we don't just stop at at you know computing the minimal set of Dom operations and making the Dom operations fast we do automatic top-level event delegation we basically re implemented an event system so we have event plug-ins that you know you can write it's it's a pluggable part of our core that read the raw stream of browser events that come in and generate synthetic events and these synthetic events are compliant to the w3c specification in all browsers and then we have our own implementation of bubbling and capturing which works consistently across all browsers now we have a great side effect of this which is you get some cool html5 events in IE 8 for example because we have an entirely synthetic event system another thing about performance is we provide some hooks to help you get even more performance so there was a great talk yesterday about two-way data-binding performance and comparing and contrasting the techniques and any sort of automatic management of your UI can be made to be slow if there's a crazy enough example what makes react special in this even though it's fast out of the box we provide optimisation hooks that don't require you to refactor your application to get speed boosts what this mean is what this means is that you can write a function that can tell react not to diff a certain part of the tree and this is this doesn't require you to change the coupling between components rethink how you fundamentally architected your app and these hints to react are usually just one line of code and we built demos that run at 60 frames per second in non JIT iPhone 5 web views and that's the environment that a lot of you know PhoneGap users would use the bottleneck is almost never the diffing it's always the Dom operations so the virtual Dom let's just do some other cool things so we can run in node.js so we're talking about not breaking the web in the last presentation and I think there was mention of Google not crawling single page applications that are all rendered in JavaScript so what a lot of people are doing today is they're running phantom j/s they're running their JavaScript and then they're dumping a static HTML file and serving it to Google what we do is we can actually render an entirely static HTML page without a Dom on the server so it's actually really really fast and you can serve all of your production traffic with it so there's obvious C SEO benefits here but we can do some other cool things too you run the same code on the client in the server and you send down some markup react boots up on the client and looks to see if markup is there if the markup is there all it does is attach event listeners and initialize itself so you get a faster page load experience your users will get the speed and of being able to interact with a you know static HTML page and by the time the JavaScript is downloaded the interactivity will pop in for you so you can imagine the first page load experience is a static page you start typing a comment in a comment box and by the time you're done typing the comment and you press submit the JavaScript is loaded in the background and you're ready to go it's completely seamless there's some other cool things we can do because you're building components that separate your concerns and represent your application structure we have knowledge of what your application looks like and what it's going to do so your components tend to reflect the structure of your application and the information architecture of the UI you're showing so we can say you know hey if the if a large subset of this virtual representation about to change maybe we should use a different method of emptying dom nodes than one for a smaller subset of the of the dom and this is something that you can't do just with dom manipulation and finally testability for free I mentioned before that these are just idempotent components that take in some data and output a description of the DOM and it's a description of the Dom so you don't actually have to run a s DOM or phantom j/s to test your components you can if you want and there are some useful use cases for actually testing in a real engine but you can just pass in some data and then assert what your component returned from its render method it's very fast and you don't need a set of a convoluted test environment for it a week or two ago we also open source SVG vml and canvas support via our bindings to the art library we think that you should be able to render your interactive charts in the same declarative way that you render your interactive UI on the same you just create a component that renders to a canvas instead of to the DOM and finally we have an experimental branch that renders your whole app in a webworker I'm not sure that this is a great idea but the point is when you have a virtual Dom representation you're not tied to the browser you can run anywhere in any sort of environment and it's extremely valuable and while this was kind of a cool hack it wasn't really that much work to do we just send the events over the boundary into the web worker and it sends Dom operations back over to the web worker like I said not sure this is a great idea but it has some cool implications so let's talk about the key takeaways that I just mentioned I want you to build components not templates because I want you to separate your concerns in the language of your application not in the language of the framework it's really hard to think about mutation so just throw out your old application re render the whole thing and then have the implementation take care of it for you and that implementation is a virtual DOM and it's actually not very complicated extremely fast thanks to the great JavaScript engines we have today so with that I'd like to say thanks to Jay s Khan for having me that's it you
Info
Channel: JSConf
Views: 384,238
Rating: 4.9284191 out of 5
Keywords: JS, JSConf, JSConf EU, JavaScript, JSConf EU 2013, Hunt, React, Facebook (Website), framework
Id: x7cQ3mrcKaY
Channel Id: undefined
Length: 29min 31sec (1771 seconds)
Published: Wed Oct 30 2013
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.