 Hi everyone, thanks for coming. Today I want to spill the beans on things I've learned writing a number of popular Ember add-ons and share thoughts on the four things that I think make an add-on good. So firstly, my name is Lauren. You might know me as Sugar Pirate. And my skills include dad jokes, ordering bubble tea for my colleagues and then drinking all of it, and being Australian. Because of these highly valuable skills, I work at Netflix on applications that power the world's largest studio. So come to our booth later if you're interested in what we're up to. So add-ons, chances are you've used one. Raise your hand if you have at least one add-on in mind when I say good add-on. Oh, that's awesome, it's a lot of hands. So last I checked, there are actually more than 3,500 add-ons in existence if you check the emberaddons.com website. And in the beginning when add-ons were first introduced, it was actually really tough to write one because a lot of features didn't exist in both Ember and Ember CLI. And in the past you had to resort to like hacks or intimate API to do certain things. But I think we can all agree that add-ons have gotten pretty great over this time. But out of 3,500 add-ons, how many are good? This was the question that made me think about this whole talk. And I have a very simple theory that there are four major things that go into contributing to what makes an add-on good. So firstly, the add-on needs to solve an interesting problem. It doesn't have to be an extremely difficult or challenging problem. Something simple done well could still qualify as solving a useful problem. But it has to solve it so well that someone else would rather use your add-on than to build it themselves. Secondly, it needs to be straightforward to set up and use, and that usually means good documentation, examples, and a low barrier to getting started. And honestly, I think this is where most add-ons fall short. Third, the API needs to be delivered. It doesn't have to be perfect, but you do need to put some thought into it, and it can't be an ad hoc API. And this is really tricky to get right on the first try, but thankfully that's why semantic reasoning exists. And finally, it has to be reliable. Or in other words, it also needs a meaningful test suite. And this is especially true for add-ons that aren't presentational. People want to use your add-on to solve problems and not cause more problems for their application. And a test suite is a good way to give people confidence about your add-on. So which add-ons for this bill? There are many, but these are some of the more popular ones. We just listened to Mac T's talk about Ember concurrency. I have talked about it a lot. My coworkers are probably bored to death with me talking about Ember concurrency, but it's probably my favorite add-on so far. It's got really great documentation. The API is very simple as you just saw, and it solves a really difficult problem. Ember power select is also an add-on that hits all those four points, in my opinion. And you would think that a simple select dropdown would be simple to build. It's just a simple select, or how can it be? But it turns out it's not that simple, but Ember power select makes it a really nice experience. Liquid fire, of course, needs no introduction. Provides a very nice declarative DSL for you to declare animations that were previously not possible. It's also very easy to use and very well documented. And finally, Ember CLI deploy deployment is so different across different teams and companies, but Ember CLI deploy is flexible enough to handle all, or if not, I mean most if not all of it, and it's also very sensible. And these are just some of the more popular add-ons. Now when it comes to running good add-ons, I think there are many approaches, but personally I like to practice DDD documentation-driven development when I make a new add-on. Documentation, document, okay I'm not gonna do the whole thing. And the main reason is that it helps me think ahead of time what the developer experience should be. You know, what kind of API does this add-on need to surface, and then from there, you start to write tests and you can do a test-driven development against that API. Because it's true, if you don't document something, how will they know that it exists, or how will they know to actually use this feature without spending hours digging through your source code? Some languages even rightfully treat documentation as a first-class citizen. So this is Elixir, and the examples in the comments in gray, they can actually be run as tests. And unfortunately this isn't a language feature in JavaScript, which is really sad. But documentation is so important that some add-ons even have their own dedicated documentation sites. While this is really nice to provide, by no means is it required, you can certainly have very decent documentation with a markdown-based readmealone. And this is typically the place you should start anyway with documentation, and you can always visit making a fancy pants doc site in the future. If you are in the habit of commenting your code with JS doc or UE doc style comments, then you can also find add-ons or other JavaScript libraries that will help you generate documentation. And even if you don't, they are still a really good way of teaching contributors how to contribute to your code. So let's say you've done all of that. You have an add-on that solves a really interesting problem. It's well-documented, has a good API, and it's well-tested. Now what? Well, in most cases that's not sufficient by itself. And the thing is, and this applies not only to open source, but generally speaking, projects require two things to be successful. First, it has to solve a problem. And if you've done those four things I mentioned earlier, you've already got this in the bank. But more importantly, building it isn't enough by itself. And you also actually have to convince other people to use your add-on or your library. And again, this is not only true for open source, but many things in life. There was this really great talk at ReactConf by Chung Lo on the meta language and what he describes as the meta language is the stuff that goes beyond the code. So these are things that like blog posts, videos, conference talks, documentation, whatever else, a thought leadership would be a good one. These things are really important, but they're not codified into the library or the language. Of course, anyone can build an add-on, but the project doesn't end when you hit NPM publish. In fact, it's only just started. Luckily for us, there are many ways to spread the word. You can write about it, you can record a talk, record a video, you can do a talk at a conference, like MacD, and people do wanna listen to learn about it because no matter how mundane or technical or boring you might think it is, it's also a really important step in getting feedback so you can improve on this library. But if you're like me, despite being up here on stage, when I create new add-ons, I tend to write about them first. Personally, for me, writing has the best ratio of effort to reward. Writing helps me communicate my ideas better, but I think your mileage might vary. And as an aside, I'm still running this Emberway publication, so if you do wanna write about something that you've written, let me know and I can help you publish it. So in this talk, I wanna share my experiences and lessons learned writing add-ons, and hopefully it can also inspire you to start writing add-ons of your own. So first, let's take a quick look into what exactly goes into an add-on and how to think about an add-on structure. So when you generate an add-on for the first time, you'll notice that the folder structure looks very similar to an Ember application. But one of the main differences is that it has an add-on folder, but otherwise it mostly looks the same. And there are a few things to note though. So on a high level, the add-on application and test folder live in Emberland and in these folders, you're actually working in the framework itself and Ember CLI helps glue it all together. On the other hand, there are folders which are in Node Land or in other words not in the browser and these are all files that are used by Ember CLI when the add-on is installed into the consuming application. Now in the add-on folder itself, we can think of it like a source folder for your add-on and most logic lives in here and these files won't get merged into the consuming applications tree unless you also export these files in the app folder. As a rule of thumb, I only export things that are part of the framework like components, helper, services and so on or other parts of the add-on that people might want to override. So here in this example, we need to export this helper so that the user can actually use it in their template. But if the user has an append helper already in their application, then that will actually take precedence over the add-ons helper. So in that way, they can override an implementation if they need to. And this is really important to think about because you want to be deliberate about what gets merged into the consuming application and you don't have to export every single thing in the add-on folder and it's often not recommended and you can think of it like exporting is making something publicly available so and you don't really want to make everything publicly available. Now in scenario where another add-on conflicts with yours, it is possible to specify which add-on will win. So here, Ember Chain Set Validations which is a plugin for another add-on called Ember Chain Set. These two add-ons both define a chainset helper but I wanted the Ember Chain Set Validations helper to win. So here you can actually be very explicit and say that this add-on should be installed after Ember Chain Set and therefore its helper will take precedence. One thing to note though is that even if you don't export something in the app folder, it doesn't make it private and consuming applications can still access it if they know the path to it. And it is very easy to see all the modules that EmberCi knows about. I'm not gonna tell you what the command you need to put in the console to see this. I'll tell you later if you want to know. But keep that in mind so there's no real concept of private modules here. In addition to the add-on and app folder, add-ons can also introduce blueprints and blueprints are interesting. You've definitely used one before. These mostly look like JavaScript but you'll notice the ERB-like syntax, the embedded Ruby-like syntax where you can put these, I don't even know what you call these, arrow percent equals. And these will be used by EmberCi to dynamically inject different things into these files when they're generated from this blueprint. You can also look these up on the EmberCi docs. These template variables are provided to you by default but you can also define your own in your add-on which is very useful if your add-on is extensible in some way. One thing I also note about node LAN is that you get access to the add-on hooks in the index of your add-on. And these let you work with the add-ons build directly and you can do a lot of things here like include custom EmberCi like commands, you can include, choose files include to exclude, you can add preprocessors and so on. So let's go through some examples of add-ons that make use of these hooks and see how they use them to do the features that they include. Ember test vectors is a really great add-on by the folks at Simple Labs, the same people behind Ember Simple Off. And what this add-on does is that you define a data test selector attribute on your HTML elements. And then this test selector can be used in your tests to select elements. But the cool thing about this add-on is that it will actually strip these data test selectors away in environments that you tell it to. So you don't have to pollute your production HTML with unnecessary attributes. And to do this Ember test selectors uses two main EmberCi hooks. So first it has a preprocessor to walk the tree and then it finds and removes those data test selectors from your template. These test selectors are very useful again, instead of selecting something by its class or its ID or whatever other attribute which can be very brittle. If you, for example, you change the class name because of the styling, then it's really good because the test selector is decoupled from the presentation. Ember test selectors also makes use of the tree for add-on hook in order to remove itself from the build if the test selectors are being stripped out. After all, the add-on becomes unnecessary in production, right? Because if you're stripping out HTML, why do you need test selectors? So it will actually remove itself from your application and it will bloat the final production asset. And then Ember Composable Helpers is an add-on I co-authored with Martin while I was at Dockyard. It's a relatively large library that includes a lot of helpers. And it doesn't really make sense to include all of them if you're only using one or two in your application. So we use the same hook as well to include or exclude specific helpers from your application. In the add-on, the tree for add-on hook will call a filter helpers method which then uses this regular expression to test what file names it needs to include or exclude. And then based on configuration in the consuming application, we can be and say like, oh, right, I only need helper x, y, z and I can just remove everything else because we're not using them. And finally, Ember CI Deploy is an add-on that we use a lot at Netflix. It makes use of custom commands to give you a really nice interface in which you can deploy your applications from the command line. And the nice thing about this is it actually helps you make your deploys automatable so you can have, for example, a CI build deploy an application after a test suite runs or whatever else. And custom commands are really simple to add to an add-on. Ember CI Deploy defines them in a separate folder which also is a nice way of just separating it out and not having this massive index.js file in your add-on. So I've written a couple of add-ons now and throughout the experience, I've learned a thing or two, a few hacks here and there that I wanna share but don't use the hacks. So first, I wanna talk about the developer experience. It's really important to think about how others will use your add-on as you build it. First, in your documentation, it's super useful to describe why the add-on exists and what it does. That's something that's actually missing from a lot of add-ons, like, what does this add-on even do? Why does this exist? Tell people it's really important. And you don't need to write an essay worthy of thought leadership. It's just describe it simply. Just a little bit of explanation goes a long way in helping people understand the goals of your add-on, how it helps them solve a problem and how they can even contribute and make your add-on better. Next, it might be obvious, but you should explain in detail how someone might use your add-on. Again, this doesn't need to be a fancy website. And then depending on the kind of add-on you're writing, this might make sense for library kind of utility add-ons. I will typically detail how to use the public API for an add-on in ways that I anticipate they're used. So, you know, it just gives like a simple example of how you use this feature to do some, like the 80% use case. And I take inspiration from documentation, like from libraries like Lodash and Ramda, for example, but this doesn't really work for all add-ons. You know, it really depends on the kind of add-on you're building. You know, if your add-on introduces a new way of thinking like Ember Concursy, for example, then this kind of documentation isn't enough and you definitely need to explain your ideas more. And if you do have the time for it, it can be very effective to create live examples of how to use your add-on. This shows off your add-on directly and gives people more confidence that they'll be able to use your add-on to solve your problem. So here's a really nice real example on the Ember Concursy website. Are you sick of Ember Concursy yet? And it's even more appropriate when your add-on is presentational. So, for example, Ember Burger Menu, the demo site and documentation site, literally dog food is the add-on right there. It's awesome. And Ember PowerSelect, again, also does a really great job here. You can actually try it out in the docks itself. But if your add-on is presentational or if you're lazy like me and you don't want to put together a whole fancy site, you can use Ember Twiddle, which is really great. I think I'm not sure when, but Ember Twiddle now has add-on support. So we can actually install an add-on into a Twiddle, which is awesome. Thanks to all the Ember Twiddle people. And personally, I like this a lot because it becomes a live playground that you can share and people can actually try out your add-on and edit it a little bit and see if it works for their use case. And this is actually kind of like, try before you buy, right? Another thing that seems obvious is that your add-on needs meaningful tests. The good news is that Ember makes your life relatively UV now, thanks to all the awesome Ember CLI folks. For example, by default, your add-on will run tests against different versions of Ember. This is all by default, you don't have to do anything. But in some cases, if your add-on explicitly needs to support like a really old version of Ember or a very specific version of Ember with some weird edge case, then you can actually test that explicitly in the Ember Try config. And yeah, this is really useful. And if you also use Travis CI, which is free for open source libraries, then you can make use of the build matrix, which will let you specify different variants of the build to test in parallel, which is really nice. And you can even also specify which of these builds are allowed to fail. So, you know, if you see at the bottom, I'm not sure if you can see it, but Ember Canary scenario is allowed to fail. And this should give you and your users more confidence that your add-on works as expected in different versions of Ember. Additionally, it's also possible to test your add-on and your application against a real browser. There are various ways to do this. For example, in the future, you might actually use Headless Chrome instead of Normal Chrome. And there are a lot of add-ons that actually do this. So you can check out their Travis configs, for example. Now, one more thing that's crucial for a lot of add-ons is the ability to configure them in some way. And this is one area where I feel it's not super straightforward and there are a lot of ways to do so. But I don't think it's documented very well. So the first method is one that I saw was adopted by LiquidFire. So in LiquidFire, there is this file called a transition map, which looks very similar to a route map. And you place this file in the app folder of your app. And somehow, magically, it knows how to pick this transition file up without you doing any other work. And this is really nice because it makes configuration quite painless. So let's look at this transition map a little closer. So what is it? It just looks like a really simple export of a function, right? And somehow this functions context, you know, the this keyword, you know, it knows how to define transitions, it knows how to define all these other really nice DSLs, very similar to Ember's router. LiquidFire makes use of the Ember resolver to locate this file and then invoke the function with the new context applied to it. And this is slightly intimate API here because I kept it small. But you can see that these three basic files app.js resolver and router.js, you actually can locate them with the factory with their magic incantations. And factory four is a new feature. I think it's already in Ember. But if you're all supporting an older version of Ember, you can use the Ember factory four polypool so you don't have to use that intimate API that I just showed you. Now, there's nothing special about the transition map. For example, it exports just like any other JavaScript file in Ember. And that means in your scenario, if you're making an add-on, you could say, you could tell your users to export a plain object. You can export whatever they want, whatever you want. And then your add-on can look for that file and then pick it up and do the configuration there. So it doesn't have to be a function like in LiquidFire. That's just the way LiquidFire decided to do it so that they could have a nice DSL. Next, you can also have your user define their configuration in the config environment file. This is generally an older practice, but I think it still remains useful where you want your users to be able to configure your add-on differently in various environments. So for example, Ember Metrics is an add-on I wrote that gives you a nice API on top of various analytic services like Google Analytics, Mixpanel, so forth. So you can actually track events or page views with one API instead of having to call like five different services in your application. And in this case, it's actually really useful for us to be able to do things differently based on the environment that the application is being built in. So you might not actually want your development environment like you're just clicking around and drop down a hundred times to trigger production analytics because your marketing team will be like, wow, we're getting a lot of youths, but it's actually just you. And so configuration environment that file seems like a really great choice for this add-on. And Ember Metrics installs an initializer into the application that imports this config file, sorry, the configuration, and then registers it in the container as config colon metrics, and then that object is injected into the metric service so that the service can access the configuration. Now in the service, you can just access it like any other property, just like this get options, and you got your options, awesome. Note that this is all defined in Ember Metrics itself, so the consuming app doesn't need to do anything else. So this is really convenient. And another popular option is to make use of the Ember CLI build file, and this is a good way to allow configuration that happens at build time. So again, Ember Composable Helpers comes with a lot of helpers as its name suggests, but you don't want to bring in everything, so we let you configure it here where you can say like, I only want the increment helper, I only want decrement, but accept pipe. Yeah, you're not supposed to use them both at the same time, is this an example? And yeah, this is all handled in the add-ons index file, so the included hook lets you modify what goes in the build, you can whitelist and blacklist, and then if you have those functions returning new broccoli trees, then you can exclude or include those offers. And then depending on the kind of add-on, it might also make sense to allow users to extend it based on their needs. So again, with the Ember Metrics examples, it ships with some bundled adapters for different services like Mixpan on Google Analytics, but it doesn't define like an adapter for every single thing. And the idea is that with extensibility, we allow users to define their own adapters so you can write an adapter for your application against your bespoke analytic service or something else that we didn't build. And then this is also nice because it also strips away the adapters that you don't use. And these adapters are just plain Ember objects under the hood, except that the service, the metric service expects them to implement some specific interface. One thing to note about this approach though is that these plain Ember objects are not managed by Ember's container. And what that means is that you have to manage their lifecycle yourself. So you gotta delete them or destroy them, you gotta initialize them, blah, blah, blah. And then here in Ember Metrics example, we have a base adapter that all adapters inherit from. It doesn't really do anything but throw errors if you don't define a required method. And then each adapter will just implement those methods and you can start using it in your application. But the interesting part is in the service itself where we need, so even though you created an adapter, the metric service doesn't know that your adapter exists in your application. So we need a way for the service to discover them and essentially what Ember Metrics does is it uses the names that you specify in the configuration and then it tries to look it up. First in your application and then in the add-on. So again, so you can override the Google Analytics Adapter for example if you don't like the base implementation. And once you have a reference to that adapter factory, then the service can now just instantiate these objects as well and delete them and so forth. And yeah, that's a pretty nice way to do it. Okay, and then there's the approach where you operate outside of Ember. This is the dangerous part. So note that I don't recommend this approach but I just wanna talk about it. So in Ember Chainset Validations, which is a validation library, validators and validation maps are plain functions and objects, they're not Ember objects. So what that means is that we don't get access to the container. And so to allow our users to override validation messages like the default, so we had to rely on a little hack. I kept this font size small so I don't read it. Again, I don't recommend this approach but in certain cases, hacks are useful, right? Yeah, don't do this. And yeah, again, in certain cases, hacks are useful. A lot of Ember, a lot of Ember and Ember through I start out as hacks but in a way hacks allow library authors to determine what the optimal API should be and I can see Rob laughing. But yeah, sometimes hacks are okay but at your own risk. Another way to provide extensibility is the approach that Ember Service Worker does. So Ember Service Worker, the base add-on doesn't really do anything except take care of some basic infrastructure. And then in order to actually get some service worker functionality into your application, you need to install plugins and these plugins all do different things. So how Ember Service Worker does this, it looks at the Ember Service Worker plugin keyword in the add-on. So it actually can look at the add-ons, these plugin add-ons package JSON file and determine if this is a plugin that it needs to then initialize and install as a service worker. And then in the add-ons post-process step, it will find those plugins, it discovers them and then it registers them in your browser. And actually this is actually a really nice approach for add-ons that are extensible. It's a nice way where people can extend your add-on without any effort on your part and it all just works. So as you can see, the more you know about internal workings of Ember and Ember CLI, the more features you can take advantage of and to use in your add-on. And there are a number of ways to do that but personally my favorite is to always keep this application open. It's called Dash, it's an offline documentation app. It's a really nice search feature. I have it open 100% of the time when I'm working and it's really easy to just look stuff up and it's not Ember specific. And again, there are many ways to get acquainted with the internal guts of Ember but I like this approach because you start from the public API you're familiar with and then you can start digging deeper and see how the framework actually implements something. So as a simple example, I was digging through the source for Ember Set that I discovered this unknown property and set unknown property which is very similar to Ruby's method missing. And there are actually a lot of add-ons that make use of this hidden feature as a way to intercept sets on objects. So there's definitely a lot of benefits into learning how the framework is implemented and there are always people on Slack who are very eager to help you understand the inner workings of Ember. And you never know, you might discover something interesting that you can make an add-on around. So those are just some of the interesting pieces of Ember I discovered when making add-ons and studying other people's add-ons. And there's definitely a lot more to discover so I hope I've motivated you enough to start digging deeper and maybe write an add-on of your own for your team. But stepping back from the tactical stuff for a moment, add-ons are ultimately about open source. And when you write your first add-on, open source feels really scary. Your code's gonna be live for everyone to see and criticize but don't let that stop you. Your first add-on doesn't need to be amazing and you should at least give it a try even if it's really, really simple. If you do enough of it, you'll get a feel for it. Personally, Ember was my first introduction to authoring and maintaining open source libraries. I think my first add-on was Ember CLI Flash and I remember when I first open-sourced it I was really embarrassed by it. And if you do this even more, you become more confident and level up quicker. Open source teaches you a lot, not just on the technical side of things but also in terms of your communication skills. So as engineers, we might tend to focus too much on the nitty-gritty details and we forget that ultimately, we work with people, you know, real-life people. So sometimes our communication skills can tend to suffer. And finally, if you do open source long enough, you could be this person and write your own JavaScript framework. All right, so at some point or rather in your open source career, you're gonna get to the stage where you can no longer devote all your time, your free time to a single open source library. And in those scenarios, it's actually really important to be able to relinquish control and trust other people to step up and maintain your add-on in your place. And maintaining, if you ever have this scenario where you inherit a very popular open-sourced library or if your library becomes very popular, then you will find that it's actually very exhausting to maintain people like opening issues, they're yelling at you, they're calling your names. And it's very common to feel frustrated and sometimes you might even grow to hate working on this library because people can be quite toxic. And in those scenarios, it's really important to know when to disconnect. People will say mean things about you for sure. They will say mean things about your code, they'll make personal attacks against you. Now this is by no means normal and it's not something we should tolerate, but it does happen and again, when you start working in open-sourced, this technical part of it is only, probably have the challenge. And finally, if you do decide to start in the scary world of open-sourced, please adopt Sanver. Thankfully we have tools to make it all easier and be a good open-sourced citizen. All right, we've talked about a lot today. We first, we looked at what the major differences are between an add-on and an app. We learned that the add-on folder is the guts and the app folder is what's merged into the consuming application. Add-on hooks are really powerful, so do check them out. Then we talked about different approaches to managing the developer experience. Good documentation is really important as well as meaningful tests and you might want to take some time to think about how your add-on can be configured, how it can be extended by other people. And finally, remember that open-sourced is not just about the code. I hope my talk will motivate you to get out there and enter the scary world of open-sourced. You can reach out to me on Twitter. You can look at, look for me after the break if you have any questions. Thank you all for listening. You've been great.