Yes. Animation is entirely State. Moving from State to State in a fluid manner, dealing with interruptions.
The Animated library is designed to make animations fluid, powerful, and painless to build and maintain.
Animated focuses on declarative relationships between inputs and outputs, configurable transforms in between, and start/stop methods to control time-based animation execution.
The notion of physically-based animation.
With Relay, you need to have a GraphQL backend. No easy way to create an integrated compatible backend solution.
At a conceptual level, we can think about Relay, GraphQL, and Apollo as the same, but at the implementation level, they differ from each other.
At the end of the day, the technology that you choose to work with will create constraints for your application.
How you fetch data will affect the rest of your application.
Gatsby uses a Relay-like implementation to build the Graph from 20-something data sources - but they make that invisible when building those structures.
Another type of website is CRUD apps that want more complex forms. There are no good solutions to manage forms. In the past, Redux was used, but it didn't solve the problem.
PHP, Rails, WordPress let you generate forms and manage them nicely on the backend.
Recoil solved problems for Formik. Managing states and updates in nested forms.
Yes. Falcor is a real-time rendering framework supporting DirectX 12. It aims to improve the productivity of research and prototype projects.
The idea with Falcor is that we can do the same thing without having a solid schema (Dynamically importing REST points.)
This solves the same issues when managing State, and it lowers the barrier of entry.
Joel Hooks: [0:00] Do you currently have, or have authored a state management library? Have you ever done that?
Christopher Chedeau: [0:06] Yes.
Joel: [0:06] You have?
Christopher: [0:07] Yes, it's for a different purpose, which is animated, which is the animation library for React Native. This is very similar around like, "Oh, you have states," which is the state of the animation, and how do you update the actual elements. It's 60 FPS, and it's fast, and this kind of things.
Joel: [0:30] Animation at the end of the day is completely state. It's like we are moving state continuously and we have to get there. The big problems are what happens when we interrupt? What happens when something happens in the middle of an animation? What do we do now?
[0:44] You have to move from state to state in a very fluid way. If you don't, then it's jarring to the user and it ruins the entire point of animating it in the place. Is that right?
Christopher: [0:56] Yes, and also, there's interrupting within an animation, and now are you in the middle of two states, what happens? Also, the notion of physics-based animation, or like, "Oh, how do you define the transition from state one to state B?"
[1:10] The common animation are easing animation or linear interpolation, but there's something that a lot of the native apps are using, which is using springs. This is a way to say like, "Oh, like a real spring?" You're like, "What is the tension? What is the force applied?"
Joel: [1:32] The physics of it, right?
Christopher: [1:33] Yeah. The great thing about this is, if you start dragging in elements and then you stop, then it's going to keep the momentum going for some time. If you back up or you throw it like something else is moving on the screen, then it can keep the momentum. It feels like the animation, the transition feels more real life like.
[1:59] Using the spring physics is the way iOS is doing it on most of the animation and interactions, and has been something that's for React Native repeated. It was around how do you encode this within UI library like React? The other thing that was complicated in the process was around the frame rates.
[2:28] For animation, you want the animation to be running continuously and never stopping. What's interesting with animation is every single step along the way is super cheap to compute. We're just like, "Oh, a few mass operation, and computer don't have any issue with this."
[2:55] The way Native platform are doing it is to move this logic of running the animation in a different process, in iOS Core Animation process. No matter what happens in the app, it has super-high primes going to run the animation for you. The challenge is, how do you declare what the animation should look like when you're sending it to a different host?
[3:37] What I and we've done for animated is you define those kind of animated values which are very similar to Recoil atoms and Recoil selectors. One thing that's interesting is, from your React app, you can't see what's inside of those values. The way we're doing it is you basically declare like, "OK, this is how I want my scope to be attached to the scope position, and within offsets and using springs."
Joel: [4:58] It's interesting on a lot of levels because if you have a process, it's concurrency and parallelism, and the ability to run things that feel smooth. As users, we have to touch it. We're touching our phones. If it doesn't feel right, it's just not good. It's horrible.
[5:17] Is there a correlation between that? You brought up Recoil, which is for dealing with asynchronous processes in a web application where you're talking to a server. You're getting that same async where you don't have control of that state. You're sending it to a trusted source, and we assume they'll respond. You're dealing with a process.
[5:38] What layer of state is that? Do you even think about state in the terms of layers when you sit down to write an application? How do you consider it when you have the blank slate?
Christopher: [5:50] I want to answer this question, but first you asked me what is the parallel between Animated and Recoil. For this one, and same for MobX, the idea of how do you update the actual DOM elements in the end. For Animated, the way we want to update is at the very specific property level of the actual final DOM elements.
[6:17] The interesting thing with Recoil, and this is also how Angular 1 was doing all of this data binding. I believe this is how MobX is doing it. The interesting thing with this is it's very low level. You need to have very fine grain dependency management because you need to have the entire graph computed to know the specific attribute that you want to change.
[6:48] One of the challenges with this is that you need to have a very complex dependency management. You cannot run arbitrary codes in the middle, because now the dependency management doesn't know how to compute it.
[7:03] For animations, this has been working really well because usually for animation, you only want to do spring-based or simple mass thing about it. One of the things with Angular 1 was now they invented their own language to define how you do these kinds of things.
[7:23] The thing that I found to be very excellent with Recoil is that the way it works is it uses the React's component state, and it updates the component state. Now, the atomic unit you're working with is the React components. Now, you just need to know, "Hey, something changed in the dependency, just rerun those components."
[7:51] Thanks to that, now you still have the whole flexibility of React. You don't have to invent your own DSL for how do you take this primitive state, and how do you render UI element and the actual specific attributes?
[8:04] You still are able to target specific React components rather than the normal way of updating React, which is, "Oh, re-render the entire tree and use script component updates to add some variables."
Joel: [8:19] It's interesting to me because it is a very similar problem Recoil and Animated end up approaching it. It's probably not coincidental that these solutions tend to be...Do y'all chat at that level internally when you're solving these problems? Is the discussion and collaboration in terms of how these are come to, or is this just common patterns that we're drawing from?
[8:44] To me, there's event sourcing and CQRS, Redux had this idea and a bit of this notion, and the command pattern, if you will. There's all this. What past resources and collaboration came to decide on this end solution?
Christopher: [9:01] For Recoil, I wasn't involved in the beginning. I don't think that they was inspired by Animated. When I first met Dave and he showed me this, I myself drew the files, and now a lot of this kind of libraries and everything, the actual libraries are very small.
[9:25] Then, so, how do you frame it? How do you educate people? What are the concepts? In this case this is more about, "Oh, the concepts are similar." Now, I pitched Dave how I view the world, or how to use this concept, so he can get inspiration for his talk and how he's evangelizing it. The actual ideas they came out independently.
Joel: [9:52] It's the similar patterns is what's interesting to me. We're all drawing from our past experience and state management is usually like, "Oh, this is hard." These are real hard problems that React has been criticized for. Recoil is more interesting than simply the performance issues. That's what people address.
Christopher: [10:18] Oh, I see. I would say the biggest inspiration from Recoil is the React hooks, because if you look at React hooks, there are use states, but the challenge with use state is it's local to the components.
[10:56] The way I see the inspiration from Recoil is, let's use the use states paradigm that React added. How can we extend it to manage more than local states?
Joel: [11:12] When you're thinking about a React application, what are the types of state that you see in a typical application? It's a broad list, but what are the main ones that you see people applying?
Christopher: [11:26] The first piece of state is the data you want to display from the server, usually. You get some data source that you want to start downloading from the server and you start to want to render.
[11:37] I view this kind of state that is being used by almost all applications. I feel like Relay and GraphQL for this type of state is an excellent solution, because this is like, "Oh, what is the data I need?" GraphQL lets you say, "I want for this," like the components of Facebook, but develops an application that is similar.
[12:04] This is like, "I want a newsfeed. Give me all of the newsfeed items." Then for each newsfeed item, what is the actual title, what is the person? For the person, what is his name, what is the avatar and this kind of things?"
[12:16] If you're presenting data, like GraphQL, pattern is nice, and then Relay, what it does is it handles pagination for you, it handles local caching, so if you go to a different page and you already have this piece of data, then you can use it.
[12:36] Then, if you have small updates to be done on this, then Relay is also good because you can say, "Oh, modify this, like make alike. This is all of the fields I think needs to be updated and refetched, like all those fields, and re-update the local states of the app."
Joel: [13:03] Relay's interesting to me, because I know at Facebook, in the context of what you all are working on, you use Relay, but then the broader public, do you think there's a reason why Relay isn't the go-to solution and stuff like Apollo has taken hold in the consumer sphere?
Christopher: [13:25] One of the things with Relay's is we need to have GraphQL backends. It doesn't work neatly with just like REST endpoints. For GraphQL, we haven't provided an easy way for you to set up a GraphQL server. Apollo, they'll provide you the whole package. They provide you the backend, and also the client-side implementation.
[13:56] I believe that in the Apollo, if you look at it, it looks very similar to Relay. I would say, the two are the same to me, at least conceptually. Now, there's a lot of difference in the implementation, but at the conceptual level, Apollo and GraphQL and Relay, I can think of them as the same.
Joel: [14:23] I've thought about this a bit. When you're building one of these applications, I feel if you go for Relay, or even MobX-State-Tree, or Apollo, that's a big decision for an application. Your application becomes a Relay app at the end of the day, a Relay React app, however you want to frame that.
[14:41] It's broad. It affects the entire application, because that's what its point is is to communicate with the server and cache, and manage that data, otherwise, what do you have?
Christopher: [14:52] One of the challenges is that how you fetch data is a big deal because it affects the rest of your application, because every single piece of your application needs that data.
[15:07] I haven't found right now a way to [inaudible] this and so, within Facebook, we have something called a pattern, where you have some component that they are just to fetch data and then, the components there are just presenting the data which is already fetched.
[15:26] At some point you want to normalize how you are fetching the data, so this pattern is less useful in practice, because it's very unlikely that the links to build the component's going to be used from two different data fetching.
[15:45] There are cases, and especially if you are like other big app and you want to integrate with a bunch of different services, this can happen, but for the most part it doesn't.
Joel: [15:57] It's funny, because I believe under the hood, Gatsby is using a kind of Relay, like that's how they build the graph.
[16:06] Its whole point is, "We have 5 different, 20 different data sources and we're going to bring them all in," but they make that invisible and build static sites out of that. It's still fundamentally the same principle. It's just done at a build time versus done in dynamic at runtime. You're building these structures and displaying them.
Christopher: [16:24] This is one big part of data management, which is you've got the mostly read-only websites, and you can modify a few things. Apollo or Relay, GraphQL are excellent products.
[16:44] Now, there's another type of websites, like part of website that people are doing is basically a CRUD app, or like an admin app, where now you want to be able to create all those things, you want to be able to edit all the fields.
[17:05] Right now, in the React ecosystem, there's no good solution for this that I've seen. One of the strengths of Angular was that it would be with data bindings, made it super easy easier model. It has all of the fields, they bind that way. Then, you get a written version of the model, and you can upload it to the server. You can save and this is done.
[17:31] I haven't seen a good React form library that really took off. This is where Redux have been used. One of the issues is Redux is it's very verbose. Many times, for this kind of admin settings, you've got tons of fields, and now you need to create the action, the dispatcher and all of this, this is a huge headache. This is a reason why people are like, "Redux is boilerplate and everything."
[18:05] For this kind of app, the MobX kind of data binding is super helpful, because Angular 1 version, you want to automatically generate its form, you want to update this form. This is where PHP, CakePHP, and WordPress, to a certain extent.
Joel: [18:28] Rails.
Christopher: [18:28] Yeah, and Rails and this kind of thing are super nice, because it lets you generate forms that you can save, and they handle all of the database and everything for you.
Joel: [18:40] Have you ever used Django? Their admin interface is like, "Ooo, there it is." We don't have to think about CRUD so much anymore. Edit me right, Formik would be my personal favorite. I love Formik. I've talked to Jared about this. Interestingly, Recoil solved a problem Jared was having building forms for his Formik cloud.
[19:04] He had all these deeply nested forms. He had about five layers deep. You try to type into the form field, and it would stutter and freeze because of the way React works and cascading down. He started using Recoil to go around that and bring the update specifically, and it fixed that.
Christopher: [19:22] This is the second big data management thing are I'm thinking about. The third one, what I found is around specific tools. One that I saw is trying to build a Photoshop layer that Dave mentioned, or if you're trying to do analytics tools, where you're able to slice and dice a bunch of graphs, and a bunch of data. A lot of this is in the enterprise business. There's a lot of market for it.
Joel: [19:59] Dashboards, that sort of thing.
Christopher: [20:02] Dashboards and those kind of things, visualization. This whole space right now, I don't think that is a GraphQL world, or is a Redux world, or Angular world is working well.
[20:40] For example, if you're going to update a chart, it's going to take a while, or maybe you need to ask for the server for some data and refresh. This kind of things, with a lot of asynchronous operation, is something at least right now, in the React ecosystem, I haven't seen a good solution, but maybe I haven't looked enough. I feel this is where Recoil is interesting.
[21:05] This is also one place the core React team is actively looking at. The problem they're trying to solve is for the new Facebook, facebook.com and with a lot of, "Oh, we need server-side rendering. We need first page initiation, super important. We have tons of data that we may or may not need. We need basically read-only or very little inputs."
Joel: [21:32] This is a little obscure, but did you ever explore Falcor?
Christopher: [21:37] Falcor is in the same vein as GraphQL.
Joel: [21:45] It is. For sure, GraphQL and Relay, is just a different angle.
Christopher: [21:48] One of the constraints that GraphQL puts on itself is they want to have a strong schema, so that if you want to scale to a bigger application, this page needs this same information that we have in another place. Now I can just use the schema and use GraphiQL to be able to see all of the fields that exists that have already been exposed, now I can use it.
[22:18] The downside of this is now the first step of setting it up is very heavy, because for every field that you want, you need to add it to the schema, and walk on this very rigid structure. The idea of Falcor is, "Can we do the same without having the strong schema?"
[22:40] Just dynamically saying, I have this REST endpoints that is giving me those fields, we need to dynamically extracts these fields from the REST endpoints and stitch together bunch of REST endpoints. I view this as solving the same kind of issues and trying to lower the barrier of entry. You don't need this heavy, upfront work to be able to get started.
Joel: [23:05] I don't know why a thing takes off, and it had a lot to do with the project and just scope and running open sources, an entirely different conversation, probably, to state management, maybe related, I don't know. I wanted to also ask you about Excalidraw, that project, I think it's cool.
[23:25] I pull it up a lot when I just want to make a simple diagram of some sort. It works really well. I get the export I need. I enjoy it as a user, but I was wondering, when you're starting that project, it's graphic heavy. Was there a state management issues involved with creating that? Maybe even particularly with the multiplayer aspects of it, I was wondering what kind of problems you might have ran into.
Christopher: [23:51] I wanted to use Recoil for this, but Recoil was not open source. I didn't want to take a dependency on something and open source it. Instead, what I did, was to just have one JSON object, which is the entire states of all of the elements, and everything. The whole pattern, at first, what I did was to mutate this whole object, and then re-render the entire thing.
Joel: [24:22] Is that Redux-like then? Like you have a big graph, a single object graph, where it's your single source of truth up at the top that describes the entire tree, at the end of the day?
Christopher: [24:37] Yes. First of all, mutation worked well for a while until we wanted to be able to update different parts at different rates. For example, for the UI, if you're just drawing something, there's no way to rerun the other UI, so we wanted it to be able to bypass and not render the menus and those kind of things, to be faster.
[24:59] The other thing is around caching. We are also caching. If you are drawing a rectangle, we need to compute the path to make it look rough, like handwritten. If the rectangle didn't move, didn't change, you don't want to update it. For this, we implemented primitive caching layer around when you're modifying it, if you're modifying it, and it needs to be recomputed, just like putting the WeakMap.
[25:34] Now you've got this and same for going from the pass to the actual bitmap. This will basically re-input it from scratch, instead of, "We could have used the Recoil." Then describe a dependency, and then like, "Recoil would have handled this for us."
Joel: [25:51] It sounds almost like using it, and then looking at David's demo, there's a lot of similarity, right?
Christopher: [25:58] Yes.
Joel: [25:58] Visual and interactive similarity that I can see. That had to be an interesting choice, because you know it exists. The rest of us at the time didn't know it exists, and you're like, "It'd be perfect."
[26:42] Now, we've made the opposite version of everything that many people are doing, and it served us well. The interesting thing with Excalidraw is the scope of it is pretty small. This is just one app where you can draw and diagram and everything. We don't want to bloat it and have a loading screen, or many features and everything. We didn't need all of this infrastructure at first.
[27:19] As we saw, more and more the use case and everything, we started slowly adding things. One of the things, for example that we did, which is maybe interesting in this context, is the internationalization library, we wanted to be translated. The first thing we did was, we were not going to rewrite one, so we included one off the shelf.
[27:43] Then we saw this was a huge bundle size increase and it's a re-render like the React DOM, three times at the startup and everything.
[27:53] What I did was now that we knew the feature that we wanted, to reimplement just the core, or reuse the browser detection library, the language they come with, because I don't want to be in this business, and re-render and reimplement this shortest solution for everything else in the library, provided that we need it. For this, we've been able to shrink it by a lot.
[28:18] Same for the color picker. We started by using React Color, which was super nice at the tone and motion and everything. Once we've landed on the option we wanted, then we basically took the actual dump and output it through the CSS if it was needed, and just React code like a react component for it.
Joel: [28:40] One, it sounds like fun to take this. If you're building this efficiently, if the intent is to scale a product to market, but you're not doing that. You are building something that's interesting that you want to use yourself as a project.
[28:56] It's also, to me, like you could take that same philosophy, that design, because that's a design philosophy at the end of the day, and apply it to almost any app. We can take the bloated thing, that's fine. When I say bloated, I don't mean to disparage the work, they're just built for every solution.
[29:10] React is slim for what it is, but when you're building one of these libraries, you have to include everything for everybody, the kitchen sink. If you only need a knob to turn the cold water on, you don't need the rest of it. You can build that and design backwards almost.
Christopher: [29:27] It's interesting because at work, I'm working on performance and reliability of all the apps within Facebook. This is interesting, because Facebook, the mentality has been, "We want the features." We are like, "Optimize everything, so we can iterate fast on the features and everything."
[29:45] WhatsApp, what they optimize for is, "We don't want a lot of features, but we want to be small, and to be fast, and to be efficient," so WhatsApp, they're doing the same process.
[29:57] Any dependencies they are going to take, they are going to copy and paste just the small amount of code that they need to make it work, whereas Facebook is like, "We want to be more able to iterate, so we're taking libraries," those sorts of things.
[30:15] Both are very successful, both different strategies and different pros and cons. It's been very interesting to see the different attitudes, and the different trade-offs they've been taking.
Joel: [30:28] When you're doing that, when you're focused on performance at scale across a lot of apps, is state management part of that? Is that part of the performance question when you think about those sorts of things?
Christopher: [30:40] State management is part of the question, but at the very early, and this is something that's hard to change. Usually this is not what's likely to change that much.
Joel: [30:56] This is when you say, "This is a Relay app," right?
Christopher: [30:58] Yeah.
Joel: [30:59] That's a very early choice, and that's just how it's going to be.
[31:29] We've made this architectural decision. This required a big effort. This was for performance. It may or may not be possible within your situation, but what I found in order to improve the performance of anything, basically, is to start measuring it.
Joel: [31:50] Telemetry.
Christopher: [31:51] What my team has been focusing a lot on is the whole measurements, how do you measure performance in production? How do you measure performance in a testing scenario? Then, once you have this measurement, you need to convince people to improve it.
[32:11] For this, Facebook, there's many teams that own different parts of the app. How do you convince those 40 different teams on iOS and 40 different teams on Android to care about performance? We are building all of the tuning, so we can start tracking each individual metric and then putting all of them together in a program.
[32:36] Now, there's a incident review where we reviewed all of the issues. We need alerting on top of this. Then we need exec reviews every month. We share the status of this program with the execs. There's download pressure and staffing, and all those things. This is a lot like how do you convince an organization?
Joel: [32:58] It's state management at the business level. I'm not saying people are components, but you have all these individuals, individual opinions, individual priorities, group priorities, organizational priorities. You have to get in, and it's big, and everything's moving, and you have to fix it.
[33:19] I love where you're talking about the solution is to show, "Here's where the problems are. Here's the hotspots. Here's how you can, at the end of the day, quantify the effort that you make to solve this and how it actually affects the performance of the application." It is cool.
Christopher: [33:36] The interesting part is that, if you give a metric to an engineer, they're going to drive it down. They are going to be excited. A lot of pitfalls I've found in the past is a lot of people are excited about making their product fast, but the issue is they're basically going to start working on it for six months, and in six months, they made it faster, but they didn't track it.
[33:59] Now it's really hard to tell their manager, "I made it better." Their manager is like, "Did you add any new features? Did you get more users?" "No." So, now you're in an awkward situation.
[34:13] If you want to improve performance organizationally, the best way is take a metric and track it, get alerts when it goes down, and make a process around it, and show it to management. Now you're going to have a shot at doing the things you like, which is optimizing code, and also be rewarded.
[34:34] I don't know if this is only for big organizations, but I've seen this in the Rust projects. Right now, they have a big issue with compile time. Someone started an effort around tracking compile time in addition to doing fixes. They reduced it by like 20 percent, then 20 percent. They're tracking it and they're making it better.
Joel: [34:59] I've talked to J.D. Dalton about this in terms of Lodash. He's always competing with the browser. Can Lodash be faster than the browser? Now, the browser's faster, so I have to use the browser, but can I be faster? It's this competitive itch to drive that number down. It's gratifying at a very fundamental level to a lot of engineers.
[35:22] Christopher, I really appreciate you taking the time to chat with me. It was great to hear about this stuff, because it's endlessly fascinating. The problems you're working on are at a scale that a lot of us don't get to touch, so that's interesting to me, as well. I really appreciate it. Thank you very much.
Christopher: [35:40] Sure. Thank you.
Joel: [35:41] Cheers.