Components, patterns and sh*t it’s hard to deal with

Components, patterns and sh*t it’s hard to deal with

or… How I came up with a good use of quotes from Lost in Translation.

A brief run through a few ways of handling flexibility when it comes to patterns and components: modular architectures are hard and defined patterns need to express the right level of flexibility not to defy the point of a pattern library at all.

3ca63d4e2f2be0ef47b841e63b564d18?s=128

Marco Cedaro

January 23, 2017
Tweet

Transcript

  1. Modular architecture

  2. Modular architecture Classes and Components

  3. Modular architecture Classes and Components and Modifiers

  4. Modular architecture Classes and Components and modifiers and containers

  5. Modular architecture Classes and Components and modifiers and containers and

    overrides
  6. Modular architecture Classes and and modifiers and containers and overrides

    Components, 
 patterns and sh*t it’s hard to deal with
  7. Components, 
 patterns and sh*t 
 it’s hard to deal

    with
  8. Components, 
 patterns and sh*t 
 it’s hard to deal

    with or… 
 How I came up with a good use of quotes from Lost in Translation
  9. The issue

  10. THE ISSUE How do we manage our code, in order

    to re-use patterns without making them too rigid for the day to day activities?
  11. REPHRASED How do we re-use our patterns in slightly different

    use cases?
  12. None
  13. 1 2 3 4 FRAMING THE ISSUE It’s NOT about

    any specific tech stack It’s about modularity at its core It’s about modules responsibilities it’s about maintainability (among other coding practices)
  14. Ideas and experiments

  15. 1 Different name spaces

  16. None
  17. <IconButton className="content-actions__button" iconId="close" />

  18. <IconButton className="content-actions__button" iconId="close" />

  19. //_content-actions.scss .content-actions { //[...] &__button { flex: 1 0 auto;

    padding: rem-px-offset(1rem, -2px) 1rem; line-height: 1.5; &:hover, &:focus { background: $grey-1; } &:active { background: $grey-2; } } }
  20. How would this rules interact with the base button styles?

    
 (it’s actually useless, afaik) 
 What if we decided to refactor the base button? //_content-actions.scss .content-actions { //[...] &__button { flex: 1 0 auto; padding: rem-px-offset(1rem, -2px) 1rem; line-height: 1.5; &:hover, &:focus { background: $grey-1; } &:active { background: $grey-2; } } }
  21. What role does this override play in the pattern library

    space? //_content-actions.scss .content-actions { //[...] &__button { flex: 1 0 auto; padding: rem-px-offset(1rem, -2px) 1rem; line-height: 1.5; &:hover, &:focus { background: $grey-1; } &:active { background: $grey-2; } } }
  22. This is the most flexible way to extend anything. WHY

    DOES IT WORK?
  23. WHY IT DOESN’T WORK The css for the module lives

    in different files and the default style could be overridden in unexpected ways.
  24. WHY IT DOESN’T WORK We are creating many variants of

    the original patterns.
  25. No technique offers the same flexibility. 
 Do we need

    that flexibility? How does it play with having a pattern library? ALTERNATIVES?
  26. 2 Ad hoc BEM-like modifiers

  27. None
  28. None
  29. <Dialog className="dialog--game-intent"> <!-- [...] --> </Dialog>

  30. <Dialog className="dialog--game-intent"> <!-- [...] --> </Dialog>

  31. //_dialog.scss .dialog { //[...] &--game-intent { @include mappy-bp(medium) { width:

    43.75rem; height: auto; } } }
  32. //_dialog.scss .dialog { //[...] &--game-intent { @include mappy-bp(medium) { width:

    43.75rem; height: auto; } } } The modifier lives in the same space of the dialog. 
 …but how many of these modifiers would we need?
  33. How does this effect our performance?
 
 Does it effect

    our productivity? //_dialog.scss .dialog { //[...] &--wizard { @include mappy-bp(medium) { width: 43.75rem; height: 35rem; } } &--game-intent { @include mappy-bp(medium) { width: 43.75rem; height: auto; } } &--save-results { @include mappy-bp(medium) { width: 23.75rem; height: auto; } } }
  34. This practice allows for a lot of flexibility, giving a

    reasonable control and keeping all the variants in the same space. WHY DOES IT WORK?
  35. WHY IT DOESN’T WORK The generic component css files would

    start having knowledge of specific implementations. The file size might be effected by unused code.
  36. WHY IT DOESN’T WORK Again: do we need this level

    of flexibility? How many variants do we need to take care of if we decided to edit the base component.
  37. 3 Pre-defined modifiers

  38. None
  39. <Dialog className="dialog--prompt"> <!-- [...] --> </Dialog>

  40. <Dialog className="dialog--prompt"> <!-- [...] --> </Dialog>

  41. //_dialog.scss .dialog { //[...] &--prompt { display: block; overflow: hidden;

    max-width: map-get($dialog-prompt, max-width); height: auto; margin: map-get($dialog-prompt, margin); padding: 2rem 0 0; border-radius: 3px; } }
  42. Even though it looks a lot like the previous one,

    the semantic value of the modifiers is really different. //_dialog.scss .dialog { //[...] &--prompt { display: block; overflow: hidden; max-width: map-get($dialog-prompt, max-width); height: auto; margin: map-get($dialog-prompt, margin); padding: 2rem 0 0; border-radius: 3px; } }
  43. The patterns are at the center: no special cases, but

    pre-defined flavours of the basic components. 
 
 This make it easy to identify responsibilities and to refactor base components. WHY DOES IT WORK?
  44. WHY IT DOESN’T WORK Sometime it would drive to preemptive

    abstraction, which is, most of the time, a bad idea.
  45. It’s a great practice when we identify variants of base

    components. WHY DOES IT WORK?
  46. <Dialog type="prompt"> <!-- [...] --> </Dialog>

  47. None
  48. The issue

  49. WE NEVER FOUND AN ANSWER How do we re-use our

    patterns in slightly different use cases?
  50. And what can be tackled without defying the point of

    even having a pattern library? WHAT ARE WE REALLY TRING TO SOLVE?
  51. (Problem) => Solution* * see what I did there?

  52. None
  53. None
  54. 1 2 3 4 WHAT DO WE NEED TO CHANGE?

    Arrangement in parent components (margin, sizing, paddings…) Arrangement in relation to other components Theming (colours, borders…) What else?
  55. 1 Arrangement in parent components

  56. <div className="game-intent__dialog"> <Dialog> <!-- [...] --> </Dialog> </div>

  57. <div className="game-intent__dialog"> <Dialog> <!-- [...] --> </Dialog> </div>

  58. //_dialog.scss .dialog { width: 100%; height: 100%; //[...] } //_game-intent.scss

    .game-intent { //[...] &__dialog { @include mappy-bp(medium) { width: 43.75rem; height: auto; } } }
  59. //_dialog.scss .dialog { width: 100%; height: 100%; //[...] } //_game-intent.scss

    .game-intent { //[...] &__dialog { @include mappy-bp(medium) { width: 43.75rem; height: auto; } } } Every module has the right responsibility: parents define positioning in the parent space; children adapts and define themselves.
  60. This practices defines responsibilities in a neat way and it

    enables for specific implementations without invalidating patterns. WHY DOES IT WORK?
  61. This is really different because the latter custom class won’t

    override the Dialog styles. <div className="custom-class"> <Dialog> <!-- [...] --> </Dialog> </div> <Dialog className="custom-class"> <!-- [...] --> </Dialog>
  62. WHY IT MIGHT NOT WORK Potentially you might need a

    wrapper HTML element that could have been avoided.
  63. 2 Arrangement in relation to other components

  64. <Dialog className="space-max inner-space-min"> <!-- [...] --> </Dialog>

  65. <Dialog className="space-max inner-space-min"> <!-- [...] --> </Dialog>

  66. Helper classes, if the base components are expecting them, could

    help avoiding repeated code. <Dialog className="space-max inner-space-min"> <!-- [...] --> </Dialog>
  67. Besides the benefit of not having to come up with

    new class names, creating a set of positional helpers moves the conversation regarding component relationships back to the pattern library. WHY DOES IT WORK?
  68. WHY IT MIGHT NOT WORK The positional classes might get

    stale if not codified properly in the pattern lib.
 
 We might end up with weird stuff. 
 (e.g: .space-maxYminX or .inner-space-noYmaxX)
  69. 3 Theming

  70. //_question-content-block.scss .question-content-block { //[...] &__icon-button { //[...] .icon { width:

    $content-block-icon-large-size; height: $content-block-icon-large-size; } }
  71. //_question-content-block.scss .question-content-block { //[...] &__icon-button { //[...] .icon { width:

    $content-block-icon-large-size; height: $content-block-icon-large-size; } }
  72. //_question-content-block.scss .question-content-block { //[...] &__icon-button { //[...] @include icon-size($content-block-icon-medium-size); }

    } //_icon.scss @mixin icon-size($size) { .icon { width: $size; height: $size; } }
  73. //_question-content-block.scss .question-content-block { //[...] &__icon-button { //[...] @include icon-size($content-block-icon-medium-size); }

    } //_icon.scss @mixin icon-size($size) { .icon { width: $size; height: $size; } }
  74. The icon exposes an API to change some predefined properties

    The responsibilities order of things is maintained //_question-content-block.scss .question-content-block { //[...] &__icon-button { //[...] @include icon-size($content-bloc… } } //_icon.scss @mixin icon-size($size) { .icon { width: $size; height: $size; } }
  75. Every base component can be as flexible as it defines

    itself to be. Developers always have control on what they expose. WHY DOES IT WORK?
  76. WHY IT MIGHT NOT WORK The complexity of the sass

    logic might grow.
  77. 3 What else?

  78. None
  79. None
  80. None
  81. None