Video details

Model-View-Presenter with Angular | Angular Performance Best Practices


Lars Gyrup Brink Nielsen & Stephen Fluin

1. Lars Gyrup Brink Nielsen - Model-View-Presenter with Angular 2. Stephen Fluin - Angular Performance Best Practices Debugging the Performance 5000+ Angular Apps To build the best user experiences we need to build fast applications. At this point, I've analyzed over 5,000 applications. Come and learn about the best and the worst standards and practices across the industry, and what you can learn from what everyone else is doing.


Welcome to my presentation. It's a very special one because it's the first one I ever did in public. It's called Mulvehill percent of what Angela? And it's I really love design patterns, and one of the first things I did was trying to figure out how to get a better separation of concerns. But we'll get to that in a minute. First, let's briefly last break, don't mind the four names, just call me last spring, told us the other ones are family names and the father of twin girls. I live in Denmark. I'm a writer at In-Depth Tech Speaker and podcast, host for the Deep Dive. I contribute to this from time to time. And I'm also Microsoft MAPI. In my day job, I met from that architect, that system made in Denmark. And that's the logo in the bottom here. First, let's get an overview, there's three main concepts you need to learn to be able to work with might be a presenter and they kind of said that in the name. In our case, though, I tried to adapt it to Angela. It's an old pattern or not old in the history of computer science, but it's started in the 80s and 90s. So in our case, I adapted it to show that the model will represent. The application state, the view is a component, but it's a very thin one. And complex behavior like logic will be living in something called hypocenter, which is just another class, as we'll see later, the reason for a model built here is to structure your code in a way that where you can separate your different concerns. Many of you have probably seen the horizontal layers like these four. So these are one of the common ones, but you could even go further and categorize it like this. And so on the left hand side, we have the the different categories or the different layers or different concerns that you code has to worry about. So in the right hand side, we have examples of of what could be in this layer. So the way I like to structure it is that a piece of code should only be concerned about exactly one of these categories. And it should be on the same abstraction level, so you need one, for example, high level business logic or low level assistance, but not both. And you also don't want low level persistence, logic and high level persistence logic in the same file you'll have to structure. Around that. So anger when it comes to angular components, they will be they will be in some of the bottom layers here, presentation, presentation and user interaction. But if you. Apply this pattern very strictly. You'll see that even the user interaction will be abstracted away inside of a presenter class. So what you end up having is an application that is highly maintainable, it's very testable, very easy to test, it's scalable in terms of an application growing and becoming more and more complex. And it'll also be performance because you can apply some performance benefits while using the structure in the code. These are the three parts of the pattern. The model is represented by a container component, maybe a lot of you already noticed patterns, at least a container and a presentational components, a container component is where we map the presentation layers of our application to non presentational layers like application state and IO devices and persistance. So we do this so that we can have presentational components that are not worrying about anything except presenting information to the user and allowing them to perform user interactions to change the application state or other side effects. But the prison, even the presentational component, when using this approach will be a very fine plus, it'll just be mapping to present their methods and mapping percenter purposes and efforts to input and output properties on the component model. And when you do this, you. You follow this pattern of optimizing for testability, most of your at least your complex logic will be in a class that has barely any dependencies. So you can test it in isolation using unit tests. That gives you a high level of confidence and you can even reuse them across framework's. Or across different components. This is an example of and I hope it's visible on the screen and on the screen because it's an animation. Is an example of the human directional data flowing and angular represented using this pattern model percent or so on the left hand side. We see some state or some data coming in from whatever layer of the application that flows through some service class into the inner component. It reaches the presentational component. It's handed over to the presenter class, back to the unique properties of the presentation of components and mapped onto the are projected onto the template of the component, which in turn updates the DOM of our Web application. And going in the other direction, a user could, for example, click a button to change the application state so that interaction from the user will be covered by an event handler to be forwarded to the presenter, which will. Emit a value from something maybe into the subject, and that subject triggers an output property on the presentation component. That is intercepted by a container component which forwards that data and some representation to to a service and then some side effect happens in another layer of the application. So this is this pattern is focusing strictly on the presentation layer of our application. Here's another example, if you want to take a more complex component, so here are split a table into a bunch of different components. So connecting it to the rest of the application, we still have a service and that serves as a dependency of the table container component. The table presentation components then has components. One for each row and each row has a presenter class. And something happens in one of these roles, some text is entered by the user, for example. So we see that same flow of states moving up the componentry hierarchy. So it's just to give you an idea about what the structure of this looks like at an abstract level. To tell you something many developers are using are familiar with. I took the two of heroes tutorial from Angolite and I applied this pattern to the repository so you can go and look for yourself and have a look around the code and see what this looks like in practice. In this presentation will be refactoring some of the original components to use this pattern. The first one will be looking at here is the container component, and because of this nice format of this event, I'll actually be able to show you step by step how to restructure your existing components, because it's important not only to learn the concepts, but actually also see how do I do it in practice, like you're talking about all these layers and different classes and new concepts that I might not know about, but I have an existing application. How could I use this, Peller? Well, let's take this dashboard component from the two of Heroes tutorial as an example. So we see here that it's it has a dependency on the hero service. It initially gets to hero service, the hero data from that hero service. And it takes a slice of them, the top four, I think, to display it in a dashboard, so it's not all the heroes, only the four top ones after them. But anyways, let's see how we can extract some of this code out and turn it into a container component. First thing we do is create another component glass, as we can see here in the top. Next step is we actually just cut some of this code. We do that for the constructor. With the dependancy sort of take that out of the existing dashboard component. And then we we used just an observable property called Top Heroes, and we're not even subscribing to anything here, so it's perfectly fine in any consideration to just assign it in the property since it doesn't have any side effects, is just setting up the pipeline. The pipeline, as we can see in the bottom, we're actually extracting all of the code from this original dashboard component except for one property, even the life-cycle hook on. And it is also removed. And it's not even present in the container component because we don't have any side effects. And the component model that will be handled by the component template, as you might have guessed. And we'll see that later for now, as soon as we complete, the step will be left with just one property. And as you can see on the left hand side of the slide here, the first step is to what we just did. We isolated and extracted the integration with non presentational layers. And we put that into a new container component. And the second step is, will make sure that the container compound component model will stream the data from the application state through observables to the presentational component. That's what we do now. So we to do that, we need to connect. We already have the absorbed stream, but now we need to connect the container component to the presentation of component using data bindings. So first step here is we used the async pipe, for example, or some of the the new push pipe and or the let directive. Not just to push pipes could be used in this example. Excuse me, so we bind using the property binding, we point to the hero's property of the dashboard component from the template of the container component, as we see here in the bottom area. We also want to make this dashboard component a reusable component, and we could do that by providing it any set of heroes and just pausing at a different title. So we'd actually like to add a title here and call it Tupamaros. So now we need to implement the presentational component part of this, we already moved a lot of logic out of the original cast and this is what we're left with. That thing was the bottom is still the container components template, and based on this, we can see what what data we will be accepting from our parent component. So it's the hero's property that we already have. So we will need to mark that as an input property, of course. But we also need to accept the title property as an input property from our parent component. But first will change the selector from app dashboard to app dashboard UI so that the components using the dashboard component will be using the container component. And we don't have to change their existing templates, so it's just if you come up with a better name, this is just a suggestion to just put a patch UI on there to represent that. It's a presentational component, but you can call it anything, really. Now we're applying this and put decorator's to our input properties, so we have the hero's property and we have to title property. And after this, the next step is we have now declared the data mining API of our presentation component. So the next step, as we can see on the left hand side, is we not want to make sure we're using just minimal presentation logic in the component template and the component model as well of this presentation component. But not for a minute that in the component model, there's no observables, there's no subscriptions, there's not even a life-cycle hook. So this class is very simple. There's barely any logic going on at this point. It's just a data structure for sending data to the user, mapping through the component template. And. Well, if you want to be really thorough here, we would actually extract out the router link because it's just a magic string floating around in our template here. So this is not easily testable. So we could put that in a constant or whatever, but for the purpose of this presentation, let's just leave it here. Because what we're looking at here is actually the template of the dashboard component, the presentation one. Would you say that this component could support on push change the election strategy now? I know there's a bit of a delay, but the. Please put your answer in the chat and I'll wait wait a moment, does this component's support change the U.S. strategy on Bush? I see some hello's. Who wants to guess yes or no on push change detection support at this point in time? No one wants to take a guess, I'll just continue. So, yeah, it does actually, of course, we need to put in that change detection property here. And the sorry, I can't pronounce your name, the person with a P is saying, yes, you should use the on push here now and you're right. So it does actually support change detection on strategy, on push. We just have to put it in the metadata after component decorator here, as we see now. And Michael, I. Santoshi also says yes. So you're absolutely right. There's just a bit of a delay. So as you might know, the unposed change detection strategy improves the performance of our application, especially when applied across most of the application, because it disables some of the dirty checking during change detection, because it simply checks to or sorry for saying simply it's not easy to understand. It's actually a lot going on. But when it comes to this component, it'll just it'll check whether the input preferences have changed. Using a referential comparison, and if they haven't, it doesn't have to go and dirty check all the bindings and the template and bindings to the components of this one. So that's actually a pretty easy performance optimization. But you have to understand what's going on when you're working with purely presentational components. It should be, in most cases, no problem to just apply it like this as long as there's no stateful logic in terms of connecting to that application state. I mean, it can have local UI state, if you know what that is. But all the non presentation layers to those concerns are gone from this component. Nonsuch only concerned about presentation. And because of that, we can use the on change detection strategy. OK. So now let's get to a real example, a more advanced one. This one was very simple. So we also have this to have heroes to the heroes component. And it seems like it's doing a lot of things here. It supports and at hero action. It supports the delete hero interaction. As we can see in the code here, it has the dependency on the hero service. It has to hero's property for presentation. And some of this code to get here is looks very similar to what we have before, except it's it's displaying all the heroes from the hero service. So this actually has a lot of concerns, in addition to supporting more than one use case, this component. So what do we do? We follow the same steps as before, so we start out by creating a container component class, as we can see here in the top. And now we want to isolate and extract everything that's concerned with integrating with nonperson layers into a container, into this container component. So basically, everything that that touches the hero service, we want to remove that from from this component. And even down today, the hero state, the cashing of the Silver State, we would also like to remove that from this component so that we have a presentational component that doesn't really care where the heroes came from and is not stateful in that way. It just accepts the data from its parent component. So that's what we're we're taking the first steps toward now. First, I pulled in a micro library I created called Arkadiusz Multi Scan, it's a simple operator for managing state and a component in a reactive way. So this is the last parameter takes is similar to a JavaScript producer. So that's the initial state we have here, the empty array. But the property will be unobservable of a heroes every. So after adding that will start extracting the different methods from from our mixed component, the hero's component. And the first one we take is don't get heroes, we want to extract into our container component. So that it doesn't know about where to get it, get the heroes from, it should only be the heroes can only be concerned about presenting those heroes to the user. So we copy paste it or we actually cut and pasted the or copied and pasted the constructor because there are still methods depending on it. So we can't remove it yet to put that into the container component. And we also took that method call that returns and observable the hero service get heroes and the next line following that. That's how we reduce the state and it'll be merged into the state of this observable, so it's that the current heroes and the lauded heroes, the ones that are returned from our get get heroes observable. So that's if you know ah, yes, I'm sorry, indirects you you would have seen pretty similar to this, but not in the exact same way I implemented this, to be able to have some simple code without having to explain the whole framework. I hope that you can follow the logic that's going on here, that thirsty observable Bullivant. And then there's the producer for that and not an indirect producer about a JavaScript producer function, but only called for that observable emitting an event. So. After we've removed that in the original hearer's component, we're left with the honored and honored lead event listeners. So let's take a look at the next one here. Now, we actually want to take the state concerned with adding a hero. So at the very top, we can see you added a subject that will emit a hero. And every time that happens, we can see in our multiscreen operator. That then the state is reduced to at that heroes to the existing heroes, Ray. If we look down at the. He was component. We can see that we didn't actually manage to remove everything from this method because some of it is actually a presentational concern or at least in the presentation layers. Because it's about form validation and validation based on the name of the hero that the user entered. So it's not something you want to extract to a container component. So now we will take a similar method here and put it into the container component and we also called on that like the the one in the original component, but this is the integration part, so. We we are doing let's see. We're doing pessimistic updates here because we're calling the service to add the hero to the server or whatever. Before we're actually adding it to the assist or the cash to state our heroes array in heroes observable, so only when we get the success or the next omit from the hero service at Hero, we will emit another hero into this hero added subject and was triggered at the Heroes added reducer. An update, the state that is forwarded to our presentational component. And there was an error handle as well, and it simply ignore ignores errors from the server because then we don't want to update the state. I mean, sure, in the real lab, we would want to handle this in some way, at least let the user know or retry or something like that. But here we're just ignoring it, using the noob function from whatever. It's just a function that returns nothing and does nothing. So now we could get rid of those two lines of code in the original honored method. I'll just scroll back. And you can see it disappears from the bottom. Because now we're representing that we extracted it into our container component. OK, and then we do a similar thing for the delete user use case, so we add another up or so we're a subject here removed. And whenever that is triggered, we will filter out that hero that we want to remove filtered out from the hero state in this heroes dollar observable. And there's one more thing we need to add up here, and it's the undelete event handler. So this is actually Alesi. This is optimistic update because it removes the hero before it contacts the server to delete the hero. And if there's an error on the server side, when the leading that hero, the hero, will be added back to our hero state. So this is called an optimistic update because you update the UI before getting that acknowledgement from the server. But then you need to roll back the change if there's an error on the server side. So that's what we're doing here. And I don't think that's in the original to a Heroes tutorial, but I thought it was nice to also show that in this example. What that could look like. So now we're able to remove some of the logic from the U.S. component and I think where we actually extracted everything that we need and today here was a container component. At this point, it looks like this and this full length. So it has these two event handlers on and on the lead, we need to bind those to the presentational heroes component. And all the state will be managed by this multiscreen operator and the side effects of of reaching out to the server is handled in the event handles on that and on the lead as well. Very good. So now we need to go back to what's left of the original heroes component and we need to declare its presentational. I'm sorry that the data mining API of this presentation component, so now. We've changed our container component template that we see in the bottom of this file, so we see that we want to provide from this Shiro's observable using the async pipe. We want to pass that here on state, which is just in here, Waziri, into a hero's input property of this hearer's component. So we'll need to add the input decorator to that. We also do the title property, as we did before, and we have to invent bindings the on add and undelete whenever the presentation component outputs or emits an event for add or remove. So we'll need to add those to our properties as well. I already changed the selector to appear as UI to match what the container component templates expects. So let's first add these and put decorator's and add the title and property. Now we have the the inputs ready. Now, look at the output properties the event millers add and remove, and when the unaired event handler is called in, this presentation will hear his component. We will just emit that name through the ad output property. Anything left to do, but we still need to check whether we are using minimal presentational logic in our template and model for the presentational component. And as we see here, there is actually some what I call a complex presentation logic in the template of this presentation component. So that is a candidate for. Something we could extract to a presenter, but we haven't learned about those yet, so let's leave them here for now. But I'm talking about the in line kligman handler that in addition to calling the on, I had Evan Handler, it also resets this input volume up the your name input element. So that's something, again, we need to dumb to test this. It's not easily tested in an isolated test and it's not something we can reuse in other components or even in other frameworks. But we would leave that for now, let's look at the rest of this template, so it also has the list of heroes. And here we see that the click event handler on the delete button is actually just calling directly the property called Remove, calling the method of dad, passing it the hero that is iterating over in this energy for a loop. And if we want to be really strict, we would also move that logic to inside of the company model or eventually into a or. Class, but let's just leave it here for now. I don't have a problem, you don't have to be very dogmatic about this, use whatever makes sense. I mean, of course, if we wanted additional logic like we saw before, we should really be moving it outside of the template into the component model or a percent of class. But also another problem is that the component model doesn't even mean it has to remove our property, but other than that, you can't really see what triggers that just by looking at the glass itself or whether any logic is applied to that event. So next step is applying the UN push change election strategy. You see that in the top. We've added that now because now we have a presentation component instead of a mixed component with many concerns. Now we're only concerned about the presentation layers and our application. So, again, we had the strategy to get better performance in our application, the first concept we need to learn, here's presenter's. So what we should be left with is something like local, Jewish, state and presentation logic like that. But if there's anything complex we would like to extract the interpreter that represents the user interaction layer of our application. So this is the hero's component component we we saw just before after transforming it into a presentational component, actually. So what we start with when we want to add a presenter just at the class here. And then we want to extract whatever complex presentational logic we have into that class, so looking at the class below, we see some logic going on in the on that event handler. That's what we are interesting in in extracting to do that. We add, for example, I mean, you could use some libraries for this, like Interex components or the ARC's Angola State Service. But here, I'm just using ARC's yes subjects to not have any dependencies. So I add an ad subject, and that is a private property. I don't want to expose a subject to outside of this class. So instead of I'm taking its observer representation and exposing that in public Adbullah property. And now I need to you know, basically I'm cutting and pasting this logic into my personal class. Well, almost instead of calling this that at the moment, I'm calling this that at the next and in putting the name that was passed by the user. So now that we've removed that, of course, we need to connect the event handler from the owner to Ben Handler from our heroes component to the presenter. And to do that, we need to be able to inject the presenter into the presentational component. So this is how we do that we could use the providers or the view providers, property or sort of metadata of this component at the Heroes Center, and then we'll be able to inject it into its constructor as we see further down below. Now we need to connect the presenter to the presentation component. So we could do it in many different ways here, I'm trying to follow the angle of building blocks, so I'm actually connecting the observable of this percenter to Adam Sobel, to the output at property. So I'm actually subscribing to it. I could have done it in other ways, but this is what I'm doing here. And then I'm calling to the onat method of the presenter from the UNSNAPPED method of the component, and it's simply passing on the perimeter or the argument that it was passed from the user. So as you see here, there is really a thin, thin layer as possible in this presentation component. There's no additional logic going on except for delegating the control floor to different parts from the template and sort of percenter to. The properties of this component. But now that we subscribe to this absorbable, of course, we need to manage the subscription as well so that we're not looking at a memory, so that it's actually destroyed the subscription as soon as the component is destroyed. So there's other ways to do that. But I'm adding the undestroyed to the component, putting on this dry subject, using the take until this destroy operator. So now that we have these softer artifacts that are only dealing with a single system, concern are very easy to use to test actually most of the presentational components and our templates done in this way are hardly worth testing at all. The presenter clauses are naturally isolated, as they are usually free of injected dependencies or any dependencies at all. The container components there are also relatively easy to isolate and are Templar's are never worth testing. When using this approach, you can actually rarely have a need to use the angle of testing modules when focusing just on the individual components and classes that are part of this pattern so we can avoid the test back if we want to do that. So this next section actually want to see how much time have I spent now? Derek. Because I started the presentation before we actually put it on. So how much time have I spent? Know, let's do it. So I think 10 minutes you will have 10 minute. Let's do it in 10 minutes. I was speed up a bit, and this is actually some bad stuff, but you can you can take it to the next level if you want to. Be really strict on what you're saying. You want a 20 minute or. I will be 10 to 15 minutes. Perfect. Very good. So now that we have this hero's percenter, as we saw before, how can we prevent it from being leaked into protected content, child components? Well, there's actually a technique to avoid this so that it's only. The services only provided to whatever's inside of our template and maybe some other components, but it won't be accessible from a projected child component. So to do this, we can use the view provider's option and start in our component metadata. And that does what I just was trying to explain, that now it's only provided for our templates, the components in our template. And of course, the component itself, we can take a step further and be very explicit about which injector we want to receive this year percent or service from, and by using the self decorator, it'll only be able to resolve a dependency from the the providers at this component itself. There is a problem if you want to look at it in this way, there's a problem about. Component taxes. That's a term coined by Justice Warren Burger, and in that 2017, in his talk called Embrace Component Tranquility, he was talking about the tax of adding container components because an angler, you can only add in component by using another DOM element. It's very heavily tied to the DOM. So as we're seeing here before, we had just one element representing the a search component, for example. But now because we're adding a container component, we're adding an additional DOM element to that. Now we have both the add here search and Aparo search UI elements. When we do that, well, it can cause some performance to our application, even though we didn't add, we didn't even need additional elements for sake of presentation, only for sake of data binding and in some cases. We thought it might not even be possible to add an additional element. I mean, some elements expect a certain structure and could be some, even if we're not in full control of the HMO and in some system based on a CMS system for a website or something like that or e-commerce, it might not even be possible to add an additional element. So what could we do to to to try to fix this? So to to avoid having to add that additional element, but still extract the logic that is non presentational from our component, so I experiment with a few things. The first one is something I call the Container Directive's. And. I'm I'm defying a huge research directive, and I scroll pretty fast for this to just for the sake of time, but I'm basically extracting and literally cutting and pasting the logic up to a directive class instead of the container component class. As we see here now, the container component is entirely empty and. But but now we we want to initialize the presentational components property because we're hoping we want to hook on to the presentation component directly. And to do that, we could use the Internet hook, for example, we could set component title to your research and how are we accessing that component while we're actually just injecting it? And calling it a component property, as you see, we're injecting the research component, so we're tightly coupled to execute this component, but that's also what we want to do in this case. And we're using this host directive to be strict about where we want to receive this compound from. We don't want to receive it from higher up in the componentry. We want it exactly where we are applying this directive. And you'll see what that looks like in a minute. You are actually using this director. So the component has a search, our property, our properties are actually subject, so they have a subscribed method, so we are subscribing to that and then calling our own on site search event handler, which will just emit a value into the search terms subject. And that will. In turn, trigger, side effect. Because they will call that the hero service search heroes method, as we see in their fifth line of code or something like that. So we're also subscribing to the. The heroes. Observable in this directive class, and whenever something is emitted from that one, that is when a search result comes back, we assign it to the hero's property of the presentational component. So now we need to manage to subscriptions to the application state and component events because we're handling them manually and this approach to container directives, we're using the same technique again and destroy subject, adding the take until operator on our observable subscriptions. Because this directive will also follow the life cycle of the component it's attached to. So what would it look like to add this container director to the research UI component? So we're looking at whatever parent component wants to use this research, then we're attaching this app here, search director, as we can see here, and that's it on the side effects, they take place whenever events occur and during the life cycles of this directive. So to compare, before we had two moments and we had all these data bindings between the container component, the presentation component, and that happened in the. While the container component was added in the parent component and the presentation component was in the container component template, whereas in the bottom when we're using this container Directo, it's in everything is in the parent component template. So there is no container component anymore. And we saved that additional DOM element. So that's one way, but I really don't like losing all this declarative, declarative data, finding and managing all these extra subscriptions and mutating state, I'm not too happy about that. So I wanted to find another way to do this while keeping that declarative data mining syntax. So I came up with something called Provider Directive's. We're creating a research provider, DirecTV. In this case, it's a directive is that it's very important to have this expert as a name. And it's attaching to the AP research UI selector. So whenever you use that and and this directive is available to you, it'll be attached to that same component. It's not a component, but it uses the same selector. So you don't have to add any additional. I mean, you could add an additional selector to this one if you wanted, but this makes it more easy to to use. And anyways, it's tied very tightly coupled to to this presentational component anyway. So in this case, it would make sense to use it elsewhere to try to make a reusable. So we now have this directive class, so let's start extracting logic from our container component from before. So we're adding to search terms subject, we're pasting also that on search of an Tytler. And now we're left with what's shown here at the bottom in the container component. We also want to extract that or use a similar pattern as before with the unsalable that has side effects, but also returns to a new state of the the search results. But we're not subscribing now and we're not triggering any side effects in this class itself, only when the event handler is called. So what will it look like to add it to the presentational component, this provider, and I reckon. So we have now whatever parent component that wants to use our search, she research component. So we use a template of reference variable here that we named provider, since it's a provider, DirecTV. And we tell it that what we want to a reference to here is this directive by using its exported name to hero research provider and see that in the bottom in the first highlighted line of code in the template. And the second line, we see that now we're actually able to access that observable property exposed by our provider DirecTV, and by that to the presentational component using the async pipe. And we're also able to listen for events on the presentation, a component component, and handle them by using the provider DirecTV. That's what we see in the bottom line here. So now our presentation component is actually attached or integrated with our non presentation layers. So it does exactly the same thing, or at least the same concerns are managed as with the container component. But again, if we compare before we had the container component for your research and another element for the presentation component, and we saw that we had the data binding to the property, binding to the heroes and the event binding to the search event. And actually, we're using these provided directives, the syntax becomes very similar. The difference here is instead of having an additional element wrapping the presentation component, we have this template reference provider. But of course, the downside is that you need all this code and every every parent component that wants to use this CitySearch component. The upside is that you could you could use a different provider, DirecTV, for it. And if you really don't like this duplication of code, well, you could use the container directives I showed you before and start. So we had the benefit of of getting rid of that extra element, that might be what we really want to achieve in some cases, and we still maintain our data binding syntax in a declarative way. So be careful not to get too dogmatic about this pattern, you don't necessarily need to use a container component and a presentational component or even a percentage for every single component. If you prefer, you can just leave them as is until they start becoming complex on the component level. But if you choose to use this pattern, you can even combine it in different ways, like sharing a container component or even sharing hypocenter. You could imagine what we saw in the beginning of presentational table component and has a presentational role component and a presentation cell component in its view and the. Even death either in its own template or in the project, the concept? Well, all of these presentational components can share a single passenger and a single container component. Can integrate the whole presentation or table component to the application stage. So you don't need one to one match between container components and presentational components or even between presentational components and percent or classis, you can mix and match. And and when you start using this pattern, you think carefully about which state you want to externalize, like what's the shared state and preciseness state, the client state and what you want to keep internal to the components of the local UI state or or the locally scope state. So this is this will result in apps that have reusable composable components. And another benefit, you can even use the fake container components using development when you don't have a backend yet, are you just want to speed up development in general and then you don't have to deal with those pesky backend developers. So to summarize, we we're going to isolate and extract integration with nonpersons layers into our container component or a provider directive, the complex presentation logic we can extract back into our presenter class. Then we need to manage that subscription for the connected observables between the presenter and presentational component. But then we can unit tests on an isolated unit, test the container components, the provider directors and the presenters and the rest of the application can be covered by entrance tests to make sure we cover all the integration between the templates and the classes. Yeah, I already share some of these tips, I should have waited until my slide mentioning them. Sorry about that. And the last point I didn't mention is you can split work into visual development, application development and integration development. Some developers are more familiar with HMRC as assets or so. They could be working on the presentational components. Some developers are very familiar with Angela, but maybe not the visual side. So they could be working on all the different forms of components. And the presenters and some developers are more familiar and more happy about working with integration. So they could be working with the container components and all the services that they're going to need. So if you're working multiple developers on the same project or have many teams or just many developers in general, you can split the work into whatever makes sense for for your colleagues on yourself. Final thing I want to share here is thank you to these amazing people, Jason Bonta from Facebook, Michael Chen tactic, Shandon Abramoff were describing container components. It was four or five years ago. And the community that Abramoff even has a. Something that inspired me here. His on provider components for Redox and React that day when Bush first described this concept of working with three percenter with Angela. But I felt it was missing some. Details about how to implement it, he was discussing the tradeoffs and the benefits and so on, but how to actually apply to your application? That's what I wanted to find out how to do. So I started with this presentation and it turned into a whole series of articles that you can find in depth. And there's a link in a second as well. There was a guy called Repeller for that described a percenter with JavaScript and JavaScript. I also drew some inspiration from from his work. And Swathi, again, for the embrace component tranquility, talk about component taxes. That was a difficult problem to to solve, but discovered a few nice patterns that we can use for data mining and managing states. Those all the ways you can reach out to me, find me on Twitter, I'm lazy G.K and Twitter and GitHub. My articles about this topic is depth that Dabdoub. And I always feel free to reach out to me about whatever. Thank you very much, everyone. Thank you. Thank you so much. It was a great presentation, by the way. One question, why lazy? But you don't look like a lazy guy. A lot of things. So I'm very busy, but I don't mind being called lazy because it's just a nickname from back when I was gaming. Some people still call me and I'm fine with that as well. So I won't be offended if you call me lazy. Please do that. So thank you. Thank you so much for for this verifiable presentation. So next in line is Steve and Steve, and we'll talk about Angella performance. Best practice to win the welcome. And the stage is yours. Sorry, we can't hear you. We still can't hear your. How about now the better? Always, always, much better. For some reason, the Zoom was recording at two percent volume, which is not enough, I don't think, to hear me. Awesome. Thank you so much for having me. I will I will take the stage here now, so before I get started, I want everyone in the chat rooms watching live. Can you just type in the chat where you're from? Because I'm always really curious kind of what kind of global community, because I know we have obviously we have a very strong Polish community, so chest to everyone from from Poland. But I want to understand why it looks like we've got some people in India, we've got people all over. And I really want to understand kind of what's the breadth of the group that we've got today. So we've got India, Poland, Germany, Hamburg. And a whole bunch of places, it is awesome to see whenever the global community comes together. Thomas Patrick from Poland. OK, we've got some good Polish representation in Poland, which is very good to see from Warsaw. OK, Ernest Germany, Ukraine, France. And I think I even saw online a couple of people that were coming from the United States. So Argentina living in Poland. Awesome. This is a really great group, so I'm really excited. So what we're doing today is we're going to be talking about the things that I've learned from debugging a whole bunch of new applications. So I'm going to go ahead and share my screen and you should be able to see everything just fine. Can we see everything OK? Awesome, good to hear. So what I'm going to do is I'm going to introduce myself a little bit first. So if you don't know me, my name is Stephen Flamin and I am a developer relations lead on the team at Google. And my function on the team is really twofold. First is help developers and organizations be successful Cingular and second needs to understand what it's like being a developer of the world so that we can reflect that onto the team. And so a big part of my job is talking to developers through their challenges, through the problems that they face as they build avocations through things like performance, debugging, and then going into that second point of representing and understanding the real world of development. I spend a lot of time looking at applications across the ecosystem, trying to understand what are they doing, what are the best practices, what is happening in reality that might be disconnected from the things that we want to be happening out in applications. And so I try and keep a pulse on all the things that are going on in the ecosystem. We're going to go with through this talk in three parts. First, we'll talk about some of the data I've collected. So when I say 6000 plus in your applications, I want to explain where that comes from. And then we're going to talk to some of the things that we see going wrong. And then we're going to end with some live coding and some recommendations. So let us go ahead and dive in. So let's start off talking a little bit about the data, because it's very, very easy for us, especially in your team, to become disconnected from what's happening out in the real world where you don't always know what people are hearing when you go out, you're speaking and you're telling people, hey, do these things, and that can be even different from what you actually end up seeing people build. And so I look at kind of two types of data. So one is depth data. So this is kind of in depth, looking at someone's code, looking at the performance attributes of their code. And then there's also breadth data. So trying to understand what are the trends that are happening across the ecosystem holistically. And I try and capture both of these. So depth comes from a few different places. So I have a lot of conversations, one on one with your teams that are building and scaling large applications both inside of Google and outside of Google. As you probably know, I is very popular in the enterprise. And so some of the kind of biggest apps in the world are in your apps. And so they have very interesting performance characteristics. And second is conversations. I talk to a lot of developers and people love to share. Hey, this is the problem I'm running into or hey, this is how my app is affecting my users. And so I try to bring all of that together as part of the understanding of the depth of their application. One of the really interesting things to note, and I talk about this a lot, is that we still believe that around 90 percent of your applications are private. So this is an enterprise building tool for partners or employees or some sort of workflow engine. And so most and your applications are invisible to the world. They are not hosted on a dotcom that's visible to everybody either on the login screen. And so most of these new applications, you can't just go out and look on the Internet and find the most of them are at companies driving the work that people do every day. But we do see about 10 percent of your applications are on the public Internet driving really great consumer style experience. So it's really interesting to think about that, because if you just look at the public applications, you're going to completely misunderstand how popular anger is and how your apps are being built. So I have a whole bunch of different ways that I collect data and I post one of these on my blog, Fumio and I actually built this as an indoor application. So one of the things that I do is try and look at the performance of that application. And so oftentimes developers, when they think about performance, their default assumption is that runtime performance is most important. And for a lot of different user experiences, it is what we see is that is actually really good at runtime performance when you building your applications and you're doing kind of the standard best practices on pushing some things that some architectural things that Lars was talking about, your application is going to be very good. Construction is going to happen very, very quickly as it goes through the kind of single pass through the entire componentry. And what ends up mattering more is that first load experience. How long does it take for a user to actually start interacting with your application? The first time and a lot of people said this doesn't matter because my employees, my team members are forced to use my application. But that that's absolutely the wrong mental model. Everyone that uses your application, every user matters. And if you're making people wait, if you're hurting their experience on, for example, a mobile device, you are not going to be building a successful application. So when we talk about startup performance, the number one highest order of magnitude effect on that is the bundle size. And so most of the time, you're talking about Web application performance. You're talking about bundle size, because this is the thing that not only from a network standpoint, slows a user's experience down, but also from a CPU and a part time, because even if the user has the fastest Internet connection ever, if they're loading their application on a really old phone that has not a ton of CPU, the CPU still has to pass all that JavaScript and run it and execute it and kind of spin up and load all that code. And so we do a lot of things to spend our focus on this idea of time and bundle size. And so that's going to be a lot of what I talk about today, but not everything. So we've talked a lot about death, but where does breadth come from? So I actually have a couple of techniques that I use to try and understand the breadth of the ecosystem. The first is a chrome extension that I built called a new inspector. This is a tool that I for code I found on the Internet. And what it does is it basically looks at the human tags in the pages you're browsing and it looks at the headers that are being sent by the server. And it does a detection. It says, hey, we see that these technologies are being used by this Web application. And if you go in the options, you can say I voluntarily choose to send the domain name of any in your app. I find up to the server at most once per day. So I'm not trying to track anybody. We're only just trying to find any other applications so that we understand the breadth of the ecosystem. The other thing I do is I have a whole bunch of custom tooling that I've built using things like Chrome Headless. You can actually automate tool puppeteer to load a page. You can scan that page, you can look at that JavaScript loaded, you can look at the render Doomtree, you can evaluate runtime expressions. And a lot of these techniques are necessary for understanding how your apps are actually built. Because if you just look at, for example, the ship down by the browser, which is something like tools like I have done in the past, you're going to categorically miss a lot of anger applications. And so really trying to get in and understand using the same technology that your browser uses to understand what it is and does, we're using tooling to look at those same sorts of attributes and properties. And so when I run one of these little scans, like, for example, on my website, I can look at the version that is running the compiler. So all of this data is completely public. There's nothing private or sensitive here. These are all of the signals and attributes that every Web page is putting out for users. And we're just taking a look at it. We're saying, what does this user using to build around your application? I will say I have scanned over 6000 sites and I do not have enough data. I really am always looking for more sources of data. And so if you are interested in some of the attributes of your application, for example, if you want to benchmark the bundle sites that you've got, I have this site that I built. So if you go to bundle size dot dev and you just type in the euro in Europe, I will do exactly that process. So my computer will basically load your Web page and puppeteer and then look at the JavaScript and say, OK, how much JavaScript are you loading? What version of angular you on all those sorts of things? And what this does is this kind of goes into this dataset that I use to understand the breadth and the changes that happen over time in the ecosystem. We're doing a lot of twenty, twenty one planning right now, and some of the ambitious goals that we're considering are what could we do that would improve the bundle size, the average one size for all the English applications across the entire ecosystem, that that would be something that would be really, really cool to show. Excuse me. If we take a look at the size of the public applications and we see that they're getting better over time, that would be a really strong reflection that applications and best practices are permeating throughout the ecosystem and actually being leveraged by developers as being useful. So let's talk a little bit about some of the worst practices that we end up seeing from all these applications that I've looked at, so these are the things that would make my my son, Daniel, very, very upset when he sees them in your in your application. The average in your application that I've scanned is around three point nine megabytes, almost four megabytes of JavaScript. I would say that that is too big. I would say that A in your applications home page, like the landing page, the first page of user visits when they hit an application should be around between three hundred KB and let's say a megabyte. That would be a pretty good in your application. Obviously you can optimizing to make things even smaller than that. But three hundred to a megabyte to a megabyte probably be pretty good. And the fact that the average in your application is almost four megabytes is really a reflection that we are building these large, very complex applications and we're just reaching for tools. We're trying to build the features and we're not always pausing to reflect on the performance of our application and the user experiences that we're creating. I also want to call it that this is not uniquely an annual problem from the outside scan. The average in your application is five percent bigger than me and your size. But despite your apps from my scans at least being smaller than other apps, on average, this problem is bigger, right? We still need to focus on this. We still need to fix this. Just saying that everybody else is doing it is not a good enough excuse because these things do affect the user's experience. They do affect conversions. They do affect your business's success at the end of the day. So I have this story that I always tell where it's very, very easy for you to accidentally upload your bundle slides in ways that you don't even know about. And so we were talking to a team and their bonuses was really like they had a hundred analyzable bonuses, but their application was slow. And so we got in, we looked at their bonuses and we found out that their main bundle to their homepage was 15 megabytes of JavaScript. And that doesn't sound right, like not a lot of applications are getting up to that big without a ton of function in their home, but really didn't have a ton of functionality. And so what we did is we drove in. We did these standard tools of running source maps and looking at funnel size and figuring out where it coming from, tracing it back to its origins. And what we found was that they had been embedding Swigs in their angular scoped CSFs, which gets encoded as JavaScript. And so they were actually shipping down 15 megabytes of JavaScript because they had these giant cyborgs being encoded as JavaScript. And so there's kind of two or three extra layers in that chain that you probably don't need. The discussion there was really, really simple where we were able to just basically extract out those messages in the file system where they really should live. Right. Browsers are very good at loading SVOD when they need it, and that that took almost all of their bundle size and made it disappear in less than an hour, which is kind of the impact on the success that I want everyone out there to have. One of the other things that we've seen is that it's very, very easy to accidentally do things and we see this very often with libraries like moment where even though it's got a bunch of functionality the developers want, it's very easy to accidentally pulling your lookouts, for example, multiple times, which now three hundred KBE of accounts that you probably don't need are being loaded two or three times. And so now you have over megabyte of JavaScript just for a moment as an example of something we see all the time. And one of the big pieces of news from yesterday was that moment has actually now been deprecated. So if you're using moment and you end up having three or four locales, definitely go and look at alternatives. There's a lot of really great ones. They have a whole blog post about this on the Moment website. But part of the reason that I think moment is done and moving towards deprecation is that it was easy to make these mistakes. It wasn't using kind of modern JavaScript where we could shake and lazy loading apply to these best practices to only load the code developers need when they needed it, which is something that we can do with more modern libraries for for data functionality. One of the other big giant culprits that we see a lot is marketing JavaScript, because you as a developer might be building the most optimized, fantastic homepage ever. You're going to get every conversion, every user's going to load instantaneously. And then your marketing team comes along and they say, hey, we need a live user tracking where we see everywhere their mouse went and everywhere their eyes looked. And we need a live pop up for life support. We're going to have a chat room and we have a mailing list notification reminder at the bottom, all these sorts of things. And oftentimes a marketing team will come and say we need these things, but they won't actually consider the impact on the user. We have to push back a little bit on these things and understand the balance, because what good is it tracking your users and trying to optimize your site based on their behaviors when your site takes an extra 10 seconds to load on mobile devices, that is not what the marketing team is trying to do. And that's what we need to kind of watch out for, because the marketing javascript is still something that we need to care about. It's still part of the experience that we're delivering to our users. But 13 percent of applications are still not using compression. This has gotten way better over time, but that number is much too high. And it's really funny because Angerer apps compress very, very well. So if I took an example application with a three hundred and fifty two kilowatt main chunk, so that's 352 kilobytes of minifie JavaScript that the browser actually has to pass. But over that work it doesn't have to be three hundred fifty two kilobytes. Right. Except or if you use Bratley even better it's going to be saving two thirds of that bundle size without really any developer changes on your site. Right. Just a server configuration is going to save most of the bundle size of your application and it's going to dramatically improve the performance of your app for users that are network bound. So basically, your sites are going to get 70 percent faster if we use content commercial. So if you're not using compression or you don't know if you're using content compression, go and take a look at your site and try and make those improvements. One of the things you can do is use a CDN and use modern hosting. Almost all the students that exist out there are doing all these best practices by default. So content compression tubes, edge caching to all of these best practices come by default when you're using a CDN. So, for example, I use Firebase a lot and I get all of these features out of the box and that makes my application better without changing a single line of code because we as JavaScript developers in twenty, twenty, twenty, twenty one need to not only worry about the application that we're renting, but how that application is being delivered to the user. All right, so let's turn now into some of the best practices and some of the recommendations that we have. So these are things that would make my son as happy as reading his favorite book. So first and foremost, stay up to date with your in your application. So when you have a new application and you let it get out of date, what ends up happening is you are not benefiting from all of the work that the entire team is doing to make your application better. In basically every major version that we put out, we are doing work to make and you are smaller and faster. Not only that, but we're improving the bundle size of your application. We did this in four and six. We did this to eight nine. We do this every single time because we continue to make England better and because we have this opinionated control of the full stack. We can do things that improve the completion pipeline, we can adapt to new versions of typescript new versions of weapons, and we can use all those technologies to make your bundle size better. And this is an area that we spend a lot of time thinking about because there are things that we control in that built system that can improve it for every year. So we're spending a lot of time looking at, what, five right now, for example, with the hopes that that can improve, build speed and bundle size in various different ways. So if you use this energy update command, it is very, very easy. So we put out these blog posts, we have updated audio, and we also have this command line tool. And you update it really tries to make it easy for you. And we really ask people to go a little bit beyond that because we try and make it easy for you where when you update and you are working to update your application of the latest version. But if you are building a library or if you're building tooling for other developers, which we see happening a lot at big companies and teams that are distributed, you should be making it easy for each other. So we within a few schematics, it's the same technology that we use within Google to upkeep like two thousand plus your applications up to date whenever we make change and we have to go and update those 20 and your apps. And the only way we're able to do this is via automation. And so schematics are that technique for deploying that automation that is available to everybody. It's available to the whole community. And so if you're not building schematics to keep your ecosystem UP-TO-DATE, that is a really big opportunity that you're missing out on. The next top tip that we have for making our application performance lazy load, we really have this idea that you should only be paying for what you use. And so within a year you can do lazy loading out the component level. But what we see is that most developers are more comfortable in our tooling is really great around using the router to do lazy loading. And I'll actually try and do a little bit of a demo around that. But in order for you to understand what you should be doing with your application, you really need to start by measuring. And this is a really simple process to actually go through this in a little bit. But you should install something called source methods for there's other tools out there like funnel web analyzer. But those tools actually categorically misrepresent some of the bundle sites. And so we highly recommend sort of explorer as your go to. And then whenever you do a bill to do a production build with source maps turned on, you can also do this in your angular Jason and then just run source map explorer on the generated JavaScript. You will find that source map and it will map back all of the bundle sites to its origin within your application. So what I want to do is I want to demonstrate some of these concepts with a real world demo. So I'm going to exit out this little presentation here and we're going to dive into an application that I've created. So if we take a look, this is a application, just a blank engineered application. Right. This is the same thing that everyone would get out of the box with ANGULAR. And if we take a look at the code, this should look all super familiar. And if we take a look at the package, Jason, we're going to note that this application is actually on an out of date version of ANGULAR. Oh, no. What do I do? Well, it's actually really, really easy. So we're going to do is we're going to kill this and we're going to run and update and we're in it. And your caught and angular size, Seelie. And unless I've done something wrong here or messed up the setup for my demo, this should just basically update our application. It's going to install the latest version. So I use that latest version, Seelie, to apply all of the schematics that we need to get from the old version to the new version. So you can see we are moving from nine point one twelve to ten point one. So we're not just moving to version 10 zero. We're moving to the latest version in the latest major. It's applying all of these different migrations to make sure their application is compatible with the changes we've made to ensure it's applying updates to best practices, it's doing all of these different benefits to my application without we have to change a single line of code. So that is complete. We can take a look at our packages and now we are now on the latest version of regular. And so if I do an energy build or an energy serve. What we should see is that we'll do a build in the background and we should get out a fully functioning application that is on the latest version and so we can actually take a look and this code and see what the changes were. So you saw that we had all those migrations that we were playing. None of those migrations applied to my specific source code is what we do is we leave all those changes on disk so you can step through them. So you can see we renamed Browser List RC with browser or we rename browser list to browser WRC to make it a hidden file because most of us don't need to worry about most time. We've updated your picture, Jason, we've updated your TS config in terms of configuring your bill and we've updated the config for your end to end test. So we are updating your application to keep you up to date with the latest version of your, which is kind of very, very powerful. One other change we make while we wait for this build in the background is I'm going to go ahead and update my angular JSON file. So the change that I want to make is in the I recommend every developer do so turn source maps to true because source maps in production aren't really a user cost. Right. Users don't load the default and they're not really a security problem because you should not be relying on the security of your client side JavaScript anyway, and we're going to turn them chunks on. True. So source maps will make sure that whenever I do a production build, I get source maps by default and named chunks is going to give me user friendly names in those production build so I can actually tell what is what. All right, so our production bundle has finished here, and since we're going to be doing a few different builds, I also want to take a look at my browser list file. And I'm going to say, let's just say the last two versions. So let's just bump this up to more than five percent, so what they should do if you haven't used produced, it's actually really cool to say browser's list and you can see what versions of browsers you're actually supporting. So with that change, I said only browsers more with more than five point five percent market share, I'm only going to be supporting these two. And so whenever I do a correction build now, we shouldn't be doing that S5 bundle generation because new modern browsers don't need them. This just happens automatically based on the browsers that you're saying you're going to target. But as you saw, we did a source map. So let's go ahead and add a source map explorer. So we should be able to use force map explorer and actually take a look at the bundles that we generated. Sources, methods for. And we're going to say star Maine star Jess. And that should give us a bundle analysis once I type the name of the application room, we can just manually target it here. I mean, is it really? All right. And for some reason, that's floating in wine, which is definitely not what it's supposed to be doing. Let's see if that actually is the correct browser. That is a little bit weird, that is going to mess with my demo just a tiny bit. Let's do it one more time. It is not coming up in the browser for me. I apparently have too many browsers installed on this system. You can also if you take a look at just the sort of explorer tool, you can see it has a whole bunch of command line options. So what you can actually do is you can tell it to output the results. As a Jason, you can tell it up with the results as HTML. So what we can do is we can just say thanks for dishdasha e-mail. And then we can just redirect this to report on Jim'll, and then I should be able to say Google Chrome, Beita, so bit of an extra step here, but we have now our source map explorer and we can see that this application out of the box because we are using things like animations and the router. Our application is around two hundred eighty six KB, which is OK. Right. This is not the four megabytes we were afraid of, but what's actually go ahead and now build our application out a little bit. So the first thing to do is I'm going to I've already engie added and the Timoteo here. So I'm going to generate a component that uses some of your material. So I'm going to say MGG angular material table and I'm going to generate my table component. All right, so we take a look so that generated that component and then in my home page, I can actually just go ahead and swap out that page. So let's go here and let's just get rid of everything but the router and I'll just say at my table. And if we have an enemy circling in the background, we should what we should see is that the local authorities, instead of this default placeholder application, we're seeing it replaced with a starter component from the interior material project, which is really, really helpful for developers. Right. I can start very quickly and build out a very good looking application. All right, that's going to finish in just a moment here, and we're going to do is we're going to take a look, because if we look under the hood of the source code to my table component, we're going to see that it actually brings in a lot of different material features. So you've got Matt pagination, you've got Matt Hetero, you've got Matt Table. And all of those things have been added to my app module as imports automatically. So all the features needed for this feature set. Should be rendered here, we've got a tiny bug here, hopefully that doesn't break our build. All right, it is working here, as you can see, are your original app works and we have this feature, but if we do an energy bill, dash, dash, prod, we're going to see that there is something that has happened to our size. Now, our bundle size is not going to be around two hundred and sixty. Maybe it's going to be much bigger because now we're using more features of angular and so that's unfortunate. Let's do you that of yours you here. So we update it in your. But we didn't update material CDK, which might be causing part of our issues here, but we're going to see is the bundle sizes increased. And so one of the techniques and one of the ways that you can get around this is we should actually be using lezzy loaded modules. And within Angara, there's a really, really easy way to create Lizy loaded modules. And so I'm going to do this in another time here. And you can use the energy command in this and you generate a new module. And I'm going to attach it to the existing model of laptop module. And I'm going to say, let's make this in a room, let's make this a new route called about and we'll create a component in module called about. So imagine take your application creating in about this site so that one command is basically now updated my routing module in the route of my application configured lazy loading so that when the user navigates to slash Rentz. We're going to automatically navigate to that page. So if we're just routing, we can see we've got low children. Which is doing this dynamic important so that when we do a build should automatically generate a lazy, loaded bundle, so we'll just give this one more try here. I don't know if the bill is going to work or if I've missed something up here. And if that production build works with source maps, which should be automatic because we set that configuration flag in our adjacent file, this application should now be lazy loading. And so any code we attach it to that about Munjal isn't going to be affecting the initial load of our application. All right, so. For example, if we now use that energy, generate a material table, if we did a dashboard now, we would actually do that in the about folder rather than our home screen taking all of that out of the blocking out of that critical path for our application. Give this just a second more. See if it worked. If you have ever wondered what 92 percent chunk asset optimization was, this is the process by which the primarily Web tool, as well as kind of things like tercer, are actually doing the module math to figure out where to put your code. So this idea that if you only need your individual code in your about module, we shouldn't be putting that into your main module. So we can see here we have finished our production bill that we've got at least a module called about because we have named chunks, we've got source maps, we've got all these great things. So it's to sort of map, explore and let's pass it our application. And let's now take a look at the main. And it's starting up in one browser again. Sorry about that. That's a little bit weird. So we'll just skip that. All of that makes sense, you can see the bundle sizes here are applications gotten a lot bigger, but we are in control, right? We can decide where we want to load that coat and when and where and why. All right, so one of the techniques that I want to call out is server side rendering. So last year almost no one was doing server side rendering. The data I have from debugging a whole bunch of apps and looking at the broad ecosystem of less than one percent of sites. We're using server side rendering single universal tools like Skully, whereas this year in twenty twenty it's more than twenty five percent of apps. And so this is a huge trend that we're seeing the ecosystem because for public facing non internal applications service had rendered version is going to give you users a better perceived load time, which can be really, really important as a server gives you a couple of benefits, so it gives you machine credibility. So if you ever want to have a shared a Twitter share to Facebook share to whatever button you need, machines that don't understand JavaScript to be able to pass your application and the performance of your application really is improved in terms of the perception of users that they can see and interact with the application faster, even if it takes longer to load, because you have to load both the HTML and the JavaScript can make your application feel faster, which is what actually matters. We have these idea of bundle budgets. So if you look at your data, you're going to find this little budget section. We set things to a very conservative, two megabytes and five megabytes. We recommend you take a look at your introduce in your budget and lower these to around, I don't know, within 10 percent of your current bundle size. Because what we've seen is that when we help developers and teams build applications that are small and fast, they most often end up kind of backsliding over time. Where developers want to build new features, developers want to build new capabilities. And it's very, very easy to accidentally put your bundle size if you're not monitoring it, you're not enforcing some of these things. And so what you need to do is bundle sizes so that you make it a conscious choice. Right. You can always choose to increase the size of your bundle, but you want it to be a conscious choice rather than something that you just do accidentally so that that's what bundle budgets are for. There is also a new set of standards out there called web vitals. And so these are kind of the go to metrics for understanding how performant is your application. So there's three of them, Schnaubelt largest content page. So this is the biggest Domme paint that ends up happening in your application. They believe that the biggest page is probably the most meaningful and the one that users actually waiting for. And so that that's the metric. So it's kind of milliseconds to that large content pain. Second is cumulative layout shift. So this is all the times that the browser has to relay out the page. How much is it actually the way that page and so a page that ends up changing and everything gets pushed down once and then it changes again and everything gets pushed down twice and then a third time. That is not a great user experience for a first load. So trying to measure and minimize that metric is important. And the last point you can't actually measure in a lab, which is first input delay. So this is only based on real user behavior when a user actually clicks or type something or actually interacts with the page, how long does it take for your application to respond? So as soon as user thinks they can do something and tries to, how long does that take? So these are the metrics that are kind of the industry is moving towards the leadership from the Chrome team in terms of trying to map user expectations and user perception of your application forms into numbers that we can measure and tool and instrument around. So that was the talk. We've covered a lot about performance. We've covered a lot of the things that we do wrong and how bad the state of the ecosystem is from many perspectives. But I want to leave you with a couple of thoughts. So overemphasising metrics like bundle size can miss the point. So you should always try to make your business as small as possible. But you should also be focusing on the user experience overall because we should be having fun with you, making sure our users have fun, because in every application it is about the tradeoffs that you are choosing as a developer. So make sure that you are focused first and foremost on building great experiences for users. And oftentimes that'll include bonuses, but not to the detriment of everything else. Thank you so much. This has been a lot of fun and I, I don't know. Are we doing Q&A today? They can do it, of course. We can do it moment. Great presentation, Stephen. Your video is like a fresen. My video's is frozen, that's not good for Rubia. I also see your video frozen, Stephen. I will fix that in just a mere moment. I think do we have Q&A we want to do or what's the next step here? Yeah, so if if someone has some question. Yeah, please. Right. Between the comment and now we have five minutes more. Let's do five minutes more with some questions and. So let's start. Any questions to Stephen or to Lars? Someone is asking Stephen to produce more videos on the demos with Angela Channel. I should produce more videos. I completely agree. I have a couple that are are in the making. One is a overview of Web development in twenty twenty because I think we, as especially Engelhard developers, we forget that there's a whole ecosystem out there of not just single page client, single page applications and client side JavaScript frameworks, but there's things like server frameworks and like WordPress that are still dominating most of the web. And so understanding kind of what everyone else is doing is a really important reflection. I've also been working on a video, a couple of ideas about what is angular, because I think everyone has a different concept in their mind. And I think I want to share just some of the things that I've learned over the years. And so those are a couple of the videos that I'm working on. I know that I don't produce enough. There's another question, and you did discuss this, but maybe you can repeat Ka'bah is asking, is there still value in turning source maps off and production code to obfuscate your code? So I, I believe obfuscation doesn't really do anything. I mean, yes, source maps will expose the underlying file layout of your application. It will expose file names, symbols, all those sorts of things. But I don't really believe that. In a modern 20 20 security environment that you are exposing too much by giving those things out, if you are relying on the name of your files to keep you secure, you are not secure. JavaScript does not work that way. You're saying no to security through obscurity. Correct, yes. I have one question to Stephen. It's not a technical question, is a question about the decir and the way you want to come to England this year in person on or just online. I I would love to come to Poland, but I don't think it's in the cards this year with the fact that most Americans aren't allowed outside the country due to our Cauvin situation as well as in November, I'm expecting another baby boy. So all I'm going to be quite busy this year. Congratulations from the place you're supporting. OK, do we have something, other questions? No. OK, so thank you. Thank you. Thank you so much, guys. It was great to see you. And for you and to see this great presentation. And I hope to see you next year in Poland, so if not this year, next year we have to do. I went to Krakow a couple of years ago and I loved it, so I can't wait to go back. Yeah. Thank you so much. I thank you, have a great day, everybody, have a great night.