Joel interviews Michel Weststrate, author of Mobx and his new library, Immer. Today they get into the power of Immer, its early success on Github, common mistakes in state management, and what is next for Mobx.
Joel interviews Michel Weststrate, author of Mobx and his new library, Immer. Today they get into the power of Immer, its early success on Github, common mistakes in state management, and what is next for Mobx.
Immer is a light-weight, immutable state-management tool. Michel talks with Joel about some of its capabilities. Immer takes an object and a function and can track all the changes made to that object, it then gives you back the original object and a mutated copy. Immer can replace reducers, Michel calls them "producer" functions as they "produce" the new state.
Joel then asks Michel "what makes state management so hard for people and are they overcomplicating it?" This question leads to Michel explaining that people don't think enough about the structure of their state enough up front. When you talk about state, there are three distinct concepts, values, references, and identities. However, people tend to only think of state purely as data. "You have to think about what is going to store it and what is going to reference it."
Michel talks about how the mobx-state-tree fits into an application. Mobx is unopinionated; it doesn't tell you how to organize your stores. mobx-state-tree, however, is very explicit about the three concepts of state, values, references, and identities. With mobx-state-tree you organize your data into models and tell it how they relate to each other. It's all about consistently organizing your state!
What's next for Mobx? Michel is currently working on some exciting features using proxies to make Mobx even more transparent than it is now. Michel has also been thinking about improving on asynchronous processes and how to leverage async actionables.
"Michel Weststrate creator of Mobx and Immer Libraries for JavaScript" Transcript
Joel Hooks: I wanted to say first and foremost, thanks for MobX because we use it at Egghead and we really love it and it's made our development life better with React. I hope this quells some of the state issues that we ran into. So really and truly thanks for creating this awesome library.
Michel Westrate: Cool. You're welcome. Great to hear you that you love it, guys.
Joel Hooks: Yeah, I think it's really kind of, I don't know ... we'll talk more about state management because it seems like a running theme with what you work on. I wanted to jump into that actually, and talk about this library that you've released most recently and that's Immer, which is about immutability, but could you explain what it is and why it's interesting and why we might want to use it?
Michel Westrate: Yeah, Immer is actually a very small, neat utility. Basically what it does is, you give it a function or you write a function, and that function gets one perimeter and it's what you call a draft. It's an object and can basically store anything. It can be anything, it can be like your Redux stage, it can be your [inaudible 00:01:06] integration, and it can be your X stage, it can be your [inaudible 00:01:09] ... I don't know, any plane jump data you have, you can pass into it.
Michel Westrate: And then in the function, you give to Immer, you're just going to mutate that data in anyway you like. You can push new items to an array, you can introduce new attributes object, you can change attributes. I mean you can just do anything you would normally do in a JavaScripts. And then the funny thing is, as soon as your function ends and you look at the object you are mutating, you'll see that you got your original object back, it hasn't been mutated. [inaudible 00:01:45] data loss, keeping track of all the changes you are making, end of function. And then it produce a copy of its original state and applies all the changes to that copy, while keeping social sharing, if anything you didn't change.
Michel Westrate: And so the final stage ... if you write a reducer, this is usually difficult doing, so you are having a piece of state and then you start to produce a new state and you need to clog the tree to a certain depth until you can do your extra mutations. And so that whole bunch of depth is being removed if you use Immer.
Michel Westrate: You just do your mutation you intend to make and then Immer does all the copying of the rest of the tree, as far as it is needed for you. And its basically, it is inspired by the concept of right of copy, data collections, like you have it in Java standard library and also mutual shares or something. And what it does, it proxys old objects and as soon as you write something to it, it creates a copy of depths, data in the backgrounds and applies change actually, into some different place. But you won't notice because you can still risk mutations to share. So its a very small, but very mild agility and you got a lot of friction, I was actually, really surprise by it but I think the first two weeks, its already got to two thousand stars and get up, so its very interesting how to see it's being picked up.
Joel Hooks: When I was reading your articles on Immer, I think what stood up to me most was actually the use in the reducer because it reduced the reducer, I think that might be a fair explanation. You could use this any place that you might have a reducer, like in Redux for instance. You can bring this in, you really kinda help clean up and solidify some of the thoughts in there. Is that true?
Michel Westrate: Yeah. Exactly. Actually, I have some thoughts on how to make [inaudible 00:03:42] and in the end, I decided to call a producer a scan reducer. But also the idea that you produce the new states based on what you already have. And so that makes that very, naturally fit for using RE users.
Joel Hooks: Yeah, the other place I thought, this should be interesting to read assets, I probably learn a reducer pattern myself and then I've read a lot about state reducers now, where people are taking a state reducer and using that to manage local component state and seem like another place that would be pretty awesome for.
Michel Westrate: Yeah, yeah. I think with most applications, we still have to discover. Like the first application I follow was actually, something quite differently and it was to my webic complications, we have this configurations where you have for prediction and developments and they are like, for three quarters the same, but then there's something of dirt loader and the loader J which needs to be different from predictions or something. And that was actually my first application for Immer. I could just stop modifying the webic configuration I had, and in the end I didn't modify the original one but just got it fresh webic configuration for developing. And so the same, better you can follow the state reducers and reset state, et cetera, because its all basically, transforming one object into the next immutable version.
Joel Hooks: Alright so you don't need to use a user reducer. You can just use it, you run set state object and that's your state object for your component. That's pretty cool.
Michel Westrate: Yeah, exactly.
Joel Hooks: So, I mean, state, like we always, I guess it's part of our marketing, but it really speaks to the truth. I'm always saying "State is hard, we are dealing with state," and we have lots and lots of courses on Egghead that are about different ways we can manage our state. I noticed that you have a conference talk that was titled "State Management is Easy" and I was wondering, what do you think? Are people over complicating it or what is the reason that state management is so hard in our application?
Michel Westrate: I think the basic reason is that we don't think enough about how we want to structure our state up front. So basically, when you talk about state, you can distinguish three basic concepts. You have values, references, and identities. So things that are not used value, we don't also have identity. And the people usually think about state purely as data and such, passing data all around starting to store some pieces of data and redundant twice. That's where it get all hairy and tricky. So if you want to keep state management easy, the simple question you have to ask every time, is for every fact you want to know your application, who's going to store it, and who's going to reference it.
Michel Westrate: If you keep asking this question yourself, you will avoid treating the data and by that you will afford having still data and those kind of things. And I think one of the reasons, why something like Redux has become so popular is because it simplifies state management builds those three concepts. So it eliminates the concepts of having identities and also doesn't really have references, you have to manage those yourself. It just minimizes state management to having values, and it makes that one hand very easy because there's way less concepts to think about. On the other hand, you see that somewhere unnatural. How you can see that is basically, if you look at how we name our reducer, we call it something like "update to do title." When you look at the reducer, what it does, it isn't of anything to do title, it's like creating a new to do, are you replacing an old one.
Michel Westrate: So that is apparently how you conceptually think about things, is the things have identity, and to do, is the same to do even if you gave it a new name. This mismatch in having less concepts than there are actually are state managements as I think, why people call boilerplates. That's the mismatch between the conception of all you have of your state and the actual permutation of it.
Michel Westrate: Redux is also very appealing because it does make it easier by removing a few concepts. But I think the root core to making state management simpler, or simple, is just recognizing what are the values of your application? Which things have identities, like which things do exist through time? Which things should be referring to other pieces of information? If you can answer those questions, in the state you manage, then it becomes a lot more simple.
Joel Hooks: Yeah, I agree with that. To me the cost of Redux is like this boilerplate, this structure that we have to build around it and we have to have several files, and there's a level of indirection than can almost make it confusing, where you have your state management, but then you're kinda also adding this cost of some mental confusion in terms of where things are happening and what's occurring.
Michel Westrate: Yeah, exactly and I think, there's a chance, I mean it's also great in certain cases. I think what maybe helps, I have a background in Language Engineering and a lot of the languages I engineered prosper related around data management and data base design. I want to see that there are few recurring themes which are like set identities, references, also compositions, relationships, very important data bases. But once you think on those terms, then a lot of confusing about the state management disappears.
Joel Hooks: Yeah and for me, 'cause we switch to, like I mention in the beginning, we use MobX at Egghead, and to me, what it brought to the table was one, it removed a lot of the boilerplate that I was experiencing before. And then, at the end of the day, it feels like observable properties and lightweight dependency injections. So I get what I want, where I want, and I am able to, you know, add observable to a property, and it's just wash and kinda all manage for me. And as a user, that level of use is very simple. Is that the basic description, like the pitch from MobX? Or how would you describe MobX?
Michel Westrate: Yeah, I think it's pretty close. And actually dependency management is even really part of MobX, it like more patterned around this context because people had problems with depths and its part of the package, but it isn't really MobX specific. The most compelling thing about MobX, especially if you use their more complexity situations, it's not just observables, the effect the observables are being traced automatically for you so that as soon as you use observable, MobX captures that relationship. And in the background, at the construct, a complete dependency tree of how the data flows through your applications and that's why it's really make it powerful and something that's stuff like the antimeters are just dependency injection itself cannot offer. It's this thing that MobX can precisely track what data is relevance where. iI you change the title to-do, and that affects how many to-dos can be rendered on screen and that affects three different components, the MobX will track that precisely for you. That data has to flow in those places.
Joel Hooks: Yeah so, when I'm looking at it, it really, the look and feel of the thing is the simplicity. If I understand what you're saying, under the hood, it's also giving us performance optimization, right? It's managed in our almost black box management of our data and state and kind of affecting if we are using it in React or affecting how our components re-render and when they do based on this data that provides some efficiencies.
Michel Westrate: Yes, exactly. So, as a goal, when MobX was like, if you write the components, you should be writing it, as if you render it only once and you should be writing your application as if, of every change, your entire application would fully re-render. I mean when you write application as that, then you're dealing with subscriptions anywhere, anymore. Because if you will render your application, it should always be fresh, right? And so, that's what MobX tries to close. The gap in reality is of course, is you cannot re-render your whole application on every chance, but you can write your goat, as if that is the case and that's what MobX brings to the table.
Joel Hooks: Yeah, so you really don't have to think about it. You can just write to your observables and everything just works.
Michel Westrate: Yes, exactly.
Joel Hooks: So, do you ever in MobX, is there any use case where those two fit nicely together? Or is Immer general enough that you would just use it in a normal React application for your data structures?
Michel Westrate: Personally, I didn't combine them yet, anywhere, but I know that people sometimes do combine MobX partially with immutable data structures. So for example, they have a observable collection of to-dos. The to-dos themself, they are kept immutable for a different reason, maybe because literally you see observer and it should be change or something or because apparent application is still on Redux or it can be many reasons. But only in those cases there makes sense, you can combine the two, because with Immer you can manage the immutable parts. With MobX, you can manage the immutable parts. But beyond that, I didn't really cross lay them.
Joel Hooks: So you have another library kind of in this system of MobX and that's the MobX state tree. And I'm wondering how that fits into an application. We have a MobX application, we want to take it a step further and how does the state tree, how do we use that, and what does it do for us?
Michel Westrate: Yeah, so MobX in itself is quite opinionated on how you organize your observables, right? Where you put, where you store them, how you bounce them around. Like for MobX, you can introduce observables, or yet components, you can put them, I don't know, your module sculpt if you want to. Basically, MobX doesn't have any opinion where observables come from, it will just react to that. And for many that's very appealing, because you can basically design your owner section for application and you can somehow feel MobX in there and it will work and if you're migrating a big bone application or no contact application, you can manage MobX in there and it will also work.
Michel Westrate: That's for others, it can be confusing because MobX doesn't tell you anything on how you should organize your stores and your models, et cetera, and so that is where MobX state tree comes into play.
Michel Westrate: So that's a very opinion implementation, of how you could manage state with MobX. And so the concepts in state management I talked about earlier, like values, identities, references, compositions, those are all very explicit notions in MobX state tree. So the best part of MobX state tree is I think you create a domain model of your application, of your state. So you organize your data into models and you tell how the models relate to each other, which are contain, for examples introduce your contain your to-dos and you store contain users, that's users that contain to-dos, they just refers to to-dos for example. These are things you express on MobX state tree explicitly. And that helps you to, it forces you to think on how you organize your state, so hopefully, you cannot make accidentally a mess out of it, because you didn't think it through.
Joel Hooks: So we are getting an architectural layer, so we can learn and understand how a common or better way to organize your state, or at least a consistent way.
Michel Westrate: Yes, exactly. It's all about organizing your state in a consistent way. And also because it's very consistent and very regular, it can also offer more feature and books for you. A funny thing about MobX state tree, is that, it does also keep an immutable version of its store and so you can pass MobX state tree for example to the Redux [inaudible 00:16:58], and your Redux [inaudible 00:16:58] will learn what's happening in your MobX state tree, even though it's immutable. If you'll just think the immutable representation of it and the reason about that one. And that also makes easy to do things like when I'm traveling or in exchange patch this to a server, those kind of things. And so we can do that because you declare precisely, the model of your data.
Joel Hooks: I thought that those, like both Immer and Mobx state tree, in their documentation, kinda show you that you can use these things, basically anywhere, right? They come back to Redux to me, like we can use MobX state tree and they'll actually fit into a Redux app or you can use Immer and use that, to make your Redux app simpler as well as, not just MobX. So you're really creating tools or you generally useful more than specifically useful too, to the ecosystem.
Michel Westrate: Yeah. The funny thing about Immer and MobX state tree is that they both prove opposite points, opposite side of the coin. So MobX state tree is all about a mutable tree and it proves that you can treat a mutable tree as a immutable one by chiefly generating snapshots. So in MobX state tree you can interact either an immutable life of the tree, but just attributes or inject your fit into an immutable way and applying snapshots to get new versions of the tree. And on Immer, does exactly the opposite. It starts at a immutable world, then it allows you to interact with it in a mutable way and still at the end of the Immer friction, you are holding two immutable objects. Still very short of state, before and after it is executed.
Michel Westrate: So that's kind of intriguing too. Like combine those two worlds and both directions. It's quite funny, because people often, see it as opposite paradigms, and actually they can be reconciliated.
Joel Hooks: Yeah, that's cool. So you said you had a background in Language Engineering, I assume that's Programming Language Engineering, like from a Computer Science perspective.
Michel Westrate: Yes, yes, that's correct.
Joel Hooks: Does that influences these crusade you are on, to simplify state management for JavaScript developer?
Michel Westrate: Yes, definitely because what Language Engineering makes you think about is, what is the essential complexity and what's the accidental complexity? So what is the information you really need from the user? What do you need the programmer to express and the [inaudible 00:19:34]? And what is the information you could actually infer? So people call for example, Java, boilerplating, because it does not infer enough information once you are providing it. So you have the accidental complexity of needing to declare the type of a variable, while it could be inferred.
Michel Westrate: There are other type of an expressionist is in self essential, it somehow has a type what you want to re-use it essential information as much as possible. And so it was kind of this distinction between accidental and essential complexity is also what drove me to develop MobX. It just like, I want to write a components, but I only want to express essential stuff. And essential stuff being, what data does it trend there and how does my dome structure look like. And then the accidental complexity, the question is, what if there's other changes, how should have let it done? And that's the thing I try to entirely obstruct the way in MobX and React. And I think MobX gets really far in that sense, because basically the only boilerplate at least is putting an observer decorator on your components, that's the only thing you still have to do mainly. And all the other things, like how data is centered in your future to your components as it obstructed the way.
Michel Westrate: So, I think that background definitely, mainly wonder how can we write less, how can we write just what we want to express our thoughts, write anything that's just basically copy and paste on the course we want to do.
Joel Hooks: So what's next for MobX? How do you improve on what you already produced? Do you have ideas?
Michel Westrate: Yes. So first of all, there are some interesting developments I'm going to be working on and that's using more of the [inaudible 00:21:49] features, like proxies, because they can make MobX even more transparent than it is now. And at the same time, I'm brainstorming about, how can we make [inaudible 00:22:06] processes even better? So MobX has always been naturally quite suitable for [inaudible 00:22:14] processes, in the sense you can use asynchrobites or even generators without any trouble. But lately I was diving into, also quite a new concept, the async goals. I'm starting to wonder, how can we leverage those concepts? Can we express derived information as a generator, so that you can introduce more complex derivations mechanisms? Like you would do for example in RX radio, debounce, data retrieval, those kind of things. So it's all pretty early, but we're thinking about it.
Joel Hooks: And also, I was thinking just in terms of MobX and the future. Right now, there's a new version of React in Alpha that introduces this update data context API, which looks like it give us this kind of a pub-sub apparatus. Does that affect MobX or does it change it or does that provide any replacement for using a library of any sort? You know, or are we going to still reach for a statement in the library?
Michel Westrate: No, I don't think it's really changed anything. So what the new API does is, it fixes a few fundamental flaws in the current API which makes it hard for library alters to achieve interpretability with other libraries. So notorious sales for example combining [inaudible 00:23:44] and Redux, where Redux connects what prevents components of data, whatever component which prevents changes from propagating and [inaudible 00:23:55] wouldn't react to changes because it would assume that all changes would go through the complex API and through the entire tree. And so this is the thing that basically fixed and show you the improvements but it's not fundamentally changes anything on my opinion because it's essence ... it's not that you now can express things you couldn't express before. The difference is that it's now safe for anybody to use API, whereas API was for library authors only, that's a big difference.
Joel Hooks: It's a big red flags above it -
Michel Westrate: Yes, exactly.
Joel Hooks: That's about. If you're a user, don't use this.
Michel Westrate: Exactly, so that's a big difference but it's not like that it fundamentally changes something. In the sense, the suspense is more way interesting, cause that gives actually new way of self expressing things.
Joel Hooks: It looks like time flies and there's all sort of fun stuff coming up with the suspense-
Michel Westrate: Yes, exactly.
Joel Hooks: -on API's.
Michel Westrate: So that's-
Joel Hooks: Do you have any ideas burning for how you wanna use this stuff? Have you started looking at it at this point?
Michel Westrate: Yes, I started looking at it. Not sure entirely how I am going to use it. So the thing is for MobX utils, of MobX royalty goods, already gets quite close to suspense in that sense that you could already render promises on a very concise way into the doc. Thus, small utils packets, called MobX utils and it has its concept of turning a promise into an observable, so you turn promise into an observable and then you can render based on the failure of the observable, which is what you do everywhere with MobX. So in that sense, rendering promises is something which is already quite common on a MobX world.
Michel Westrate: The interesting thing, of course, in suspense is, it got four of the rendering tree and that's very interesting. It can render a component which of essence is feasible in the dome yet, and so instead of seeing that components transitioning to the difference common states, you won't see the components anywhere until the promise is settled, for example. And in the meantime you can inject with another block of the, there's another rendering of the tree, by the previous version. And that's what make suspense very interesting.
Joel Hooks: Yeah, I'm looking forward to seeing how the stuff shakes out. Its cool to see the framework of all a little bit. What are the options that will give us as developers and then for library authors like yourself, it's really exciting. I always like to see how people push the envelope and give us cool new tools to make our development lives much better, which again, thank you to that, Michel.
Joel Hooks: I am going to call it and really appreciate you taking the time to me today and I look forward what's next.
Michel Westrate: Cool. Thanks a lot.