 So, for those who don't know me, I'm Mike North. I work in Silicon Valley for Yahoo, where I'm the UI engineering lead for their ad platform. This is the first Ember app of many that Yahoo started building about two years ago. And now it's kind of the heart of the Ember ecosystem. There are many other apps that have sprung up since then. Additionally, with Tracy Lee, I run a meetup called Modern Web UI that aims to foster cross-pollination between all the different framework communities so we can share our best ideas with each other. When I have time, I contribute a little bit to open source. Hopefully we'll be able to keep that going as things get busier this year. These are a couple of the repositories that I've made a little bit of an impact on. So, I'm always looking for projects that need a little bit of love. So, ping me if you know of one. The path I've taken to becoming an Ember developer, it started with C and C++, and then writing Java APIs, and then getting into Java Swing. All of these languages and frameworks felt like there was something missing. Finally, when I got to Rails, there were these great composability patterns that I found, and everyone has their own particular favorite thing about programming language or a framework that makes it feel right for them, and for me it's composability. This is how I feel when I get really great patterns that I can mix and match with each other and sort of build up a toolbox and as a project grows, be able to do new and interesting things really quickly. So, today I'm gonna first talk a little bit about what Yahoo is doing with Ember, where we've come from a couple of the pain points we've hit. Then I'm going to help nail down what composability is. So, as we talk about a couple aspects of Ember and of the apps that you guys are note out writing, what's the checklist to see whether something is composable or not? And then we're gonna dive into four areas, style, computed property macros, components and tests, and talk a little bit about how you can do these in a composable way today. So, as I said before, Yahoo has this big ad platform that's sort of the heart of Ember at Yahoo, but there are 14 Ember apps in production. There are nearly 70 developers who write Ember code as part of their day-to-day work, and we have our own internal add-on ecosystem. We're hopefully starting to contribute more to existing solutions rather than homebrew our own. And it's really, it's been a great decision to go with Ember. It's been a great decision to go with an opinionated framework. So, here's what the app looks like. Ember is part of what's helping revive good UI at Yahoo. And going with single-page apps is a big part of that. So, what is composability? So, for the purpose of this talk, so composability can mean a lot of things. But for this talk, let's think of three points. One is recombinant self-contained pieces. So you're looking for little building blocks that you can mix and match to do new things with existing code that you weren't necessarily planning to be able to do when you first wrote the code. In order to do that properly, you have to have conventions and contracts so that little pieces are interoperable. And a good composability pattern should promote and encourage reuse so that you're essentially prepared for whatever someone might do with your little building blocks. As far as why we should care about this, why this is important to Ember developers and developers in general, you get to leverage the code you already wrote in new ways. Turn it around and use it differently to build some new functionality. You get to build apps in a more expressive way. And what that means is the way you write the app, the way you define something is much more fluid, much more in line with how you would describe it to a person in human language. And it also opens the door for unforeseen features in use cases just sort of falling out of the code that you've already written because you're more focused on the blocks and not building something super specific for a given purpose. So these are the four areas I'm gonna talk about today. We'll start with style and move on to computed properties and then finish with components and tests. So who is used to seeing this kind of style in their app? All right, a couple, thankfully maybe we've already started moving in this direction. I used to see this all the time, especially before people started getting used to Bootstrap and maybe not using Bootstrap or other UI frameworks, but following similar conventions, you really don't know anything about what this div looks like from reading through a template. You don't know how it's sized or where it's positioned. This is the declarative way to do this. So it's the same style, but you're using these little tiny atomic, single purpose CSS classes. And now if you're reading through your handlebars or you're reading through your HTML, you can learn a lot more without having to compare your style and your structure side by side. So the key to doing this is make your CSS classes small and single purpose and make sure that as you're building out new code, you're trying to stick to these and you add new atomic classes where necessary, but try to leverage what you have and try to make sure that you're sort of following these conventions and you end up with a lot less style to maintain more expressive HTML. And you can mix and match these classes to define whatever you want to define without actually having to worry about affecting other things for example, by having a new rule that's not specific enough. So one thing that is a lesson learned at Yahoo from building apps at a very large scale is we add classes and attributes to DOM elements for a variety of reasons. And you wanna make sure that you decouple these concerns. So here we would wanna make sure that if we have this class large input, we wanna be able to freely change that without breaking tests. So what we've done at Yahoo in the ad platform is we add this attribute called an auto ID and you can call it whatever you like, but for all of our testing selectors, we always refer to this attribute which is always unique to a particular page and this lets us freely refactor style and structure without having to worry about the test breaking just for that reason. So it's a nice way of keeping these separate and making sure that if you change your tests, your style doesn't break and vice versa. All right, so that's the easy one out of the way, style. Now moving on to computed properties. So this is the basic idea of how you can, you get a computed property. Essentially it's a recalculation function with a caching capability built on top of it. So you call it the first time, it'll calculate and return its value and you call successive times, it will return the cached value. If a dependent key is changed, the cache is invalidated. So the next time you call it, you will calculate a new fresh value and we'll hear more about this later today in one of the other talks. In general, you can think of computed properties as filters, right? So they're just like here's an example of RGB components turning into a hex color and sometimes if you have a reversible calculation, you can go the other way as well and have your setter setting it's dependent properties so that you can sort of have a nice, convenient binding for a particular use. So this is a big part of Ember apps. I think a lot of people, if you look at your controllers and if you look at your components, there is a lot of this going on. So connecting back to composability, we got to think about our building blocks and our building block here is a computed property macro. It's just a function that returns a computed property and this is part of the definition of composability. So this is an atomic building block. It's isolated. You can mix and match these to form a new component but not necessarily to form a new computed property unless you end up creating intermediate properties and they end up sort of dirtying your object because you're adding new intermediate computed properties just to build this big chain. So the composable part comes in with this library here. It's called Ember CPM. It's sort of the junk drawer of computed properties since it doesn't look like we want to add more to the framework itself. But you can see here we have a sum and a product computed property macro and we can actually nest macros inside other macros and it ends up that you can just have whatever property you actually want on your object and you express that by nesting and combining other computed properties. So I'm gonna tab over to a quick example here to show you the difference between these approaches. So here I've got a basic app for a restaurant menu and we've got a couple items on the menu here and we've got an order sort of your receipt. So we can add a hamburger and fries and you see that we've got a subtotal, a tip and tax. And in fact we've got some primitive properties here for tax and tip percentages and we can also give someone a discount. And I wanna express this discount in terms of a positive dollar amount. That's the most intuitive way to do it. So to do this without using any computed property macros at all it's pretty verbose for defining something simple. And we have to do a lot of multiplication and then we have to add everything together and invert the discount so that we subtract it from the price. We're not doing much here in the way of functionality but it takes a lot of code. So if we then switch to using the computed property macros available in the Ember framework what is essentially changed is this here. So we can use map by to get the price property off of each item in my order and then we'll have an array of numbers which we then can sum to get the subtotal. So that's great. That's a very succinct way of expressing this. But there was really no need to have this order prices property here. Like there was never, that was not part of the design. I'm not exposing that to anyone. And now another developer may come along and start using that or it might get set. It's sort of just there for the purpose of something else. So taking a look at this code here this is what's necessary to calculate what needs to be calculated. So if we use Ember CPM and Composable Computer Property Macros this is it. There are no recalculation functions. You can see we're able to nest product in another product to convert from integer percentages to a coefficient and then multiply it by the subtotal and then here we're summing three properties and then a computer property macro. So this is a great way if you find that you're doing a lot of arithmetic and a lot of conversions to start getting used to doing things this way. The test coverage is already there. You can build up a nice library of these atomic building blocks and mix and match them to get what you want. And it's surprising when you start getting used to thinking about things this way how much you can leverage a pretty small set of macros in order to do a wide range of functionality. All right, so that's great. Now we can mix and match style. We can mix and match computer property macros components. So this is a big one. And we're pretty close. So it's not the source of truth for state which is a good starting point. State starts to become messy if you're trying to mix and match and you don't know who's holding what. Components definitely promote reuse. That's the point. They're little modular chunks of view that we can freely use for various reasons. They're not easily recombinant though. They are in some simple cases but to really create something that starts to look like a DSL starts to look like very expressive. You can run into trouble in some ways. So we're gonna walk through an example of just building a card here and I'm using Ember CLI materialized just for style and for a goal. It has structure that it will render this way if we get it right. And this is the structure we're looking for. So if taking a look at it, we have a title. We have a body of the card. We have two actions down here. I don't think I can right now. Sorry. So I will show important chunks of it bigger in the next slide or a couple slides down. So one approach to doing this is to take the lowest common element approach. And that basically is taking the concept of yield and working backwards. So you can yield when you use a component in block form. And essentially if you're saying, okay well I'm gonna drop this yield in somewhere and everything that has the potential to change, we sort of have to capture that and pass in a lot of HTML. So this is that approach here. And on the left you can see we're not actually doing much of anything. Like this doesn't add any value. The markup is almost as bad if not worse than what we started with. So this is not useful. So another approach is the parent does everything approach. And that is in this case we're gonna pass in the title. We're going to use our block for the body of the card. And then we're gonna pass in an array of actions. And this will end up being a very specific card component that we can get to render exactly what we want. But this is not composable. So this doesn't give us this recombinant mix and match aspect that we're looking for here. So here's what we're going for. If we can get something like this. This reflects what it is to be this card. You have a body, you have some actions, you have a title and we really don't force you into using any other markup beyond that. Every important concept has some markup and then there's nothing more. So there is a challenge involving content projection. So we have four pieces of content we need to worry about. The title, the body and each action. And you can see that if the code's not too small here the actions need to be in their own special div. They're not something that can just be lumped into the yield. If we really do want to save the user, save consumers of our component from having to add a whole bunch of extra markup when they define a card. So we can, we probably know pretty well how to do the title. It's just a property binding. And we can use our one and only yield for the body of the card. The actions are where it gets tricky. So I'm gonna show you guys an approach to handling this that will allow you to project little pieces of content into components in a reasonable way. So the three things we need to make sure are true for this approach to work are, the children do not do the rendering. They exist for the purpose of capturing a piece of template, right? So the parent actually does the rendering. And in order for the parent to do the rendering the parent must be aware of the children. And so we need some registering and unregistering mechanism. So essentially what we're using here is nearest with property. And that's a way for a child component to search upwards through the component hierarchy to find something that has a non, something that for which a given property key exists. And so I just created a property called underscore WGE card, right? It's something that no one's really gonna touch and it's just really there as a means of allowing child to find parent and then child registers itself with parent, right? Child has its render method overridden with an empty function so that it doesn't render. And here's the parent with its HBS and if we look more closely at the pertinent section we're just iterating over these card action components, so each card action is a component and then we're gonna render a plain view and pass that plain view a template that is the template that was captured by this card component. And then we'll also pass parent controller along which is a computed property essentially to make sure that when actions are called they will end up firing on the controller. You'll have access to your view controller data. It'll be just as if you're using like a standard block component here. So what we have here is now the ability to project content into our component and that'll let us not only use actions but add other accessories to this card. Maybe you want an image. Maybe you want some sheet that slides up from the bottom but you're essentially free to add accessories and then they will each be able to place their important chunk of content in just the right place. And so now we have a card that we don't have to pass a whole bunch of HTML into but it's very, very, very expressive and it's very strongly connected to conceptually what is it to be this card? All right, the last one up is tests. So this is a big pain point for a lot of developers and at least from my standpoint working with the engineers at Yahoo, the better I can make the test writing experience, the lower our defect count goes and the more tests we actually get written. So we get more release confidence, we experience fewer actual bugs but there are some sort of speed bumps along the way that hold us back from getting there. So we recently had to deal with the sensitivity to order and timing and that had to do with like if you have some promise that is, some request that started in Setup Controller and basically not everything is settled by the time you arrive at that page. You know, depending on how you synthesize your API response there might be some sensitivity there. Brittle selectors are a big problem. We talked about that when we were going over style. Now we use auto ID, we use something independent of style to find buttons that we want to click and then also because we're not really writing dry tests there's not, there's some patterns but there's not really a great pattern that's resonated with us for dry tests. We still run into situations where one change will break just about every test that might test around that change. So and our tests look like this and I'm glad this code is too small for most of you to read. It's ugly as hell. It's essentially set up a bunch of API requests or API payloads, visit a page and then make your asserts. This should look very familiar. In fact, if I cross my eyes it's like I can almost understand what's going on here. So there's a lot of what we're dealing with here are API payloads and selectors and like the test has to be very aware of not just what is this page trying to do but how is it structured? What data is it asking for? And this is sort of bleeding into the idea of like what a test should be which is here is a scenario that I am testing. Here are the asserts that I'm trying to make. So page objects, who here has heard of page objects? Awesome, not nearly enough of you. So the concept of a page object is it's sort of a third level of testing API. If we think of the first level it's like jQuery and document query selector all. Retrieve a DOM element. Level two is the Ember testing API which is fill in and click and trigger event. These are your nice async helpers that are promise aware that that's probably what most of our tests are written in today. The idea of a page object is you take a given component or a section of your app and you handle all of the... You take care of all of the code that has to touch has to handle specific API responses or has to click a button with a particular selector. You take all of that and you build it into an object and you give yourself this great surface to interact with for writing your test that has much more to do with how the page works and what is this page about rather than what is the class on this button that I have to click in order to submit this form. All right, so I'm gonna kick over for another quick example here. Oops, come on keynote. All right, so this is what a page object looks like and this, I may open source the library for this. I think there's one that already exists it's Ember page object, wild guess there, but there is some school of thought that it's better to write these for your app because there's not much to them and they're very tied to the particulars of how your app works and they're not a big deal to write from scratch. So here's just a base class that I wrote which it's essentially giving me some common methods to like grab a DOM element but I'm building an assert into it, right? So this will fail if the element doesn't exist and fail the test if that is part of what I'm calling to make an assert. I built into it an ability to easily grab something by auto ID. This is just a convenience layer here. All right, so I want you to think back to this example that I had with the restaurant and the menu where I was adding hamburgers to my order. This is the page object for that page. So I've got some, I've got the ability to prime pretender with an API payload to respond with so I've synthesized my API that's needed for this page and then I've got methods here like click the menu add button. Give me the subtotal, give me the total. And essentially what I'm doing is I'm creating this object that encapsulates all of the particulars of the DOM that have to do with this page here. The test that I can then write looks like this. Much, much cleaner, right? This is something that you can have your product owners write. This is very, very easy. So this has been a pattern we've used at Yahoo and it has, I think before we started using it we had something like 7% test coverage after our initial sprint to get our MVP done and things have really taken off and we have much higher test coverage. Obviously it's easier to get higher than 7%, but. But we have good release confidence now, largely due to easing the burden of writing tests. So some tips for writing these objects. Always return this from your methods so that you can just chain things together. It's nice to write this big long chain. It looks sort of like Rx if you guys have written that. And the idea is that it's a big assert chain that at some point it's gonna break and it's gonna fail if your tests fail. That's exactly what you want. There is sort of a school of thought, do you just have this thing spit out? The page objects spit out values and you do your asserts outside of it or do you have the asserts baked into this object? I think that the victory is implementing this pattern one way or another. You guys can decide what's right for you there. And build page objects for components. This is the recombinant part. So if you have like a date picker and the date picker has, click on the field to open it, advance to a particular month, click a day, like that could be a page object in and of itself that's a child of another page object. Like restaurant menu instantiates a new date picker page object. This is the recombinant part. This is what allows you to mix and match and essentially to if you change your date picker, update it in one place, all of your tests will start passing again. So as I wrap up here, I feel very strongly that composability is right in line with the direction that Ember seems to be going in. If you look at the major highlights of, you know, the major developments to the Ember ecosystem recently, like add-ons and what's to come, like services, I mean, like, sorry, like engines, services exist. There is definitely an emphasis on being able to define encapsulated chunks of behavior of code and compose them in a way that lets you be extremely productive in building an app. So, and just to recap here, we now know how to take style and reuse it in a mix and match kind of way by using atomic CSS classes. We can use computer property macros in a composable way using Ember CPM. We have a content projection trick that lets us compose components in a way that goes beyond the basics, right? And then finally we talked about page objects and how you can use those to sort of get the DOM and API requests specificity out of your tests and to write really easy to read, really easy to maintain tests. So I hope you guys will start, you know, keeping an eye out for composability and I hope that this has helped shed light on sort of some new ways to address these areas. So you're talking about having child components sort of exist as a first class citizen. So I think that there exists a proposal as of late last week and maybe a core team member can help me here for introducing a syntax. If you've used Rails and you've used a form builder, you can say form four do F and then F dot text field. So I think that there are some ideas around adding something like that, which would really allow some more complete ways of delegating, rendering, you know, one way or the other. Or delegating, you know, who's doing what in a way that gets us the encapsulation we're looking for. Anything else? Yes. Could it be a cool world where people are shipping components in add-ons? Thanks. When people are shipping components in add-ons, our ship is kind of this kind of help, test helper with the component? I would love to see that. And especially, there's only really one pattern to follow and that's, you know, passing in an assert or I guess components don't really have to deal with Pretender, but you know, the means of getting a handle on the testing framework itself. So either we can find a way to integrate it with like Ember test helpers or we can sort of, as a community, arrive at some convention. But there's no harm in publishing something that makes, you know, like wormhole very, very testable. And that could be consumed just as the component is consumed by people's apps. Cool, that'd be neat. One more question on the content projection concept. Yes. It strikes me just intuitively, I don't know if this is true or not, that something like that might make Ember's rendering passes less efficient? Yes. And have you run into that? So it definitely will make the rendering passes less efficient. And I think that, so I've used this in places where I'm not all that concerned about performance. Like I wouldn't want to use this in a table cell, for example, and in each. But if I'm just rendering a card, one or two cards on a screen, or if I'm rendering a set of three tabs, you know, until we have some more established first class patterns that don't, I mean, this is a hack. This is a hack to do it this way. Until we have a first class way of doing it, I think that it's better to kind of acknowledge the hack and live with it than to try to find a more ugly and deeper hack that's trying to do things properly that the framework just, we collectively have not been able to add that to the framework yet. Cool. Yes. You have to maintain your page object to stay in sync with your component. So how do things getting out of sync there, how do the failures look different from a failure of your actual test scenario? Like how can you tell whether you broke a test or whether you have to update your page object? So ultimately you're just breaking a test, right? If you think about what we've replaced, really it's like, this element cannot be found. And perhaps if we look back at the base class I had here, so if you wanted to, you could add in your asserts, you know, a prefix that lets you know, like in which page object was this failure detected? You know, I think that there's definitely something to be added to this pattern for sure. And identifying where the error happens, that's another important like snag that if there is a good answer to that question, it will help people write tests better. It'll make the pain of breaking a test and going and finding the breakage quickly and fixing it, it'll make that easier. So I think that there are definitely ways to do it and just adding more information in the asserts is one. But that's a very good point. Knowing where the breakage happened is key. All right, thank you guys very much.