 Thanks. Thanks, everyone. So this is resources squared, or otherwise, and hopefully, resources on resources, what I believe to be a core primitive when it comes to reactivity. And that doesn't mean just forever, but first, a quick introduction of myself. Online, you can find me everywhere at nullvoxpopuli, and at the bottom here are some links to projects and just where you can find me. So this presentation will have a lot of links, and it's written to still be useful and have all the context when it's uploaded and read. However, when live links aren't very helpful, so almost all links will be represented by QR codes, and most of what I'll be linking to is documentation and live demos. Now QR codes can get a little squirrely. So I did test this, so it might work, but if you're in the back of the room and you want to be distracted while I'm talking, feel free to move closer so you can scan the QR codes. And if you're online, make sure to get your phone out. I like doing things while I'm doing things, so QR codes are good stuff. I'll also upload the slides to GitHub afterwards. All right. So you didn't get to see that, or this, or the video, all right, yeah, look at the QR codes. Oh, man. Okay. All right. So here's a list of things I've done over the past couple of decades, TLDR, I've done a lot of things, and I've used a fair number of technologies, and I've been using Ember the longest so far, chat GPT most recently. So on the left is a picture of my partner and favorite human. She is the best. Outside of programming, I like swing dancing and video games, and this is a screenshot from Beat Saber, a virtual reality game. So I have some disclaimers. I'm going to try to get through these real quick, but some may consider parts of this talk experimental, and that's okay. There are certainly gaps today. We need more learning materials around resources, patterns, in and outside of Ember. We need to actually implement StarBeam for Ember, and for those that only stick to what is in the official documentation, this may feel experimental and out of reach. However, to help mitigate that feeling, I've been working on some learning materials and tutorials. I'll be working to help close those gaps, and I'll try to answer anyone's questions and provide help. Wherever you think you need help, I want to try to be that for you. The goal here is to solve real problems more efficiently while also reducing cognitive load on everyone writing their Ember apps. All examples are going to use the new GGS format. Thankfully, we had a talk on this yesterday on this new format, but here's a quick TLDR, maybe recap, for converting between the old and new in your head. Whenever you see a template block by itself, that is most similar to a template-only component. The key thing here is that it's always a component, and you always know where things are defined. Whenever you see a template block within a class body, that's equivalent to a glimmer component with a class, normally two separate files. The idea is that it does not make sense for templates to be a separate concept. Both examples are full-blown components. It's only a matter of if the component has its own state. All of this is my opinion, but I'm committed to these opinions, and it's not to say that these opinions are not shared by others, but I genuinely believe that they make not only our ecosystem stronger and better, but the concepts benefit all ecosystems outside of Ember as well. There's no RFCs for what you're about to see for becoming part of the default blueprint. However, I do plan to bring these concepts to the default experience, and I'm starting an RFC when I get home. Okay, last disclaimer, I promise, it's extremely important that there are easy migration paths within the community. Programming is hard, and some migration paths are not and have not been so easy. The overall goal for everything I'm working on for and around this talk, resources, et cetera, is to be a polyfill for Starbeam. Ultimately, I want Starbeam to be the resource implementation we use. But in this talk, I demonstrate with the library Ember Resources, because you can install and use it today. At the moment, I haven't written any code mods, because there are still some designed details to work out with Starbeam, but any behavioral difference between my library Ember Resources and Starbeam should be considered a bug. I am committing on keeping support for Embersource 328 for as long as I can. I know a good number of folks were caught off guard by the number of deprecations that came up during the V3 series. I think I heard there were like 70 deprecations or something. That's a lot. So I want to make sure that folks who are still on V3 can use the patterns coming in the future. So getting back to it. With the introduction of Ember's first edition, Octane, a new reactivity system was introduced. Tracked properties. By the end of the 3x series and leading up to V4, we had two user-facing reactive primitives. At tract and functions. In Ember Octane, it was assumed that all reactive state or root state, the very root of what auto-tracking pulled on, would exist on a property and a class, which would then be decorated with the at-tracked decorator. This use of a decorator allows for a hidden getter and setter so that the reactivity system can still operate while allowing native access to those properties. We'll see how this works later. So in Ember Octane and before, functions were called helpers. It wasn't until Ember Source at 4.5 that plain functions became supported as a reactive primitive without the polyfill. However, helpers, now called classic helpers, had two implementations. A simpler function-based version and a class-based version. These both required framework-specific abstractions to use and build. But the class-based version of these classic helpers had clean-up capabilities, though awkwardly via inheritance. So what about modifiers or components? We'll come back to these later, and yesterday you may have seen something in the keynotes that may allude to what is coming. For components, though, I'm going to propose that there are not primitives at all. But first, I'd like to propose that we as a community rethink reactivity in general. Instead of at-tracked, let's think of and redefine these as values, making the at-tracked decorator a user of reactive values. A value is the most basic kind of reactive primitive we could possibly have. These can exist within functions, outside classes, anywhere. And this will be a theme throughout this new way of rethinking reactivity. For function-based helpers, we can just use plain JavaScript functions. Supporting plain JavaScript functions as a reactive primitive, as well as their arguments, is essential for reducing the number of abstractions folks need to learn when they learn number. For class-based helpers, we can use this new primitive functions with lifetime and cleanup. This allows us to compose our value primitives for managing state throughout the lifetime of the parent object. And then we can have optional cleanup. We'll expand on both of these concepts momentarily. For a couple of these, though, we still need abstractions because reactivity is not built into the browser. We'll call values cells, and cells provide the abstraction with which we can build at-tracked, and allow us to use reactive values everywhere, not just classes. Functions we can leave as is. They can directly access the state on cells. These will auto-track and are completely transparent to the renderer, just like getters within classes. Functions with lifetime and cleanup are resources. These are the key abstractions that we'll focus on for almost the rest of this talk. All right, a few slides ago, we hand-waved over the fact that at-tracked extracts a secret value. Here are the secrets behind the hand-wave. The secret value can be thought of as a cell. All right, so what is a resource? It is a unification of a lot of concepts. In Ember, they rationalize class-based helpers, modifiers, services, and routing. Outside Ember, they rationalize hooks and eliminate the need for effects or help eliminate the need for effects. They allow you to derive data in ways that previously would need effect-like behavior. A resource's reactive function yet represents a value. It is bound to a lifetime and may have cleanup. So what does a resource look like? This is what they look like when using Ember resources, which you can install today, all the way back to Ember 328. You can do this. For this particular resource, we create a value, a cell. This represents the current date time. We can set up an interval and clean up the interval when the resource is cleaned up by whatever the parent context may be. In this case, it is a small component. Lastly, the time is returned. The renderer inherently knows how to render cells as their values. Looking at the code snippet on the slide here, this is the star beam version. The only thing that changes is the import. So this is the anatomy or layout of a resource. You set up initial state, provide optional cleanup, and then return the value. We can configure arguments, and this is probably one of the bigger differences between Ember resources and star beam. Due to how Ember's plain function invocation works, we need a wrapper function to handle receiving arguments. This is because Ember doesn't have a public API for tweaking how plain functions are invoked from templates. It is intended to just be a function, though, and making it just work will be the process of implementing star beam. There's nothing magic going on here that a user of this would need to be concerned about. When resources land natively in Ember, this wrapping resource factory won't be needed. So cleanup is useful for cleaning up event listeners, canceling observers, timers, disconnecting from web sockets, maybe freeing up memory. Bunch of things we could clean up. So far, we've been looking at a clock example where the interval needs to be cleaned up. Let's take a look at another situation which may need cleanup. Now, cleanup in general is a concept we're likely used to. Components, modifiers, and class-based helpers all have a will destroy method. If you're the type of person who likes using features as they're released into the framework, you may have seen at Ember destroyable. Cleanup is co-located with setup. This is an improvement, but we can do better. So resources have more ergonomic cleanup. It is co-located with the behavior, which is a goal that will destroy methods didn't know to care about yet. And there are no additional imports, which leads to better intelligence and editor assistance around this API. So resources have a lifetime. What's a lifetime? An application has a lifetime. It has a start and an end. And during testing, oftentimes, you have one application lifetime per test. It may even be a stripped down lifetime, only what's needed for rendering a component. But you could visit a route during the lifetime of your application. That route could be thought of having its own lifetime as would the components rendered within that route. This precursors all the way down the rendering tree. Along and within that rendering tree, we may have a resource or it could be a component that fetches data for this route. And when the parent lifetime ends, so do its descendants. Now, when working within the framework, we need to hook into the application owner for access to services and set up the destroyable relationships to the appropriate lifetime. If you've ever done this yourself, it is a lot of work. So here's what the code looks like if you wanted to link up to a custom class, to a component, so that then gets the owner and has this destroyable method called when the component is torn down. We have that cached, we have set owner and get owner, we have associate destroyable child. We don't want to do any of this. This is a lot of boilerplate. Resources do this for us. When we use a resource, it automatically has an owner. We get linked template invocation for free and it automatically has the correct destroyable association regardless of where it's used. So when it's used in a template block component or within another resource or service and that parent template block component resource or service is destroyed, so will that resource be also destroyed? So resources can easily be composed together. They abstract away the details and inner workings of the framework that would otherwise be exposed to your apps. Using our resource that represents the current time now, we can define a new resource formatted now. We can compose now via the use function and it renders in a component the exact same way. Okay, great, but why does any of this matter? Resources allow us to implement concepts that we are familiar with, but with greater ergonomics. They allow us to define how data or state is derived with the flexibility of optional cleanup. This represents values. We've seen the clock example where the value is the current time. We can manage the lifetime of modifiers, services, routes, and not only do resources allow us to implement all these concepts in a coherent and concise way, rationalizing all these different things together. They allow us to bring our reactive concept to the broader JavaScript ecosystem, which is the goal of StarBeam. So let's start with examples of resources as values. And before diving into this example, I'm sure the first thing you noticed was the static on the right. And if you're wanting to scan the QR code, it redirects you to a REPL or a playground where you can start poking around this and try to find bugs to call me out on the code that you see. But yeah, let's see. So this is representing a clock just like before, but implemented the old way. It has a number of problems. Our time value is bound to a component, so we can't tear down our interval at any granularity smaller than a component. I'm sure you all have seen components that do too much. And this pattern adds to that. The tear down and set up are disjoint. There is a life cycle hook you have to know about since components lend themselves to be overburdened with responsibility. It's very easy to intermingle different behaviors, clean up and set up all over the place within a component. And here we've hacked in a life cycle event via a set once property. The getter is still reevaluated every time underscore time changes. And if we were to add tracked data into here, we're at potentially a high risk for a memory leak. So here we can already see that this looks way less complicated. Set up and tear down at the interval I co-located, the entire construct is focused on a single responsibility. Tear down occurs at the curly brace level where time is used rather than at the component level. The lifetime for this resource is the curlies. And lastly, if we don't need a bespoke life cycle via set once property. And here is that code rendered. On the right here, you can see that time is progressing slowly, I hope. So now let's compose this interval like we saw on a couple slides ago. So here we compose using the use utility given to us by the resource and format the current value of the time resource. I've set up an argument receiving function so that we can see how to use this composition to make it more reusable, yet configurable atomic concepts. And here is what that looks like. At the top here is the original time providing resource and then we can compose it just underneath. This is using the intildate time format built in utility and then just rendering the current time in four different locales. So in this example, let's say we want to know the most recent person to have visited Tatooine, a desert planet in Star Wars franchise. We can assume that the method of retrieving that information exists and that the implementation might look a little something like this. This isn't a lot of code, but it does require scrolling. So we set up a socket and subscribe to messages. Then we define how we want to format the last message. And then handle cleanup. And like with the other demos, there's a common theme of responsibility leakage. With components, it's very easy to accidentally make a component responsible for more than one thing. And what we want is single responsibility concepts that represent the value, which in this case is the most recent person to visit Tatooine. So when using a resource, we have much easier time managing socket information. Cleanup is straightforward and co-located. We can manage state in encapsulated fashion and we can define a sort of getter for formatting the output. This QR code's a little bonkers. So the output looks like this and is it updating. There it goes. Okay, this is using the Star Wars API because it's free, it's pretty good. Okay, here same as before, we have a long file and it's quite a bit of code. Let's see what all it does. We're trying to handle loading state, error state, reactivity. We want to have a stable reference to the state so at cash is needed. We also need to handle cleanup and the combination of a board controller plus we'll destroy, but also reactive cleanup as the URL argument changes. Kinda looks goofy. So when using resources, we can co-locate and focus on a single responsibility. This code doesn't scroll and we can handle all of the capabilities that we mentioned on the previous slide. Loading state, error state, reactively responding to URL changes and canceling the request when we no longer need it. So here's what that looks like. Let's see, there's a bit of extra code in here. If you go visit this, I couldn't make it a QR code because the URL was too long but browsers are fine with that amount of URL length. But I'm scrolling through the code just to prove it's not smoke and mirrors. So what's super cool about using resources to manage data fetching is that you can compose them just like we did with the current time and you still get individual reactivity per resource. So here we configure remote data on three different endpoints. Note here that this uses an example you till from Ember resources, remote data. Fear not though, Ember resources is a V2 add-on so if you don't import it, you don't pay for the bytes. Now when rendered, it looks like this. On the right, you can see that each request for people, planets, and starships takes its own amount of time to load and it just so happens that the Star Wars API only returns 10 records at a time. This is as fine grained or as combined as you need. Some UX patterns may want fewer loading indicators than what you see here. So in Ember, there are a couple places to load components, in routes and not in routes. Loading data outside of routes is immensely useful and you'd otherwise be forced to drill props through countless layers of components. Some folks imperatively manage data as properties on a service, updated from routes, but this is troublesome due to how error-prone unencapsulated behaviors are. A common thing developers reach for and something resources make easier is fetching data within components. However, if not properly managed, this could lead to the N plus one data loading problem where you render a list, that list renders a component where each item within that list yet makes another request. Today, this could be mitigated by making the implementation of some data fetching resource. Use a backing service to manage a shared cache between the resources and then batch those requests together to minimize the number of requests. In today's keynote on Ember data, we saw that Ember data's request manager can be that cache. There will be demos of this in the near future. And in yesterday's keynote, we saw that resources will soon power the next generation of route loading behavior and mitigate waterfall data fetching, which is very exciting. We've seen that resources can be wrapped in functions to reactively handle arguments and we can extend that to modifiers. This is supported in Ember resources as of this morning and here we are doing a little animation effect on an element. The important thing is that this resource is the same as any other resource. It's the same API. It's only wrapped in a function that receives an element. And then whatever args you pass to the modifier and this is what the animation looks like. So now for those worried about bundle size, fear not, Ember resources is a V2 add-on. So if you don't import it, you don't pay for the bytes. All right, so we know that resources are bound to a lifetime and that applications have a lifetime. This means if we install resources on an application, the resource effectively acts as a service. We can define a resource that has some state. For brevity, the state will be a number, but it could be any service you can think of. With this resource, we can return a getter to get the current value, as well as a method to increment that value. But this could just as easily be an instance of a class. We can then create a component which then uses the counter resource here. This decorator is what does the linking between the resource and the overall application. To demonstrate that state is actually a service, I've rendered the component three times here and here is what it looks like in action. You can see that all the buttons share the same state. So can a resource also be a component? Well, kind of. If you like React, it may look like this. Returning a template only or presentation or stateless component as their value. Using the closed over function within the resource as the state. However, the main thing is that every framework already has really legit component implementations and those implementations are really good at what they do. But we can do it too. You can see, however, that at the bottom of the code snippet, in order to get this to work, you have to invoke the resource like a function and then render its return value. But this is only a component manager implementation away from actually working as a component. And it really shows how useful the template syntax is. I mean, this wouldn't be possible at all with the classic two file syntax. This is one of my favorite quotes about doing goofy things. But science is pretty fun, so let's keep going. So here's what the demo looks like. You can see that today the resource still needs to be invoked like a function and if we only invoke it once, each time we render the component, the return, each time we render the component return from the resource, they share the same state. I don't know if this has any use cases, but an important thing to note is that the function returns a component. So we could adapt this to a component manager and have the invocation happen automatically, but I just don't know if it's worth it. But if people really want it, I guess I'll make it. So let me know. So I mentioned this a while back and I want to revisit this idea. Components are not primitives. So recapping what the primitives are, we know that from Ember octane and now that we've renamed some of the primitives that octane introduced, we have values, functions, and now resources, which represent the value bound to a lifetime and rationalize class-based helpers, modifiers, and services. And these can all be authored and shared anywhere. And that's the main goal of Starbeam. We can write our application logic once, whether that's data fetching, UILogic, modifiers, anything reactive and just use it. And it's not only for Ember, but React, Preact, View, it's Felt, anything you want to use. It's super exciting because most other frameworks don't have modifiers. And as far as I know, none of them have resources. So components wrap the primitives. Components are refactoring boundaries. They are containers for organizing higher-level concepts. And the word resources may be a bit overloaded depending on your background. I don't know if anyone saw in the Discord chat yesterday, but there was some goofy wordplay happening. Yeah. So there's this other thing. If you pay attention to TC39, resources are also a concept in JavaScript itself. The proposal is stage three or in the implementation phase. The JavaScript resources have a similar purpose. They provide a means to manage the lifetime of an object. Ember and Starbeam resources provide reactive implementations of this concept. And it may make sense for the implementations to build on top of JavaScript resources once they are shipped. And here is what it looks like in TypeScript from Matt if you're a Twitter person. Okay, so what's left? Mainly, I need to do more work on Starbeam itself. I need to get it into Glimmer. I need to write some code mods for folks using Ember resources to get them over to Starbeam when that's a possibility. And I need to put up some RFCs because I mean, at least I think that the whole way we're thinking about reactivity has become a real cohesive story and is quite a bit more buttoned up since Octane's release. So in much the same way that promises are better than callbacks, resources are better than effects or other ways of working with lifetimes. Some last thoughts I leave with you before the end here is derived data is really good. Resources help you model any situation as derived data and resources are not effects. Someone has to pull on the resource for it to begin executing. And resources are part of a plan to bring Ember's reactivity to everyone through Starbeam. And you can install this right now and get started before I walk off stage. So if you wanna use the live editor or REPL Playground I made, it's here on the right. The left is a tutorial which includes resources as well as GJS. And it teaches other concepts that I think are really important for people to know writing Ember applications in 2023. So thanks for listening. And as always, you can ask me anything at Melvox Popular. Thank you.