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

Style Documentation for the Resource-Constrained

Style Documentation for the Resource-Constrained

Cd1faab1e45c363bc923e1db8bf12db7?s=128

Betsy Haibel

May 06, 2016
Tweet

More Decks by Betsy Haibel

Other Decks in Programming

Transcript

  1. @betsythemuffin Style Documentation for the Resource-Constrained Betsy Haibel

  2. @betsythemuffin getting things done under resource constraints 1. Have a

    vision of where you want to go 2.Figure out baby steps that will get you there 3....make those steps smaller 4....and adaptable to changing circumstances 5....and recognize that the finished product will resemble but not match your vision 6.Then go do the thing!
  3. @betsythemuffin

  4. @betsythemuffin domain-driven design for the frontend - All applications need

    a "shared ubiquitous language" for business logic - Most applications need a SEPARATE "shared ubiquitous language" for UI logic.
  5. @betsythemuffin you have an accidental styleguide

  6. @betsythemuffin Why document it? - Defuse fear of unfamiliar code

    - More useful conversations with non-engineers
  7. @betsythemuffin SCREENSHOT OF FAKE APP GOES HERE

  8. @betsythemuffin UI logic != Branding Guidelines

  9. @betsythemuffin what does belong? Look and feel of individual widgets

    - This can be as simple as a screenshot, or an embedded version -- and should be! look and feel of individual widgets
  10. @betsythemuffin what does belong? How widgets are arranged and grouped

    - What elements have sub-elements? What sub- and parent elements are allowed? - Can an element appear alone, or is it always part of a group? - What conventions demarcate elements and groups of elements? how elements are arranged
  11. @betsythemuffin what does belong? What problems does a widget solve?

    - "Only display notification boxes that relate to the user's current goal" - "Use accordions to Look and feel of individual widgets - This can be as simple as a screenshot, or an embedded version -- and should be! What UI problems does it solve?
  12. @betsythemuffin that's overkill we just use Bootstrap

  13. @betsythemuffin we "just" use Bootstrap

  14. @betsythemuffin the "just use Bootstrap" fallacy - Do you use

    all of Bootstrap, or a subset? - Do you have custom, non-Bootstrap UI elements? - Do you have implicit rules about how Bootstrap's used? - Do you copypasta markup a lot?
  15. @betsythemuffin barriers to styleguide adoption - Sheer amount of work

    - Justifying sheer amount of work - Inflexible styleguides are bad in real-world UIs - "Free spirit" designers - Worries about dead documentation
  16. @betsythemuffin this is agile forget about "done"

  17. @betsythemuffin this is agile brownfields are cool

  18. @betsythemuffin this is agile brownfields are cool

  19. @betsythemuffin this is agile brownfields are cool

  20. @betsythemuffin this is agile brownfields are cool

  21. @betsythemuffin piecemeal documentation must be alive to be useful

  22. @betsythemuffin if it accomodates what we've already got ....it's probably

    flexible enough
  23. @betsythemuffin three phases of incremental styleguides 1. Identify 2.Codify 3.Document

  24. @betsythemuffin step 1: identify

  25. @betsythemuffin tab sets cards

  26. @betsythemuffin step 2: codify

  27. @betsythemuffin <ul  class='tabs'>      <li  class='tab<%=  current_page?(cats_path)  ?  '

     active'  :  ''  %>'>          <%=  link_to_unless_current  'Cats',  cats_path  %>      </li>      <li  class='tab<%=  current_page?(dogs_path)  ?  '  active'  :  ''  %>'>          <%=  link_to_unless_current  'Dogs',  dogs_path  %>      </li>   </ul>
  28. @betsythemuffin <ul  class='tabs'>      <li  class='tab<%=  current_page?(cats_path)  ?  '

     active'  :  ''  %>'>          <%=  link_to_unless_current  'Cats',  cats_path  %>      </li>   </ul> <ul  class='tabs'>      <li  class='tab<%=  current_page?(dogs_path)  ?  '  active'  :  ''  %>'>          <%=  link_to_unless_current  'Dogs',  dogs_path  %>      </li>   </ul>
  29. @betsythemuffin module  ComponentHelper      #  <li  class='tab  [active]'>  

       #        <a  href='[href]'>[name]</a>      #  </li>      def  tab(name,  href)          classes  =  current_page?(href)  ?  'tab  active'  :  'tab'          content_tag('li',  class:  classes)  do              link_to_unless_current(name,  href)          end      end   end
  30. @betsythemuffin  <ul  class='tabs'>   -­‐    <li  class='tab<%=  current_page?(cats_path)  ?

     '  active'  :  ''  %>'>   -­‐        <%=  link_to_unless_current  'Cats',  cats_path  %>   -­‐    </li>   +    <%=  tab('Cats',  cats_path)  %>   -­‐    <li  class='tab<%=  current_page?(dogs_path)  ?  '  active'  :  ''  %>'>   -­‐        <%=  link_to_unless_current  'Dogs',  dogs_path  %>   -­‐    </li>   +    <%=  tab('Cats',  cats_path)  %>    </ul>
  31. @betsythemuffin  <ul  class='tabs'>        <%=  tab('Cats',  cats_path)  %>

           <%=  tab('Dogs',  dogs_path)  %>    </ul>
  32. @betsythemuffin  <ul  class='tabs  tabs-­‐left  span7  big-­‐text  red  maybe-­‐use-­‐cool-­‐font'>    

       <%=  tab('Cats',  cats_path)  %>        <%=  tab('Dogs',  dogs_path)  %>    </ul> what your codebase looks like, probably (no shame) (I've been there)
  33. @betsythemuffin "presentational markup" <ul  class='tabs  tabs-­‐left  span7  big-­‐text  red  maybe-­‐cool-­‐font'></ul>

      <ul  class='tabs  tabs-­‐-­‐primary'>                                                              </ul>
  34. @betsythemuffin quick (S)CSS refactors %span5  {      width:  48%;

      }   .nav-­‐-­‐primary  {      @extend  span5;   } http://krasimirtsonev.com/blog/article/SASS-­‐mixins-­‐extends-­‐and-­‐ placeholders-­‐differences-­‐use-­‐cases
  35. @betsythemuffin <ul  class='tabs  tabs-­‐left  span7  big-­‐text  red  maybe-­‐cool-­‐font'>    

     <%=  tab('Cats',  cats_path)  %>      <%=  tab('Dogs',  dogs_path)  %>   </ul> <%=  tab_set  do  %>      <%=  tab('Cats',  cats_path)  %>      <%=  tab('Dogs',  dogs_path)  %>   <%  end  %> plain HTML helper nesting
  36. @betsythemuffin <%=  tab_set  do  %>      <%=  tab('Cats',  cats_path)

     %>      <%=  tab('Dogs',  dogs_path)  %>   <%  end  %> class  LayoutHelper      #  <ul  class='tabs  tabs-­‐left  span7  big-­‐text  red'>      #      [block  contents]      #  </ul>      def  tab_set(&block)          css_classes  =  %w(tabs  tabs-­‐left  span7  big-­‐text  red)          content_tag('ul',  class:  css_classes.join('  '),  &block)      end   end what your view looks like build the tag yield control
  37. @betsythemuffin

  38. @betsythemuffin most things are too big for helpers def  card(options)

         #  set  options      #  main  code      card_classes  =  size  ?  "card  card-­‐-­‐#{size}"  :  'card'      content_tag('div',  class:  'card')  do          [              card_header(header_text),              (subheading.present?  ?  card_subheading(subheading)  :  nil),              image_tag(image_url),      #  ...   end such long many configuration much sub-helpers
  39. @betsythemuffin helper nesting again            <%=

     card(size:  'large')  do  %>                  <%=  card_header  'My  Awesome  Cat  Photo'  %>                  <%=  card_image    cat.showcase_image_url  %>                  <%=  card_badges  {                           favorite:  favorite_count                    }                  %>              <%  end  %> parent body
  40. @betsythemuffin ComponentBuilders in the view <%=  card(size:  'large')  do  |c|

     %>      <%=  c.header  'My  Awesome  Cat  Photo'  %>      <%=  c.image    cat.showcase_image_url  %>      <%=  c.badges  {               favorite:  favorite_count      }      %>   <%  end  %> like FormBuilders for … not forms
  41. @betsythemuffin Instead, use ComponentBuilders  def  card(options  =  {},  &block)  

    -­‐    content_tag('div',  class:  'card',  &block)       +    CardBuilder.new(self,  options      ).render(&block)    end build a thing yield control
  42. @betsythemuffin Instead, use ComponentBuilders def  card(options  =  {},  &block)  

       CardBuilder.new(self,  options).render(&block)   end View context
  43. @betsythemuffin class  CardBuilder      def  initialize(h,  options  =  {})

             @h  =  h          @size  =  options.fetch(:size,  'normal')      end      #  <div  class='card  card-­‐-­‐[size]'>      #      [block  contents]      #  </div>      def  render(&block)          h.content_tag('div',  class:  css_classes,  &block)      end      #  <h2  class='card__header'>[text]</h2>      def  header(text)          h.content_tag('h2',  text,  class:  'card__header')      end   end initialization render shell sub-renderers
  44. @betsythemuffin ComponentBuilder initialization class  CardBuilder      def  initialize(h,  options

     =  {})          @h  =  h          @size  =  options.fetch(:size,  'normal')      end   end grab the view context
  45. @betsythemuffin ComponentBuilder initialization class  CardBuilder      def  initialize(h,  options

     =  {})          @h  =  h          @size  =  options.fetch(:size,  'normal')      end   end configure top-level stuff
  46. @betsythemuffin class  CardBuilder      #  <div  class='card  card-­‐-­‐[size]'>  

       #      [block  contents]      #  </div>      def  render(&block)          h.content_tag('div',  class:  css_classes,  &block)      end   end build the outer framework yield to sub-renderers
  47. @betsythemuffin class  CardBuilder      #  <h2  class='card__header'>[text]</h2>    

     def  header(text)          h.content_tag('h2',  text,  class:  'card__header')      end   end
  48. @betsythemuffin ComponentBuilders in the view <%=  card(size:  'large')  do  |c|

     %>      <%=  c.header  'My  Awesome  Cat  Photo'  %>      <%=  c.image    cat.showcase_image_url  %>      <%=  c.badges  {               favorite:  favorite_count      }      %>   <%  end  %>
  49. @betsythemuffin nokogiri is your friend when you test these

  50. @betsythemuffin just HTML is ok tho

  51. @betsythemuffin step 3: document

  52. @betsythemuffin comment yr code module  ComponentHelper      #  <li

     class='tab  [active]'>      #        <a  href='[href]'>[name]</a>      #  </li>      def  tab(name,  href)          classes  =  current_page?(href)  ?  'tab  active'  :  'tab'          content_tag('li',  class:  classes)  do              link_to_unless_current(name,  href)          end      end   end
  53. @betsythemuffin #  ##  Generated  Markup   #  :include:  ./app/views/components/_card.html.erb  

    class  CardBuilder   end
  54. @betsythemuffin

  55. @betsythemuffin

  56. @betsythemuffin use cases 1. Developer skims to enable copypasta 2.Clarifying

    reference in designer/developer conversation
  57. @betsythemuffin minimum viable product 1. pictures of components 2.Example code

  58. @betsythemuffin tools - Ruby? - Hologram - Angular/Ember/React/hipster.js? - KSS

    (node version)
  59. @betsythemuffin styleguide generator language == view implementation language

  60. @betsythemuffin how hologram works /*doc   ```html_example   <div  class='card'>

         <h2  class='card__title'>          Lorem  Ipsum  Dolor  Sit  Amet      </h2>      <img  src="http://placekitten.com/210/100"  />      More  text  goes  here!   </div>   ```   */   .card  {      /*  css  */   }
  61. @betsythemuffin how hologram works

  62. @betsythemuffin document helpers, not just markup

  63. @betsythemuffin helper documentation /*doc   ```helper_example   <%=  card  do

     |c|  %>
    <%  c.title  "Lorem  Ipsum  Dolor  Sit  Amet"  %>
    <%  c.image  placekitten_url(width:  210,  height:   100)  %>
    <%  c.body  "More  text  goes  here!"  %>
 <%  end  %>   ```   */   .card  {      /*  css  */   } HTML output HTML.erb output
  64. @betsythemuffin or roll your own method - "identify" - understand

    existing UI concepts - "codify" - use abstraction to "bless" useful UI concepts - "document" - communicate with devs, designers, stakeholders
  65. @betsythemuffin CODE SAMPLES http://betsyhaibel.com/blog/2016-05-07-style-docs-for-resource-constraints/ https://blog.pivotal.io/labs/labs/using-hologram-rails-auto-generate-styleguides

  66. @betsythemuffin me - Betsy Haibel - github.com/bhaibel - betsyhaibel.com -

    @betsythemuffin - betsy.haibel@gmail.com
  67. ActBlue - builds fundraising tech for the left, amplifying the

    voices of small-dollar donors - 1.1 BILLION total raised since 2004 - committed to a modern, culturally and technically sustainable approach - now hiring UX, Rails, and DevOps
  68. @betsythemuffin Acknowledgements - Coraline Ada Emkhe - Chris Hoffman -

    Arlington Ruby - Zeal - ActBlue
  69. questions?

  70. @betsythemuffin BONUS ROUND

  71. @betsythemuffin class  CardBuilder      def  initialize(h,  options  =  {})

             @h  =  h          @size  =  options.fetch(:size,  'normal')      end      def  header(text:  nil,  &block)          @header  =  text  if  text          @header  =  h.capture(&block)  if  block_given?          @header      end      def  render(&block)     block.call(self)          h.render(              partial:  'components/card',              locals:  {                  header:  header              }          end      end   end initialization configuration methods rendering
  72. @betsythemuffin class  CardBuilder      def  header(text:  nil,  &block)  

           @header  =  text  if  text          @header  =  h.capture(&block)  if  block_given?          @header      end   end
  73. @betsythemuffin class  CardBuilder      def  render(&block)     block.call(self)

             h.render(              partial:  'components/card',              locals:  {                  header:  header              }          end      end   end invoke the configuration block render a partial
  74. @betsythemuffin <div  class='card<%=  size  ?  "  card-­‐-­‐#{size}"  :  ''  %>'>

         <h2  class='card__title'>          <%=  header  %>      </div>      <%=  image_tag  image  %>      <%  if  badges.any?  %>          <div  class='card__badges'>              <%  badges.each  do  |kind,  text|  %>                  <span  class='badge  badge-­‐-­‐<%=  kind  %>'><%=  text  %></span>              <%  end  %>          </div>      <%  end  %>   </div>
  75. @betsythemuffin class  CardBuilder      element  :header   end Shiny

    on the outside Sad in reality
  76. @betsythemuffin <%=  card(size:  'large')  do  |c|  %>      <%=

     c.header  'My  Awesome  Knitting  Pattern'  %>      <%=  c.image    pattern.showcase_image_url  %>      <%=  c.badges  {               favorite:  favorite_count      }      %>   <%  end  %> NOT YOUR FRIENDS ANY MORE
  77. @betsythemuffin questions? (for real)