How many times in your developer career you forget to remove an event listener? Close web socket connection? Unsubscribe from updates from any source? Or you are just to run some cleanup tasks, but every time you should do it manually. In this talk, I will show a new concept “Lifetime”, which will change your mindset about solving the problems above, make it all easy and even automated. I will show how I use it in everyday development and how it makes my application better and secure. I will also show how it improves DX and productivity. And I believe it’s something your team might want to use too.
Less Struggle With Lifetimes
Transcription
Okay, so my name is Igor. I'm a software engineer at JetBrains, and today I'm going to tell you about the Lifetime simple but powerful concept that we use in our applications. So to give you some background, I'll show you this piece of code. I'm sure you're all familiar with them, and maybe you as me were annoyed sometimes and wondering why all of this don't clean up automatically. We have to write all this boilerplate code again and again every time we add an event listener or subscription or something similar. And yes, I know why we need to do this. We have to write all this clean code to avoid memory leaks, bugs, and sometimes even risk conditions. I'm sure that you all don't want your app to work unexpectedly because something wasn't removed before. But we are engineers, and our day-to-day job is to make manual routine to be automatic. All that that I've showed you can be handled by something. And in our application at JetBrains, we call this something Lifetime. What is Lifetime? In a nutshell, just a simple object to which we delegate doing all the cleanups. So as you can see, it has two states, either terminate or not. And you can always add any number of functions which will be called after termination. It looks very simple, and here is how we use it.
So basically, you need to write a wrapper around some api, like event listener, subscription, et cetera, and bind the cleanup to a lifetime. And yes, you still have to write your cleanup code, but you see you do it only once, and then just reuse it everywhere. Just the same for you as writing the react component. Still looks very easy, yes? And then you just use this function, pass lifetime there, and that's it. But the major point here, as you can see, that you still have control outside in one place. So you decide when to terminate all of this at once, and you don't need to define the cleanup logic in some other places, because you already have it here. And just like it, all your boilerplate code is now replaced by one line. It's called terminate, and all your cleanup functions will be called. So you don't need to think about when something will be dropped. It was all automatically done for you.
And as I said, you can call your lifetime termination whenever it's needed. So like here, you can bind termination on component unmount. It's very basic, and I'm sure it's very useful for most of you. And because of the simplicity, you can compose it with almost everything. So having all the lifetime logic in one place helps you to make your code logic more scalable. So you can even extend and create your own different types of lifetimes. And now I can just show you a couple of advanced examples of it. So here, you can create sequential lifetimes, which terminates the current one when you create the next lifetime. Like here in this example on the right from me, every time you call next, the new lifetime is returned, and the previous is destroyed. It could be useful in a situation when you fire the same request multiple times, but you want all the previous ones to be canceled. And for example, you can also use it in a user failure, because on every effect, you might run new effects, but clean up everything from the previous iteration. And here, you can create nested lifetimes. And for me, it's the most powerful thing, because you can create this lifetime change, so even lifetime trees. So you can even represent the whole application as such a lifetime tree, and to put all the dependencies, like describe declaratively. And you don't need to worry about terminating all of them at once. If the lifetime at any level is terminated, all its nested, and then nested, and then nested are destroyed too. And that's actually it. That's all with the examples. More of them you can find on the GitHub repo, as well as the core library and some wrappers. There's a link on the screen. And there is also a link to our JetBrains protocol space, where I work. And also, if you want to grab some JetBrains stickers, I think I still have one. And that's it. Thank you for listening. I'm Mike Pearson, and I'll see you next time.