 I'm recording this the Friday before Emberkons. Unfortunately, of course I couldn't come to Portland as I did at the past five years or so. First time I was speaking and first time I'm not actually there at the same time, which is unfortunate, but I guess this is kind of a special situation obviously. So I don't have proper recording equipment here, but I hope this is gonna be gonna be good and let's get started. So welcome to my to my bonus conf talk decorators in debt. I'm Marco, I'm from Germany, specifically Bavaria, where people sometimes look like this. I am the founder of Simplabs. We're a web engineering consultancy with digital products for companies around the world. And we also have teams to be more effective with Emberk deliver better quality in a shorter time maybe and just sort of to get the most out of Emberkons. And you might know us from our open source work. We maintain a bunch of like well-known add-ons in the Ember ecosystem. We also sponsored the Ember project such with people writing for the Ember times. For example, we did a lot of work on the website with people on the learning team and so on. And we co-organize Emberfest, which is Europe's Ember conference obviously. And my notes here, I brought stickers. I didn't actually bring them, obviously. I think I sent 800 to Portland, which I don't know, maybe now in the Tildor office and maybe we can distribute them some other way. But here's how the sticker looks for this year and the dates for this year are gonna be October 15, 16. We don't actually say what the host city of the conference is. As every year sort of we have this sticker with a background that sort of gives some visual hints on the location and then we'll add, people guess, it's like our poor man's marketing strategy. I think it worked pretty well in the last years. And yeah, let's see whether somebody can guess this year's host city will of course reveal it soon. But I guess at the moment it's not even clear whether everybody will be able to travel anywhere in Europe in mid-October. Hopefully, yes, but we will hold off a bit until the situation smooths a bit more. So I have some opening story for the talk which doesn't really work anymore. I'm still gonna do it though because I couldn't really come up with anything better. So this is actually like I said in the beginning, it's the first time I speak at EmberCon. And the joke that I wanna make is that it's the first time that I'm speaking and I almost didn't make it to Portland. Now of course I actually didn't make it to Portland but let's sort of go through the story because besides Corona, there's actually another reason why I would almost not have made it to Portland if Corona hadn't happened at all. And that has to do with this thing, the electronic system for travel authorization, short ESTA, which is what all of the non-Americans or Europeans are sort of, I don't really know to who it applies, but everybody from Europe has to sort of go through this system sort of to register with their passport number and so on before they can go to the S, right? And then that gets approved and then you can go into the country without a visa. And in order to go through this, you have to answer all kinds of questions. One question is, have you ever violated any law related to processing using or distributing illegal drugs? Which I don't know, this might be the one where like many people would actually lie, I guess. There's also other questions. Like, do you seek to engage in or have you ever engaged in terrorist activities, espionage, sabotage or genocide, which I guess or hope most people can actually honestly didn't answer negatively, right? But there's also a new question since I think summer last year and that is have you traveled to or being present in Iran, Iraq, Libya, North Korea, Somalia, and so on after 2011, after March 2011? The problem is, here's a picture of me in North Korea in 2012. Here's me, here's a statue of I think Kim Il-Soon and here's a bunch of flowers that I just had had dropped in front of that statue. And I should say this is not actually sort of me expressing my support for the regime. It's just something that you're sort of expected to do when you're there. So I answered that new question honestly and not surprisingly, my travel to the US was not authorized. So now I need to get a visa, which is actually a good thing because now I have a 10 year visa and I don't have to go through Esther anymore. And somebody told me I would have been able to sort of immigration take like a faster lane or so, but I might find that out next year. And getting the visa was really easy. The person at the embassy found it pretty convincing that I went to North Korea for a vacation. But yeah, having the visa doesn't help me now, of course. And of course, it's not really up to me sort of to judge US policy, but I'm not sure it's fair that I need a visa because only because I have been to North Korea once because here's me and my guide in North Korea, that's Mr. Kim. Obviously in North Korea, you cannot do anything without a guide, right? And the guide is not actually a guide, it's more like a person that's watching you, right? And they are being watched themselves, right? But the thing is I don't seem to be the only one maintaining relatively close relationships with North Koreans, right? So it seems a bit like there's different rules for different people here. Although I will admit that I did not fall in love with Mr. Kim over beautiful letters, but just over beers as people do. Yeah, it's like maybe a bit of double standards here. So anyway, I thought this might be a good opening story for the talk. Now, as I said, sort of it doesn't work anymore really because now I'm sitting here in Munich, but so having added that story to the talk, I thought like maybe there's a way sort of connecting the talk's main topic, which is obviously not North Korea, but JavaScript decorators, like connecting the two topics a bit, right? And having sort of a JavaScript decorator slash North Korea talk. And then I was thinking about how I could do that. And the first thought I had is just this statement, which sounds pretty nice, right? Decorators are the North Korea of JavaScript, but what does that even mean, right? It's basically just a budget statement that sounds very good, but it means nothing. So unfortunately, there will be no more North Korea content in this talk, just because I couldn't find a proper way to get it in. But back to the topic, and I wanna start with some theories. So the theory behind something like JavaScript decorators is attribute-oriented programming. And the idea behind attribute-oriented programming is that it is a program-level marking technique that allows you to mark elements in your program to indicate that they maintain specific, application-specific or domain-specific semantics without leaking all of the details of those semantics into your core logic, so to say, which then increases abstraction and reduces complexity, right? And many languages have had similar concepts for quite some time. For example, in Java, you have attributes like deprecated, which allows you to mark a specific thing in your code, like a class here as deprecated. Of course, you could also do more sophisticated stuff. So here's an example from Hibernate, which is a very popular object-relational mepper in Java. And here you see we use the entity attribute and the table attribute, ID attribute, and so on to sort of define how the mapping from instances of the employee class to a particular data-based table should work or other way around as well, of course. But the thing here is we're not leaking any of the details, like any of the sort of internal mechanisms of this mapping into the application core, right? We keep it relatively clean because we just sort of attribute the elements with the respective attributes without sort of revealing how those work internally. This concept doesn't only exist in Java, though. There's also a similar concept in .NET. So here, for example, we're using JSON property attributes to define how instances of a particular class, in this case, the API error class are serialized to JSON. And again, without leaking any of the details of the serialization process sort of into our application code. When we compare this to what we have in Octane, then it's obviously similar, right? So here we use the track decorator to mark the count property as track. So the template we ran was when it changes and we use the action decorator to make the increment and decrement methods work as actions. So again, without leaking any of the details of these decorators or the concepts behind them into our application code, right? We just say the count property should be tracked. We don't care about how that works internally or what tracking even means sort of. That's not a concern of our application, but that's a framework concern. So there's no point sort of leaking any of the details of the concept of tracking or the concept of making a method available as an action or work as an action into our application code. So we wanna hide all of that and we do hide all of it behind that decorator. So this is how JavaScript decorators fit in to sort of the general concept of attribute oriented programming. So you add attributes to the code to express additional semantics while hiding all of the details. But later we will see there's actually a fundamental difference between JavaScript decorators and attributes in other languages. We will look into that more detail later sort of on the surface, it's sort of the same thing and it's meant to serve the same purpose. The insights sort of are a bit different, but for now we can ignore that. So then you might ask, are decorators ready for use? And the answer is it's complicated, unfortunately. And again, I wanna share some background here. So as most of you know, or everybody presumably TC39 is the group that defines the ECMEL script standard and that's JavaScript. It's an international group of people with various backgrounds sort of that represent different interest groups like larger companies, browser makers and so on, but also sort of the viewpoint of the average JavaScript developer sort of which I think was one of the main motivations for you that cuts like obviously, as you know, one of the sort of inventors of Ember to join TC39 because I think that his motivation sort of was to make sure that the average JavaScript developer's viewpoint sort of was recognized in TC39 as well and not only the interests of larger companies or browser makers because sometimes those could be pretty different of course. So that group of international people discusses ideas for additions and changes to the spec or I guess in reality, it's really additions only because you cannot change anything in JavaScript and it's basically an additive spec because changing anything would break existing code and websites. So each new thing that they discuss goes through five stages. In stage zero, the thing is basically just an idea for a new language feature. So anybody could have that idea and then when you find a TC39 member to bring it to the group, then it would get discussed there, right? At that point, the idea would usually be pretty vague. There's no indication of whether it'll go forward at all or maybe like it's being discussed for five minutes and then immediately rejected for some reason or whatever, right? The next stage then is stage one where you have a written proposal with proper description, examples and so on, discussions of semantics and there's a TC39 member that champions the idea or the proposal. So stage one means that TC39 is willing to examine, discuss and contribute to the proposal but there are still major changes to be expected, right? At that point, it's still relatively vague and there's no indication of whether it'll make it into the spec eventually or if it makes it, whether that's gonna be a very different form maybe but if it's not rejected then the next stage would be stage two and at that stage, the proposal must have a formal syntax definition, description should be complete, there should be, or there need to be, I think, two experimental implementations. One will usually be bevel unless the feature cannot be transpired to current JavaScript sort of. I think that was the case with proxies because there's no way sort of to make the underlying mechanism of proxies work with current JavaScript. Obviously, experimental implementations can, of course, be in browsers as well behind feature flex or whatever. At stage two, a proposal can still be rejected. It's relatively far in the process but there's still no guarantee it'll make it. The next stage then is stage three at which point the spec text needs to be complete there need to be two fully compliant implementations. Again, one of them would usually be bevel and at this point, the proposal can be expected to be added to the spec and changes should only be made when critical issues occur and that's why stage three is sort of the important stage because at stage three, you can expect the thing to be added to the spec eventually in only slightly modified form. So stage three proposals are pretty okay to use in general. Why everything before or below stage three is not really okay to be used because there's no guarantee it will actually make it to the spec and there's no guarantee that if it makes it to the spec it will be in the form that, in its current form sort of, right? So yeah, stage three is the one that you wanna keep in mind because that's sort of when you're building on relatively solid ground sort of if you're using something in stage three. The next stage is then stage four which is basically just like a stage that something goes into while it's sort of waiting to be added but it's already decided that it will be added, right? So of course, now the question is where are we with JavaScript decorators? And first problem is there's not one but actually two proposals. Second problem is one is in stage one and the other is in stage two and obviously that means that none of them is final or complete, right? The stage one proposal is basically deprecated sort of that's not going to be continued and the stage one, the stage two proposal is in stage two which means it's not done, right? It might still change relatively significantly. So let's look at some more details of those two proposals. First of all, the stage one proposal which basically defines decorators as simple functions, right? You would just write function that receives the element that you're decorating and then you can modify the element which is very simple, right? But it has major implications with respect to performance because you're actually modifying the class or the method or the property or whatever. So you're changing the shape of things sort of which is always very bad for browser engines to optimize, right? So there are major performance implications. There are also major tooling implications because you cannot actually statically and you cannot actually statically analyze those decorators, right? If a class is decorated with a stage one decorator you cannot really know what that decorator does. So you might not know for sure which methods that class has, right? Or whether the methods are actually as you see them in the class body or whether the decorator does modify them and then like the actual methods on instances or on the prototype will actually be different from what you're seeing, right? So that's of course a major problem. It's well in particular for tooling, right? So the stage two proposal solves the performance and tooling problems by basically defining decorators as first-class language elements and sort of limiting them much more but it's not ready yet. They're major changes to be expected. So it's not even really clear how exactly that's going to look, right? So coming back to my previous slide here in reality, decorators are not the North Korea or JavaScript but sort of the anti-North Korea of JavaScript because nothing is regulated and everybody can do what they want basically because there is no official regulation or specification. So the question is what do we do? The old thing is deprecated and the new thing is not ready but in EMBA we need something that works well with native classes because the old macro methods that we've been using for computer properties, for example and so on, they don't really work well with native classes. You have a bunch of options using them with native classes. So it's not impossible to use them. I think there might be some edge case whether actually behave differently but it's not impossible to use them. It's just not nice at all. So for example, if you had a person class with a first name and last name, and by the way, all those examples are, I think, taken from the IFC that I think Melanie Sumner wrote, I'm not 100% sure but the examples have her name obviously so let's just assume she wrote it. So if you have a person class here with a first name and last name and you wanna define the typical full name computer property, right? Like full name must be sort of the hello world of computer properties, I guess. Then with a native class, you could define the class first and then on the prototype, define the computer property, which is obviously not what you actually wanna do in your application. The alternative is you sort of mix like new native classes and the old M object model and you define the class as an extension of sort of an anonymous class here that where you use the old way sort of extending from M object, this works but it's obviously also not really nice, right? The best solution is obviously with decorators, right? Where you just define a proper native class with two fields and one getter and you just decorate the getter with the computed decorator here, right? So the question is how do we get that when the decorator's proposal is not ready really? And the answer is we just stick with the stage one proposal for now. This is what the TC of 39 Champion Group recommends because although the specification is not ready, decorators are already widely used in the JavaScript community and Ember is actually relatively late to the party here. So projects like Angular also have used decorators for years now. So there's a lot of pressure and also there's commitment I think from TC 39 to make the final decorator proposal so that it will allow to do the, to make the final decorator proposal so that it will allow for doing the same things with decorators that you can also do with stage one decorators. So that means you will very likely not have to change your usages of decorators, right? The decorators will only have to change internally to solve the performance and tooling problems but that also means that you do not want to write your own decorators here because why sort of, why usages of decorators will not have to change the internals of decorators will change a lot potentially. So when writing decorators, you are building on pretty unstable ground, right? If you only use the decorators that Ember provides, then obviously Ember sort of shields you from all of the internal changes that might or will probably have to be made at some point, the computer property, the computer decorator and the track decorator will continue to work the same way that would just be implemented in a very different way internally. One thing though is that in app code, you would usually, but there's usually not such good use cases for decorators anyway, because as we saw in the beginning, the purpose of a decorator is sort of making something available while hiding all of the details of that, right? Which is usually not something that you wanna do in an application, right? Because in an application, you don't wanna sort of hide parts of the code from the engineer because all of your application code as a whole sort of is being maintained by your project team and so on. So you don't wanna introduce black boxes, right? It is however, of course, something that has a lot of value for frameworks like Ember or maybe even for add-ons. And understanding what decorators do, how they work, what they can do, what they can't do sort of gives you a better mental model of your application, of course, which is also the reason why I put this talk. So let's look at the stage one proposal in more detail. We will basically ignore the stage two proposal for now because it's unclear how it's going to work eventually. So we will focus on the stage one proposal. And like I said, the stage one proposal defines decorators as simple functions that modify the element that they're decorating. And that is also coming back to a previous point. That is that main difference between JavaScript decorators and attributes in Java or .NET because while attributes in Java and .NET only add metadata sort of to the elements that they're attributing, JavaScript decorators actually modify these elements, right? So with a JavaScript decorator, you could actually modify a class, for example, where an attribute in .NET will only add metadata to that class so that at runtime, you could reflect over that metadata and sort of do certain things then, right? So that might of course be different in the stage two proposal, but for now that's really the main difference that a JavaScript decorator will actually modify the thing that it is decorating. And doing that though is relatively simple. There's basically two cases. That's the case where you are decorating a class. And in that case, the decorator is a simple function that receives the class constructor as its argument. You could also of course decorate a class member in which case the arguments for that are the prototype, the name of the member and property descriptor for the property you are decorating. And I wanna show you some concrete examples to make that a bit clearer. I have created a little example app so you can find all of the code on Gitter. And let's look at the first one. So here we have a simple mbar route, right? We just load some data from an API endpoint. We don't care about the details, of course. And now let's assume we wanna benchmark that, right? We wanna like have something in place that allows us to benchmark the execution time and maybe report it somewhere or whatever. But of course we don't wanna sort of have all of the benchmarking code as such in the route, right? We wanna hide that because it's not relevant to the application really, right? Let's say we wanna like make a benchmarking add-on or whatever. So a good way to do that of course is to use a decorator as we're doing here, right? We're just importing that as any other thing sort of in JavaScript and then we're decorating the model method. And as I said, before the decorator using the stage one proposal, the decorator is just a simple function that takes the prototype, the property name and the property descriptor for the property we're decorating as arguments. And what we're doing here is we're simply remembering the original value of the property descriptor, which is the original implementation of that method. And then we replace it with a wrapper, right? And here what we're doing is we stop the time when we start execution, then we call the original method. We stop the time when that ends and we lock that to the console. In reality, you might be logging into some sort of API or whatever, and then we return the result that we got from the original method, right? So we do not change the original method. We also don't change the signature of the method because the method that we are replacing the original method has the same signature, right? We're just adding our stuff sort of before and after the original method. And that also means, of course, that the original model method doesn't even have to know that it is being benchmarked or that it is wrapped with something else, which is the point of the decorator, of course. Another example is this one here. So let's assume, besides benchmarking the model method, we also wanna require users to be logged in to have access to that route at all. And by the way, this is a sneak preview sort of of what a version of MSimploth, which we had simplified to maintain, without Mixins can't look like, right? You can use Mixins with native classes like relatively easily in Ember, but it's not really great, right? So in the current version of MSimploth, you would just mix in the authenticated route Mixin into this route that you're defining here. But with a decorator, it's even a bit nicer and sort of has more modern look as well. So what we do here is we just import the authenticated decorator and apply it to the route class. And again, the decorator is a simple function that takes the class constructor as an argument. And we do a similar thing here to what we did before. We remember sort of the original implementation of the classes before model method. And then we replace it with our own method. And what we do in that method is we get a session or the session service. We check whether the user is logged in. If it's not the case, we just transition them somewhere else. In this case here to index probably make more sense to transition them to the login route. And if they are logged in and there's an original implementation of before model, we just call that, right? So again, we are adding sort of relatively complex logic with a very simple mechanism. And we are hiding all of the details. We don't change the original before model method. So I think this is a very nice example for how decorators are actually a pretty good way of making functionality in add-ons available for EMBA applications. Obviously those examples are sort of made up. They don't really have any sort of real value. It's just for illustration purposes here. So I also want to look at two examples from EMBA itself. And if we look at this piece of code here from previously, again with component that has a track property called count and then two methods that we decorate with the action decorator. So we can actually call them as actions from the template. So how does this work? And first of all, let's look at the tracked decorator. And this is not really the code from the Glimmer code base. It's sort of the essence of the code, right? But here you see that we have a function here that takes the prototype, the property name and the property descriptor as arguments, right? Because it's a stage one decorator applied to a class member. And what it does is a very similar thing to what we saw before. It replaces the original property with in this case here a getter and a setter. We can ignore the getter, that's not so interesting. But the thing of course about track properties is that whenever a tracked property is modified then the template re-renders, right? And you see how that works here in the setter where whenever the property is set the property to change callback will be called which is sort of an internal callback in Glimmer which sort of triggers a re-render, right? So that is basically how the tracked decorator in inside of Glimmer works. It just replaces your original property with sort of a wrapper property that will make sure that whenever the property is set and internal callbacks sort of in Glimmer is called which will then trigger a re-render. Next, let's look at action. And as you all know, the main thing about actions is that they are closures that are already sort of pre-bound to the correct context, right? So you can just call them as a function and they will be running with the correct disbinding, sort of, right? So basically, besides a bunch of other things like you see the dotted lines here basically are like relatively big parts of the actual code that I left out here. But sort of one of the main things that the action decorator does is it just, it binds the method you're decorating and assigns it to a hash of actions, right? And that allows you then to use like the method as an action from the template. So this is decorators in Ember. They are a great way for abstracting logic that is non-essential to your application but that is maybe only essential for the framework or only essential for some other system sort of you're using. But there's no stable spec which means you don't want to write your own unless you have lots of time and lots of willingness sort of to potentially rewrite lots of the internals of the decorators you're writing. And that's all that I have. Thanks. Unfortunately, I can't take questions. Unfortunately, I can also not talk to people sort of after the talk or in breaks or whatever but we'll repeat all of that I guess next year in Portland or at Ember Fest in Europe this year. Thank you, bye-bye.