Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Why does React scale? - JSConf 2014

vjeux
May 29, 2014
2M

Why does React scale? - JSConf 2014

vjeux

May 29, 2014
Tweet

Transcript

  1. min(Time To Find Root Cause) We want to reduce the

    number of bugs in the system but it’s not really actionable Instead, we found that focusing on minimizing the time to find the root cause of bugs was a better proxy to meet our goal
  2. Everytime you start the process of fixing a bug is

    by reproducing it For example, in this case there’s only one todo item but the count says 2
  3. Once you have a repro case, you want to know

    what code was being used to generate this value To do that, you are going to right-click/inspect element and look at it in the browser Then, you’re going to find something as unique as possible and grep it on your entire codebase It’s a bit of an hit & miss process, sometimes “todo-count” will give you the right code, sometimes not
  4. To make it easier and faster, we introduced React dev

    tools. This gives you the React component that was used to generate it. Since at Facebook, all the React components are uniquely named, you can directly open the file and be set. Dev tools are also really nice as you can live update props on state on the right panel
  5. Once you found the variable, you need to understand why

    it doesn’t have the value you’d expect. When I ask people what their workflow is, they usually tell me that they use a debugger, and when I watch over their shoulder I cry deep inside
  6. Debugger • Forward in time • Execute every lines Developer

    • Backward in time • Jump to updates The issue with debuggers is that they are not really useful for this use case. We are at the end of the execution and we want to know what happened to that variable in the past so that it got assigned this value Also, the debugger is executing every single line, but you want to jump directly to the place the variable got modified
  7. Local Variable Current Function ! < 100 lines There are

    few different types of variables in a React application. If you are dealing with a local variable, then it is easy, you can just scroll up and see how it is being modified
  8. State Entire Codebase ! (a lot of lines) If it

    is a state variable and you are not taking special care, then your search space is basically the entire code base. This was the source of soooo many issues at Facebook that in React we decided to treat it in a special way.
  9. State Entire Codebase ! (a lot of lines) Owned by

    the Component ! 1 file < 1000 lines We imposed one constraint on state variables is that they belong to a component, and only the component can modify them. This greatly reduce the search space to just one file
  10. State Entire Codebase ! (a lot of lines) Owned by

    the Component ! 1 file < 1000 lines getInitialState()
 setState() ! < 10 lines Still, one file is pretty big. We restricted state updates further so that you can only modify them via two functions: getInitialState() and setState(). Since there are only a couple of call sites in a file, it’s now very tractable for a developer
  11. Immutable ! 0 lines Props The other special variable in

    React is props. This is a value being passed by your parent. One fundamental concept is that it is immutable, therefore you just have to look for its call site
  12. Immutable ! 0 lines Props Call sites ! 1-100 files

    If you are into a normal component, you shouldn’t have more than a couple of call sites, but if you are looking at a core component, then it can get in the dozens or hundreds and become hard to identify which one it is
  13. Immutable ! 0 lines Props Call sites ! 1-100 files

    Automatically inherit props 
 Call sites
 and their call sites
 and … . If you have to pass a props from a grand parent to a child, then it starts adding a bit of boilerplate. Many people ask us why we don’t implement props that are automatically inherited like scope in Angular. The reason is that you now have to check all the possible ancestors of your component which can be a —lot— of files And as a corollary, when you want to update one of the top level files, it’s really hard to know all the components that depends on it, and therefore test them all to make sure your fix worked
  14. Immutable ! 0 lines Props Call sites ! 1-100 files

    Dev Tools ! 1 file Luckily for us, we don’t need to track down all the call sites, we can use again the dev tools in order to find the call site, we just have to press `up` :)
  15. Prop Types C++ – auto keyword Static Languages Dynamic Languages

    JavaScript – TypeScript PHP – Hack Write More Types Write Less Types If we take a minute to look at programming languages in general, it starts to make sense Static languages are trying to make you write less types whereas dynamic languages want you to write more types
  16. Prop Types Sweet Spot ! Type only function arguments !

    component props It turns out that they both converge into a place where we are typing function arguments. If you think about it, a React component can be seen as a function and its props as arguments. So it actually makes sense to type props
  17. Prop Types Exceptions do not propagate
 ! 1 hop The

    first use case of adding type annotations is for documentation. You can just read that file and know what it is expected to take as arguments. The second one is that it prevents errors for propagating. JavaScript doesn’t throw very often and your value is going to be able to go many levels deep before throwing an exception. The farther you are from the original error the more hops you’re going to have to do and the harder it’s going for you to trace back the error as the code is going to be unrelated
  18. jQuery? jQuery React JSX Someone asked me on twitter if

    we could support jQuery way of building virtual DOM nodes. We support two DSLs natively and CoffeeScript & ClojureScript communities came up with several others. However, jQuery has a very different property, it doesn’t come with a way to say that the node is completed
  19. Mutable call(element) ! the entire call tree Because anybody can

    modify the element after it was created, then whenever you pass it to a function you have no idea if that function is going to modify it or not. Meaning that you’ve got to check the entire call tree. This was a major source of bug at Facebook
  20. Immutable Yet, it’s still valuable to be able to modify

    an element after it’s been created. So we introduced the API cloneWithProps. The important detail is that it returns a new object instead of modifying the existing one
  21. Immutable var modified = call(element)
 ! only this pattern Which

    means that if you call a function with an element, if it modifies it, then it needs to return it. Since 99% of the time it doesn’t modify it, then you can skip a large numbers of calls when troubleshooting. This is also a good example of using immutability in JS and not some very different language such as lisp or haskell
  22. • Move Fast & Break Things • But fix it

    before it goes to prod! Conclusion We’ve got a moto at Facebook which is Move fast & break thing. The other side of that sentence is that we invest a lot in detection and once known, we need to be able to fix it fast, and hopefully before the users can see it. Again, we don’t know how to make it faster but we can make it more predictable.
  23. • Unpredictability #1: Finding the root cause • Unpredictability #2:

    Not introducing another bug with your fix Conclusion The first source of unpredictability is finding the root cause of the bug, but we covered this in the talk. Then, you need to come up with a fix, in practice as engineers this is what we do best. Finally, the worst thing you can do is to come up with a fix that causes another bug. It turns out that all the steps we did to improve tracing back when a variable was modified also helps when making a change to make sure that it doesn’t introduce unintended side effects