Slide 1

Slide 1 text

Why does React scale? Christopher “vjeux” Chedeau

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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.

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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` :)

Slide 16

Slide 16 text

Prop Types We introduced typing annotations which is something really uncommon in a JS library

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

• 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.

Slide 25

Slide 25 text

• 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

Slide 26

Slide 26 text

Questions? Christopher “vjeux” Chedeau