Joel and Dave chat about the essential questions around State Management. A critical point mentioned was that programming gets boiled down to managing State, especially when it comes to working with React; this is due to React's functional paradigms. Dave also talked about how Recoil is designed with Concurrent Mode in mind, his experience in open source, Pattern Language, and the different State in a browser.
It’s been really good. Lots of support from the community.
Joel mentions Jared Palmer and Joel talk about State Management and how Jared fixed their crippling performance problems with Recoil.
This is because Concurrent Mode rendering is not blocking; it is interruptible. This improves the user experience.
People just don't use pattern language anymore. Did Java kill it?
It's more of an oral culture rather than a written culture.
Maybe this is why people use redux when they don't need to because they don't understand what pattern of redux solves, so they use it every time.
Jed Watson combining layers of State. - Local State - shared State - Remote State - Meta State - you aren’t the source of truth - Router State
David's mental modal:
Url bar could be thought of as a component.
There's an upside to having a browser that knows about all the semantics on your page.
Joel Hooks: [0:00] Ready to chat about some state management?
David McCabe: [0:05] Let's do it.
[0:28] I don't hear a lot of people...I don't know. There's not a ton of state libraries for Vue, for instance, but we have this embarrassment of riches in terms of React about the decisions that we can make. Do you see that as a design decision from the framework? Why is that the case, in your opinion, do you think?
David: [0:52] That's a really good question. I take it where we've already started the...?
Joel: [0:57] Yeah, I'd like to hop right in there.
David: [0:58] OK, cool. When React came out, it was such a different way of looking at how to make UIs, that we had this Cambrian explosion of trying to figure out how you can organize things. UIs have basically been made the same way since Smalltalk in the '70s.
[1:18] You've got these objects and they can send messages to each other and each have their own state. You have this two-way communication for everything. It was basically about deciding ultimately, when things on the screen need to repaint, right?
Joel: [1:32] Like a classic model view controller, right?
David: [1:36] Yeah, yeah. That dates back to the '70s, and that's how you would write things on Windows. That's how you would write things on macOS. Then React is this whole different way of looking at it.
[1:46] Then it's like, "Oh, now what can you do?" You get all these ideas from functional programming all of a sudden being practical, because with React, they figured out how to bring that into the world that we know, and not completely pure functional world, in a way that it is sufficiently gradual that you can adopt it.
[2:08] Yeah, it's this whole new world of possibilities. People have been exploring that. Maybe there's other factors too besides that, but that's the main that we see going on.
Joel: [2:18] I was thinking, because there's Pete Hunt's where Vue is a function of state. I've talked to a few people and they were like, "Most of this programming, we're talking about UIs anyway," because there are a lot of layers.
[2:33] I've been a frontend developer for a long time and that's where I focus. The idea that state management is most of the job. We have all this other stuff that's going on. You're styling, and you're doing different things. At the end of the day, that programming part of it is like this effort to manage and wrangle state in a way that the user can ultimately use it.
David: [2:55] It's the best thing. One thing you could say is, at least, that's one of the easiest places to get yourself in trouble because if you think about how things work on the Web...The biggest example of this is CSS. Obviously, there's a lot of complexity there, but at the end of the day, it's a stateless system, and it's relatively simple, right?
[3:20] There's this direct mapping between some static code and then what you see and so you can get that right at a point in time. Then, that's the way it is. When you have something that can evolve over time through a number of states that is technically finite but not easily analyzable, then that's where sort of things that are hard to figure out can creep in.
[3:45] You see that with a lot of async code, where if you're trying to manage async requests using manually by responding to when they need to go out and when the results come in or when errors come in and all that kind of thing and then updates in terms of storage and reducers or whatever, and you do that manually, it becomes very complicated.
[4:09] Pete was getting out there. Basically, a lot of other stuff has already been reduced to functions. It's the thing that's not been reduced to a functional point of view. That is where the remaining complexity lies, right?
Joel: [4:21] Yeah. When you sit down and you have a new application and you're about to get started, what are the questions you ask? Before you even get started when you're thinking about, "OK, we're going to have a lot this day. We're going to have to do this," what are the essential questions that come up for you when you're designing at the design phase before the code even starts?
David: [4:47] That's a good question. Usually, when I've worked on apps that really evolved...I don't know. There is a phase like that. That's very long. It's like, "Let's make a prototype."
Joel: [4:59] Let's get started.
David: [5:00] That just continuously goes into becoming this complex app. That's the way I tend to do that.
Joel: [5:09] As that process proceeds then, as you go down the road, what questions might come up? Ultimately, I want to get to the question how do you know when you need to synthesize a brand-new tool for the world?
[5:27] Given all the choices, like the off-the-shelf choices, how do you analyze and make a decision in terms of what tools that you might bring into a project?
David: [5:35] Maybe I can talk about that with the specific history of Recoil, just to make that concrete.
Joel: [5:40] Yeah, that's fine.
David: [5:41] We have this app that started out as a simple prototype. We put together and see, can we do a particular type of performance analysis on some data that we have? That turned out to be successful. All of a sudden, we're adding all this complexity to it to support different use cases and that type of thing.
[6:04] It turned out to be very buggy. It's like, "OK, we need to actually make the state more functional and simple and less ad hoc type of situation." It's funny because when I've talked about Recoil, I usually talk about performance because that is the objectively...
Joel: [6:27] It's the obvious, in this case.
David: [6:34] demonstrable part of it. The thing that really motivated it more than that was applying out functional structure to async processes.
[6:46] That [inaudible] has come out like, "We need to be able to make this app that does all these different queries and does a bunch of data, combines data and stuff on the client, and have it not just all become a mess, and have engineers from other teams be able to come in quickly and add something and not mess everything up. Or, people who are less experienced in that particular domain."
[7:13] We want to impose this functional model on it, where, if I am making a query for some data, that is not...I don't want to think of that as a process, I want to think of that as a function but I just happen to be evaluating it on another host. If I can think of it in a purely functional manner, then it's simple.
[7:34] Recoil is the answer to, how do I do that in a way that's performant. You get this data flow graph where you have these functions and know what their inputs are, and then you memoize based on those inputs. The data set is a pure function evaluated on another host of those inputs that come from the graph.
[7:56] As to your question of, when you know you need to make the thing, we knew that what we were doing wasn't working, and we didn't see anything that solved it that already existed. Obviously, there's no way you can go through everything that exists out there because there's too much of it.
Joel: [8:12] Sometimes it might even be easier. Is there a situation where it's easier to...I don't want to even say, event, because I feel there's a lot of prior arts to what has been produced but where you want to sit down like, "OK, these are the patterns that we need to implement."
David: [8:31] You do see complaints that are like, "Why yet another one of these?" That comes out of a point of view in which making something like this as a big deal, where really this is just the encapsulation of some patterns.
[8:42] It's a way of thinking about things written down in some code that provides structure to an app. Everybody should be doing that. Everybody is doing that all the time, anyway.
Joel: [8:59] Whether you're doing it intentionally or you're doing it in an ad hoc way, we're all designing. You might design then you end up with accidental...Sometimes you meet accidents that work for you and then sometimes you have accidents that don't.
David: [9:15] The opposite of that is cargo culting. It's saying, "Oh, this library is the standard thing, and there's all these tutorials about it. So, I guess I have to use it." It doesn't really work that well, and I'm frustrated with it but that's just the way it is.
Joel: [9:31] Not to badger Redux too much, but I feel like it came in the scene. It was something that everybody was like, "Oh, that's a great idea." All of a sudden, Dan made tutorials on Egghead. Everybody's watched these videos.
[9:43] Now everybody is building Redux apps. Then now you have a bunch of sad people implementing solutions that aren't necessarily appropriate for the problem, just because it seemed obvious maybe.
David: [9:54] Redux was a really good step. It was a great idea. Depending on what the app is and where it was coming from, it was a major improvement, but nothing like that should be taken as an assumption. It's just what you should use because that's the way it's done.
[10:17] Our field would have to be much more mature before we said this is the way things...It's not always true. There are things where that's pretty established where we really have figured it out a lasting solution to something, but I don't think this is one of those areas.
Joel: [10:32] Web development in general still has a long ways to go before we're all...Even the platform itself where we use the platform crowd coming out of Google where that is, it's their mindset. They're building the browser. That's how they think about it.
[10:53] Do you see that in any near-term future where we're consolidating on solutions? We have a ways to go in my eyes.
David: [11:01] I don't know.
Joel: [11:04] Predicting the future is impossible. I don't have a crystal ball either.
David: [11:10] I certainly don't think that will happen until the Concurrent and Scheduling and that type of view of the world has thoroughly percolated through everything. That's a major change that's going to require a lot of change. React itself, it's a big conceptual change.
Joel: [11:32] Is Recoil something that people should be importing to basically every app or is it specific to certain problems?
David: [11:42] It's a good question. On the one hand, you could put it in any app. What it would give you is a set of utility hooks that work together in a really nice way and push you to patterns that are resilient and that are going to help you write the code that has certain nice properties.
[12:07] On the other hand, there's obviously some overhead to using anything like that because extra bookkeeping that Recoil has to do. There's performance overhead. There's conceptual overhead, that kind of thing.
[12:18] You could make a strong argument to just use React for most apps, which is fine for most apps. Then you'd never have to worry about compatibility or new versions, you'd never have to worry being held back because maybe the React team wants to do something in the future but then Recoil is not compatible.
[12:35] That could happen. That's not the case with anything that we know of yet. The point is the fewer dependencies you have, the less opportunity there is for some problem like that.
Joel: [12:47] While we don't have crystal balls and can't see the future, you have some insight into what is our user land future of React. The Concurrent Mode has been looming now for a long time. I feel like it's looming because people are being conscientious and trying to get the solution right, and it's a big problem.
[13:08] The public forum isn't the place to solve these kinds of problems perhaps, but is there anything that we should be thinking about in terms of developing our apps now or hedging for that future that we'll see?
David: [13:23] I don't think I have any special insight in that beyond what you probably know. It's been looming for a long time because it's been clear that it needs to happen, but it's really hard. It's just taken a while relatively speaking for it to come to fruition because there's a lot of complexity in it and there's a lot of code that exists in a world that's just not going to be compatible with it. It's the slow process.
[13:58] There's a real persistence to the difficulty of thinking about it. There's things that you can't do that it's hard to keep in your head that you can't do them. You continue to have code written that's not compatible. There's just a lot of learning left to do on that.
Joel: [14:18] In your ReactEurope talk you said something to the effect of Recoil will work with Concurrent Mode and the rest of these tools probably won't. I thought that was an interesting...Am I remembering that correctly? It will be compatible. Maybe in a base conceptual level.
David: [14:40] I don't want to make a categorical statement about other tools. Recoil is designed from the beginning with the intention of being Concurrent compatible. There's various choices in the API that might seem mysterious except it turns out to be big for Concurrent compatibility.
[15:00] We're not there yet. I can talk about what our whole history, like Scheduling and stuff, was. We are planning to support that soon.
Joel: [15:14] If people are curious, you have the documents in a public surface, but there's a lot that y'all haven't exposed yet in terms of undocumented features. I don't know where that's going. What's the cool stuff that's going to be coming to Recoil that isn't quite there yet?
David: [15:34] We don't want to expose stuff that we're not confident. We might want to change. We have some ability to change code internally with Codemods and that kind of thing, but once something is in the public, we feel like we don't want to change it unless we absolutely have to.
[15:51] The main things we're working on are more robust Persistence API or Observation API. This was developed for the specific apps that we were working on, what's in there currently. We're just going to make a more general version of that that takes away some of the specificity to those apps and lets you build a variety of different things. We're working on that.
[16:16] There's stuff to do with scaling it to bigger apps that have more state. GeoPad like thousands, tens of thousands of things. Zoom is inherent in the design of Recoil that is going to be a bottleneck, but there's just code that needs to be optimized. That's a big thing we're working on. Then the Concurrent and all that type of thing.
Joel: [16:37] What's the open source experience been like for you? Have you done this before or has this been a new experience for you?
David: [16:43] Pretty new for me. The only open source I've ever done is way back in the day I worked on the MediaWiki, which is the software that runs Wikipedia and a lot of other wikis. It's been really cool. People have made all these wonderful contributions, everything from translating the docs to fixing things, that kind of thing.
[17:07] Definitely trying to figure out how the logistics of it work, how the open source build system and that whole ecosystem works. It's quite different from the internal infrastructure that we have. There's some porting issues. Probably we should have that a bit more squared away before releasing, but we got it squared away now.
Joel: [17:29] That's a good way to get motivated too. Just put it out into the world.
David: [17:34] Definitely. People have been really supportive. I would say the response that people have has been awesome. Just watching people figure it out, and then I can look on the public Web and see code that's written in Recoil, and I'm like, "That's weird."
[17:51] I'm just used to seeing it in our own code and not out in the world. Then all of a sudden, I see it elsewhere.
Joel: [17:57] Have there been any surprises when you see people...? Has there been any sort of novel use that maybe...? I know it's pretty early for that but...
David: [18:06] Yeah, it's pretty early. It's been good to see that, generally, people are able to figure out how to use it correctly, how it's intended to be used with few exceptions.
[18:16] To me, one of the most fun things is that somebody will ask a question on GitHub, or Twitter, or whatever, and then, "How do I do this?" It's kind of a more advanced use. Then before I can answer, somebody else has already figured out how to do it correctly and can answer their question. That's just heartening to see.
Joel: [18:36] My friend, Jared Palmer, who writes Formik, he was showing me around some of his use cases. He was having this crippling performance issues inside of his app where it literally was...It's a whole form-driven app and these deep-nested components.
[18:54] He typed in them, and it'd just be stuttery and not good. It was suddenly he couldn't fix. There wasn't a solution, like off-the-shelf solution. Then he showed me after he added Recoil. All of a sudden, his app is very performant. It's working right.
[19:11] He's showing me how he's taking the selectors and doing all this wonderful selector before and after, and the async selectors, like bringing all the stuff together. It took his product he's working on, it's his livelihood at this point, and fixed it in a fundamental level.
[19:32] I was just like, "That's really cool," because his tool is relatively new. It just hit the sweet spot with React. I've seen a lot of criticism where React is like, "Well, that's too complex to be a templating language. It has a sweet spot, but then it's not performing what it has to do, like this heavy database style applications."
[19:48] Then all of a sudden, that curve got pushed in this direction. That has to be a pretty good feeling.
David: [19:55] I'm really happy to hear about that. Yeah, that's great. I don't think there's anything you can do with it that you technically can't do without it. They make it a lot easier.
[20:06] You talked about that spectrum between templating, this complexity spectrum. Something that I think is something to watch is compilation and treating React more like a language rather than something that is piggybacking on something else. It has its own...Can you take the whole literature of compilers and that kind of a thing and apply it to this domain?
[20:34] The million-dollar question is, can you have something that's a single language that is as flexible as React but then has a well-defined subset that can be compiled into a code that doesn't have to do reconciliation or anything like that, that can be very straightforward? You can mostly drop into that to get the full performance.
David: [20:56] two totally separate systems with separate mental models.
Joel: [21:00] I feel like people are working on that.
David: [21:02] Oh yeah, people are working on that.
Joel: [21:03] I've seen that in a few different places.
David: [21:05] I'm excited to see the work people are doing on that.
Joel: [21:09] Yeah, it's a really interesting way to consider it. We're bringing together a lot of different languages and approaches. It's a potluck of solutions but where if you consider, A, it's just a language for a speaking web. That's a pretty interesting thought to run down, for sure.
[21:29] Let's see. You mentioned patterns. I think about this a lot. I don't know how you feel about this. I've seen you mentioned the command pattern. When did design patterns fall out of favor in the general zeitgeist? Nobody talks about design patterns, or the command pattern or the Gang of Fourstar. Have you noticed that in my off days, or is that like a...?
David: [22:04] This is probably one of those examples of where somebody has an idea. Then the good parts just become assumed, and the bad parts are discarded or mocked. Lots of philosophers are like this over time, where it's like you think they're crazy, but the stuff that they invented that wasn't crazy, we just implicitly believe.
[22:26] The design pattern is like that. The specific patterns that are in that one book, they are what they are.
Joel: [22:36] Like you're not going to reach for the flyweight pattern or talk about that in a meeting because nobody will know what you're talking about anymore.
David: [22:45] Right. The idea that we have problems and that we can abstract over those problems and figure out transformations that's changed, that's solved those problems and lead us in a better place is something we're all doing all the time. I don't know how many people are familiar with the ancestry, that idea of design patterns in architecture.
Joel: [23:10] Like the Christopher Alexander.
David: [23:12] Christopher Alexander and that kind of thing. That's such a wonderful book. His book, "A Pattern Language," changed the way you look at the built environment around you. It's really beautiful.
Joel: [23:25] That even goes to what I'm trying to get at, honestly. I don't see that anymore. I don't see people trying to define and give...There's like a structure. They're like a recipe. To me, it even goes back to written recipes, like cookbooks. It's a book of patterns that are repeatable. You have this structure.
[23:45] I don't know. Maybe libraries are serving that purpose at this point. We're encapsulating patterns in libraries and naming them and documenting them, but is it valuable even at this point, or is it just something that's gone to the waste that...?
David: [24:01] People do that. They just don't use that word for it. On a React blog, there is a blog post that's called like "You Probably Don't Need Derived State." That's just a collection of patterns, but they don't say that. Lots of writing about programming has that form.
Joel: [24:21] Yeah, it's true.
David: [24:23] Maybe it's just the case that language about it got a bad name because of people...
Joel: [24:29] I feel like apps like Java, like J2EE has killed it, and people were like, "Uh-uh, just none of that. Thanks."
David: [24:35] You just can't call it that. People are still always doing that.
Joel: [24:39] It was like when Redux came out, and I was like, "This seems like I've seen these patterns before."
David: [24:45] In another era, you'd have a doorstop book. There would be a section called the reducer pattern. It would explain that whole idea. Then you could go write your C++ code or whatever that implements that pattern.
[25:01] Now, instead of having the book that explains it, you just have the code on GitHub and some blog posts and whatnot. The idea, it's almost more like an oral culture, right?
Joel: [25:11] Yeah. That's all it is. People just moved on and decided to name things differently. They picked the good parts of it. I don't know. Honestly, the whole idea of a pattern language will resurface, and come back, and hopefully be in a better form that doesn't make everybody sad and confused.
David: [25:33] Maybe that's something we're missing when it comes to what we were talking about before about people sort of cargo culting things. You have something like Redux, but maybe it's not emphasized when people are writing about it.
[25:47] This is the problem that it's meant to address. This is the transformation that it's meant to achieve. This is the context that should make sense. This is the actual idea of it separate from the implementation of it. Does that make sense?
Joel: [26:01] Yeah.
David: [26:04] Maybe if our language was more articulate about that, you wouldn't have as much of a problem with people saying, "Oh, this is what you use," versus, "This is the site that I'm building on. This is then what I'm going to do on this site."
Joel: [26:20] I've been so deep into this state management thing. At the end of the day, I am combining some ideas. One of my favorite ideas is from Jed Watson where he's defining the layers of state in an application. I don't know if you're familiar with how he defines them.
[26:37] He describes it as local state which is your component state, shared state where you're dealing with the application state, remote state where you don't control it and you're just asking and requesting it and often have to cache it, meta state which is kind of related to remote state.
[26:55] This one gets weird. You aren't the source of truth. It comes from somewhere. Who knows where that comes from? Then the router. At the end of the day, the browser and the router is some state that you have to deal with. It's like a specialized form of meta state because you're dealing with the browser. Don't break the browser.
[27:15] I was wondering, what's your mental model of a typical React application in terms of layers of state, and how do you think about them?
David: [27:26] You can add some additional types of state to that too.
Joel: [27:29] It's not exhaustive, for sure.
David: [27:31] Yeah. It was something Sebastian has talked about. It's like a state that's shared across tabs.
Joel: [27:36] That's a tricky one.
David: [27:41] Yeah, or things like that. I don't know that I would put the browser state or the router as a separate thing. In many web apps, changes in the URL are to do with very coarse-grained navigation. You're going to a different section of the app. Everything is going to be re-rendered.
[28:10] We have this router that's at the top of our tree that handles that. What we have to do for some of the apps that Recoil is used in is say that most of the state is going to be in the URL. That's the common case. We need a way to perform and keep that in sync without saying, "Oh, there's this thing at the top that handles this router. We're going to re-render these figs trees under it whenever that changes."
[28:35] I think of that as just an invertible function from the application state that we want to preserve to the URL. You just go back and forth. It's some arbitrary function. Then you pull out of that what parts have changed, and you set them. Then you handle that like any other state change. Then you just have to deal with our history and that kind of thing.
[29:03] You can use state snapshots to do that or [inaudible] between snapshots. It's the better way to go with that.
Joel: [29:06] If my understanding is correct, the URL bar then is essentially like a component. It's another...
David: [29:17] That's interesting. You could think of it that way. I've never thought of it that way. Maybe that's a good way to think about it.
Joel: [29:23] It's out of your control. It's the browser instead. At the same time, you are a part of the browser, your page is, which is maybe a little philosophical.
David: [29:29] There's a lot of tricky stuff with that. The browser API lets you save a state that corresponds to each entry in the back button history, but somebody could then refresh or still have that history but the states are gone. Maybe their browser crashed or something like that. You can't rely on that. You're just relying on the URL.
Joel: [29:55] It's interesting. I don't think a lot of people view it as being as stateful as it is. It makes sense to me. You did it in your demo. The way that you would carry that, and you can say, "Well, here's this state. All this stuff is in this place. Now we can just take this URL and place it over here, and it carries over," which I don't know that every app needs to do that, but that capability is quite interesting but complex.
David: [30:26] It's a key feature we're working on, which is data analysis app. People, they want to look at all these different types of views of this data and go back and forth. They want to send it to somebody else. "Hey, would you look at this?" All that kind of thing.
[30:40] That type of affordance is something we lose when we're going through the world of noble apps. Because there's no Chrome, there's no user agent, you just get whatever the app is built to do. Then you get these apps that don't even let you select and copy text to something like that. That's just a big downside.
[31:05] The people who are like, "The Web browser shouldn't have any features. It should be this minimal VM." There's actually some big upsides to having this featureful browser that knows a lot of the semantics of what's on your page because it provides a bunch of behavior that's uncommon across all pages.
[31:22] On the other hand, we're probably limited by the browser paradigm if you look at the navigation. I think Dan Abramov wrote a post about the navigation of the web is much simpler than the navigation of mobile apps where each tab can have a different stack.
Joel: [31:41] It gets pretty intense.
David: [31:46] You don't want to be constrained by that. There's also things you lose if you go to...There's things about it that we don't want to lose going forward. There are these escape patches for more powerful, more advanced use cases.
Joel: [31:59] I appreciate it, David. Thanks for hanging out with me and explaining this stuff to me. I'm so excited about Recoil and what it brings to the table and the gap that's filled. That's great.
David: [32:15] Thank you so much for having me on.
Joel: [32:16] Cheers.
David: [32:16] Cheers.