This talk discusses the challenges and advantages of using Ember as a platform for "designing in the browser." It describes the compromises and benefits of our approach.
boutique by design… a multi-disciplinary team of designers, developers, and strategists. Everyone here does a little bit of everything…” …The reason I’m highlighting that marketing copy not because I’m a shill, but because it’s the reason we’re talking today at an Ember meetup…
That means sometimes they write Ember code and we want to share our the experience and lessons learned working with Ember as a design/development team. I think we have a really unique perspective.
it provided a lot of tools we could use for the 4 or 5 sites that we had planned on. Add-ons and reusable components would allow us to mix and match pieces for different sites.
was also really attractive to us. Our designers had some been using twig partials for years and been breaking up their styles and javascript into modules…
you don’t have to learn some new way of styling to use Ember. Certain other frameworks have their own way of handling styles, and other teams at our company have battled with them. In ember your standard SASS workflow is just fine.
Book Title • Contributors: Author(s), Illustrators, etc • Description • Look Inside • Excerpt • Series Info • Illustration examples (if applicable) Medium Priority • Praise • Awards • More from this author • You may also like… • Suggested Age • About the author • Date of release • More from the author • Videos (?) Informational • Slideshows (?) • Teaching Guides (?) Low Priority • Format • What kind of book is this? (Genre / category) • ISBN (maybe strike it) • Number of pages • Imprint • Size of book • Author headshot • Author Tour info • Videos (?) General / Promo Trailer
Author(s), Illustrators, etc • Description • Look Inside • Excerpt • Series Info • Illustration examples (if applicable) Medium Priority • Praise • Awards • More from this author • You may also like… • Suggested Age • About the author • Date of release • More from the author • Videos (?) Informational • Slideshows (?) • Teaching Guides (?) Low Priority • Format • What kind of book is this? (Genre / category) • ISBN (maybe strike it) • Number of pages • Imprint • Size of book • Author headshot • Author Tour info • Videos (?) General / Promo Trailer Possible Book Page Content
at first, and the main reason was because I didn't really know what I was doing with javascript. I thought I knew how to write javascript, but really knew how to write…
a designers bread and butter, but I found that this type of interaction to be one of the hardest parts of working with ember. Even though I understand now that its about “Actions Up Data Down,” I honestly still don't know how to do it.
in twig and liquid so I thought I was fine, but when I actually started working with Ember, I realized that components had a lot more to them. Things were harder when I .hbs and .js were involve. There were a lot of new questions…
default Ember.Component.extend({ classNameBindings: ['book-‐tease'], tagName: 'article' … }); .hbs .js - Do I specify a container class when I use a component or in the JS. This seems kind of trivial, but I hated having a ton of extra `. ember-view` tags, and I didn't want to deal with
in jest, but I seriously spent a lot of time (my personal time) figuring out how to clean up some of the annoying things that get on designer’s nerves. Dumb quotes,
cleans up lots of the typical inconsistencies typographic issues * * @param String text * @returns String */ export default function apiTextCleanup(text) { let type = typeof text; let str; if (type === 'object') { str = text.string; } else { str = text; } str = str.replace(/&#(\d+);/g, function(match, dec) { return String.fromCharCode(dec); }); // replace any double (or more) conseq spaces with a single whitespace str = str.replace(/\s{2,}/g, ' '); This never would have happened if I asked chris to do it.
is fine. And I didn't need to worry about all the other stuff. Some of the fundamental concepts are still a bit fuzzy for me, but I think thats fine. Turns out Chris was hiding a ton of ember from me because I didn’t actually need to know it. Eventually, Chris would introduce me to some new ideas.
from 'htmlbars-‐inline-‐precompile'; moduleForComponent('book-‐page-‐topper', 'Integration | Component | book page topper', { integration: true }); test('it renders', function(assert) { // Set any properties with this.set('myProperty', 'value'); // Handle any actions with this.on('myAction', function(val) { ... });" + EOL + EOL + this.render(hbs`{{book-‐page-‐topper}}`); assert.equal(this.$().text().trim(), ''); // Template block usage:" + EOL + this.render(hbs` {{#book-‐page-‐topper}} template block text {{/book-‐page-‐topper}} `); assert.equal(this.$().text().trim(), 'template block text'); }); If we have designers making components with ember-cli they’re going to be generating a lot of integration tests. You’ll get a bunch of PR’s with this…
import hbs from 'htmlbars-‐inline-‐precompile'; // moduleForComponent('book-‐page-‐topper', 'Integration | Component | book page topper', { // integration: true // }); // test('it renders', function(assert) { // // Set any properties with this.set('myProperty', 'value'); // // Handle any actions with this.on('myAction', function(val) { ... });" + EOL + EOL + // this.render(hbs`{{book-‐page-‐topper}}`); // assert.equal(this.$().text().trim(), ''); // // Template block usage:" + EOL + // this.render(hbs` // {{#book-‐page-‐topper}} // template block text // {{/book-‐page-‐topper}} // `); // assert.equal(this.$().text().trim(), 'template block text'); // }); Commented out tests! I could uncomment this and write tests but we have to keep moving, and I can’t expect a designers to write tests. So many components just go untested. I’ll test the most critical and fragile parts of the application with unit and acceptance tests, but you have to pick your battles. You just can’t cover everything a designer is going to generate.
) 100) count} Add one to the thing. +1 </button> <select onchange={{action (mut vehicle) value="target.value"}}> {{#each vehicles key="@item" as |vehicleChoice|}} <option value={{vehicleChoice}} selected={{eq vehicle vehicleChoice}}> {{vehicleChoice}} </option> {{/each}} </select> https://github.com/EmberSherpa/ember-reactive-helpers https://gist.github.com/ef4/8367f996eb7b57d1f7a5 I’m a clojurist, and I don’t at all mind sprinkling in a little declarative, lispy template logic. But this doesn’t look anything like markup. If I know ember pretty well and I have to stop in my tracks to groc code like this, chances are it’s going to stump a designer used to writing markup.
onchange={{action "updateSelection"}}> {{#each-‐in vehicles as |index vehicleChoice|}} <option value={{index}}>{{vehicleChoice}}</option> {{/each}} </select> So we just kept all that declarative template code in the component’s javascript. I know it’s not as fun or clever or easy, but I think an argument can be made that keeping that logic in the javascript is much simpler. To me, a lot of those features feel like a proprietary, lispy, DSL for combining markup and javascript. Separating the concerns as much as possible felt less complex to our team.
{{#if (lt index 9)}} {{#swiper-‐slide}} {{book-‐carousel-‐book-‐tease book=work}} {{/swiper-‐slide}} {{/if}} {{#if (eq index 9)}} {{#swiper-‐slide}} {{series-‐link series=seriesItem}} {{/swiper-‐slide}} {{/if}} {{/each}} {{/rhcb-‐swiper}} Designers with a background in templating languages with lots of logic, like twig are probably going to generate a few templates that look like this. Ember-truth-helpers were guaranteed to be a necessity…
{{#if (lt index 9)}} {{#swiper-‐slide}} {{book-‐carousel-‐book-‐tease book=work}} {{/swiper-‐slide}} {{/if}} {{#if (eq index 9)}} {{#swiper-‐slide}} {{series-‐link series=seriesItem}} {{/swiper-‐slide}} {{/if}} {{/each}} {{/rhcb-‐swiper}} Maybe this is code smell too. Nathan had come into the project already knowing the dangers of logic in templates and we agreed that this kind of template was essentially a last resort.
I always understood it very easily, I don’t know if I’m in the minority. Explaining it to a designer without the context of other patterns, anti-patterns, or experience in frameworks is hard to explain.
If we end up passed a lot of actions up and data down long chains of components a designer can step in, adds some new components in the chain, but forget to pass actions up and data down, the app breaks. This is where writing acceptance tests can really pay off. So these chains of nested components, tied together with actions passed up and down are coupled… Does this make them more complex? Obviously it’s better than the alternative patterns.
average color of the book cover and use that to style element in most components on the page. So the choose color action has to pass up the cover image component to the dimensional cover, to the page topper to the page, to the page controller and eventually the application route where it’s “safer” to apply a color class to the body. These chains of nested components, tied together with actions passed up and data down are coupled.
use a service to compute and store the current book cover color and then inject that service into every component that needs it to get the color or maybe the service just changes a body class. but now your asking your designer to consider services too!
hard or complex to a designer: it’s a third thing they have to think about.We often tell Ember beginners something like “services are an object oriented escape valve” or “services are only for global concerns”. And while those are true, it makes them feel off-limits.
with difficulty and dealing with complexity, and maybe that’s okay. And your job as a developer working with a designer is to simplify the complex stuff. Those collaborative solutions will probably make your code better. If you can’t explain your solution to a designer, you might need another solution.
helpers. Nathan already showed you some examples of where he really manipulated the text coming from the api using helpers. I liked to take those helpers apart and extract the logic into a util that I could use in other places like tests or components and import that util into the helper.
that leads to better solutions. Nathan was creatively coding features that I hadn’t thought of on his own. In a process where there were stronger divisions, I would have dumped most of his features in the backlog and said “I’ll get to it later, when it’s a priority”. He’s leveraging Ember to make his designs better as ideas come to him, rather than waiting for some developer to pick up the ticket.
using ember we have to keep the barriers to entry low. I think the transition from 1.8 to 2.0 was a big step making ember simpler and easier too. bind-attr was crazy, I think we all know this now. The excellent documentation is we have is another. I think the popularity of certain other frameworks has a lot to do with perceived simplicity and ease of use. [Nathan] Or at least allow for a simpler view of ember. We were able to get to some really cool solutions that we may not have reached if we weren’t both writing code, and the simplified view of ember was what allowed me to contribute.
at least allow for a simpler view of ember. We were able to get to some really cool solutions that we may not have reached if we weren’t both writing code, and the simplified view of ember was what allowed me to contribute.