Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Design With Ember (speaker notes)

Design With Ember (speaker notes)

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.

Christopher Plummer

October 14, 2016
Tweet

More Decks by Christopher Plummer

Other Decks in Programming

Transcript

  1. Official Tag Line “We’re a free-thinking, fun-loving digital shop that’s

    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…
  2. Designers at Upstatement write code. …Designers at upstatement write code.

    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.
  3. Why Ember? [Chris] Why did we choose Ember for this

    project? Ember is a large and sometimes complex framework.
  4. Ember is pretty big and quirky. We knew going into

    it that the learning curve from jQuery to ember was steep. We evaluated the benefits of rolling our own bespoke, artisanal Backbone framework…
  5. But Ember’s conventions just let us get started faster and

    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.
  6. {% include “my-partial.twig” %} [ Nathan ] The component API

    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…
  7. {{my-component}} …but they had never encapsulated behavior and display into

    a single reusable, composable component. And that composability would come in handy across sites.
  8. [ Nathan ] Another big win for designers is that

    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.
  9. When we chose a user story from the backlog, we

    would look work with the client fully define the problem…
  10. Chis and I would then pass the design back and

    forth, working in browser / sketch / whiteboards until the feature was accepted.
  11. Possible Book
 Page Content Top Priority • Book cover •

    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
  12. Top Priority • Book cover • 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 Possible Book 
 Page Content
  13. Top Priority Book Page Content Book
 Cover Description Excerpt Contributors

    Book Title Series info A Look Inside Illustration Examples
  14. Most Universal Book Page Content Book
 Cover Description Excerpt Contributors

    Book Title A Look Inside Illustration Examples Series info
  15. Working this way with design and dev involved from day

    one meant that I was going to be writing a lot more ember code from day one.
  16. What was it like working working with Ember as a

    designer? What is it like working with a designer working with ember?
  17. It’s pretty good! It’s pretty good! I liked working with

    ember a lot, especially as i got deeper into it. It did take a bit of learning up front.
  18. It was really hard at first. Things were really tricky

    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…
  19. jQuery. I was mostly just toggling classes and replacing text.

    The jump from selector-based programming to components/data based programming wasn't easy.
  20. Some things just didn’t translate. You get a lot for

    free, but some of my old tricks didn’t work. For a designer who writes a bit of code, this was problematic.
  21. Things like toggling a class to open a nav are

    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.
  22. No more! $('.nav-­‐trigger').on('click',  function()  {      $('body').toggleClass('js-­‐open-­‐nav');   });

    You get a lot for free, but some of my old tricks didn’t work. For a designer who writes a bit of code, this was problematic.
  23. Components were scary I was used to working with partials

    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…
  24. {{book-­‐tease        class="book-­‐tease"        tagName="article"}} export

     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
  25. Where do I put my functions in components/whatever.js? - Working

    with data was new! Now i had to watch the model(?) to make sure things were actually coming down. I cant just put everything… wherever
  26. didReceiveAttrs? computedProperties? actions? - all of the sudden i was

    forced to make a lot more choices. Don't get me wrong, this stuff wasn't actually that hard, I just needed to think about how this stuff worked
  27. Logic-less templates :/ - Not being able to use logic

    in templates seemed like a deal breaker. But I pretty quickly realized that this kind of logic should be in the js.
  28.    titleLength:  Ember.computed('title',  function()  {          if

     (  this.get('title')  )  {              let  title  =  this.get('title');              let  titleLength  =  title.string  ?  title.string.length  :  title.length;              if  (titleLength  <  25)  {                  return  'book__title-­‐-­‐short';              }  else  if  (titleLength  >=  25  &&  titleLength  <  40)  {                  return  'book__title-­‐-­‐medium';              }  else  if  (titleLength  >=  40  &&  titleLength  <  62)  {                  return  'book__title-­‐-­‐long';              }  else  {                  return  'book__title-­‐-­‐too-­‐long';              }          }      })
  29. Once I learned the basics, we started to hit our

    stride. It’s pretty much like writing codez.
  30. This was really quick and easy for me to make

    [show some code add some more text]
  31. Helpers are also pretty sweet. We had to deal with

    a ton of nasty and inconsistent API text. I wanted to write some regex to clean it up.
  32. We had to deal with a ton of nasty and

    inconsistent API text. I wanted to write some regex to clean it up.
  33. export  function  cleanTrademarks([text])  {      if  (text)  {  

           if  (  typeof  text  ===  'string'  &&  text.length  )  {              let  cleanText  =  text.replace(/  *\(R*\)  */g,  '<sup>®</sup>')                                                      .replace(/  *\(TM*\)  */g,  '<sup>™</sup>');              return  htmlSafe(cleanText);          }  else  if  (  typeof  text.string  ===  'string'  &&  text.string.length)  {              return  cleanTrademarks([text.string]);          }  else  {              return  text;          }      }   }
  34. He should have 
 never taught me. I say this

    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,
  35. /**    *  Takes  a  block  of  API  text  and

     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.
  36. There are a lot of things I never fully understood.

    - WTF is “data down, actions up”? - I get scared when I have to write JS in the route - Separate logic and markup
  37. I only needed a little bit of ember, and that

    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.
  38. What it’s like working with a designer working with Ember.

    What is it like working with a designer working with ember?
  39. Teaching How much Ember do I teach? How many idioms

    do I enforce? When do we just use jQuery? It’s really not that daunting. Once nation knew the component api, there wasn’t much else to teach.
  40. Test Driven Development The first big compromise, and I know

    you are all going to judge me for this, is testing.
  41. import  {  moduleForComponent,  test  }  from  'ember-­‐qunit';   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');   });   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…
  42. //  import  {  moduleForComponent,  test  }  from  'ember-­‐qunit';   //

     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.
  43. <button  {{action  (debounce  (pipe  (r  'add'  1)  (action  (mut  count))

     )  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.
 

  44. <button  {{action  “increment”  count}}>Add  one  to  the  thing.  +1</button> <select

     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.
  45. {{#rhcb-­‐swiper  keyboardControl=true  slidesPerView=‘auto’}}      {{#each  seriesItem.works  as  |work  index|}}

             {{#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…
  46. {{#rhcb-­‐swiper  keyboardControl=true  slidesPerView=‘auto’}}      {{#each  seriesItem.works  as  |work  index|}}

             {{#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.
  47. DDAU Is Hard DDAU is hard. Nathan mentioned this earlier.

    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.
  48. Is DDAU Complex? So I started asking myself this question.

    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.
  49. Here’s a good example: on this page we extract the

    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.
  50. Services seem easier! Services can help here, and we can

    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!
  51. Are services complex or hard too? That still might feel

    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.
  52. DDAU is the developer’s job So we’re stuck just dealing

    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.
  53. Designers love helpers On the more positive side. Designers love

    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.
  54. Collaboration Again, trading ideas and code back and forth like

    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.
  55. Keep Ember Simple! If we want to get more designers

    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.
  56. Or at least let it be simple sometimes. [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.