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

A presentation at React Alicante in September 2018 in Alicante, Spain by Marco Cedaro

Slide 1

Slide 1

Slide 2

Slide 2

Modular architecture

Slide 3

Slide 3

Modular architecture Classes and components

Slide 4

Slide 4

Modular architecture classes and Components and modifiers

Slide 5

Slide 5

Modular architecture classes and Components, modifiers and overrides

Slide 6

Slide 6

Modular architecture classes, modifiers and overrides Components, patterns and sh*t it’s hard to deal with

Slide 7

Slide 7

@cedmax Webmaster before it was cool Tech Lead Condé Nast International

Slide 8

Slide 8

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

Slide 9

Slide 9

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

Slide 10

Slide 10

Lost in Translation? Basically

Slide 11

Slide 11

Disclaimer “This movie is an hour and some odd minutes of my life I will never get back.” JoeB. on Metacritic

Slide 12

Slide 12

Lost in Translation “Meaning is complex and often gets lost in translation. Everybody has their own mental model of things” Alla Kholmatova

Slide 13

Slide 13

Modular design

Slide 14

Slide 14

2013 - 2015

Slide 15

Slide 15

Slide 16

Slide 16

Atomic design Brad Frost · October 2013

Slide 17

Slide 17

Web components announced in November 2011

Slide 18

Slide 18

Pattern Library “Pattern libraries are something I do a lot for client projects. It’s a technique I first saw Natalie Downe develop for client projects back in 2009” […] […] Anna Debenham

Slide 19

Slide 19

MISSING SLIDE* ABOUT PATTERN LIBRARIES * on purpose, I promise

Slide 20

Slide 20

Pattern Library “Pattern libraries are something I do a lot for client projects. It’s a technique I first saw Natalie Downe develop for client projects back in 2009” […] […] Anna Debenham

Slide 21

Slide 21

ReactJS First release: March 2013

Slide 22

Slide 22

Where are we at, today?

Slide 23

Slide 23

Frame the issue Basically

Slide 24

Slide 24

It's not that simple “When you actually try to apply a modular approach to your day to day work, it isn’t really that simple” Alla Kholmatova · June 2015

Slide 25

Slide 25

The issue

Slide 26

Slide 26

The issue How do we manage our code, to re-use patterns without making them too rigid for the day to day activities?

Slide 27

Slide 27

The issue How do we manage our code, to re-use patterns without making them too rigid for the day to day activities? How do we re-use our patterns in slightly different use cases?

Slide 28

Slide 28

Wish I could sleep

Slide 29

Slide 29

It’s NOT about any specific tech stack or module implementation: most of the patterns can be applied with BEM, styled components, css modules… * It’s about modularity at its core It’s about modules responsibilities It’s about maintainability (among other coding practices)

Slide 30

Slide 30

Classname injection I'll be in the bar for the rest of the week

Slide 31

Slide 31

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

Slide 32

Slide 32

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

Slide 33

Slide 33

//_content-actions.scss .content-actions { //[...] &__button { flex: 1 0 auto; padding: 1rem; line-height: 1.5; &:hover, &:focus { background: $grey-1; } &:active { background: $grey-2; } } }

Slide 34

Slide 34

//_content-actions.scss .content-actions { //[...] &__button { flex: 1 0 auto; padding: 1rem; line-height: 1.5; &:hover, &:focus { background: $grey-1; } &:active { background: $grey-2; } } }

Slide 35

Slide 35

//_content-actions.scss .content-actions { //[...] &__button { flex: 1 0 auto; padding: 1rem; line-height: 1.5; &:hover, &:focus { background: $grey-1; } &:active { background: $grey-2; } } } What's the effect on the base button?

Slide 36

Slide 36

//_content-actions.scss .content-actions { //[...] &__button { flex: 1 0 auto; padding: 1rem; line-height: 1.5; &:hover, &:focus { background: $grey-1; } &:active { background: $grey-2; } } } Why is this button different from the pattern library ones?

Slide 37

Slide 37

What works This is the most flexible way to extend anything.

Slide 38

Slide 38

What really doesn't 1. The default style could be overridden in unexpected ways. 2. We are creating many variants of the original patterns.

Slide 39

Slide 39

Ad hoc modifiers

  • You're too tall. - Anybody ever tell you you may be too small?

Slide 40

Slide 40

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

Slide 41

Slide 41

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

Slide 42

Slide 42

//_dialog.scss .dialog { //[...] &--user-intent { width: 43.75rem; height: auto; } }

Slide 43

Slide 43

//_dialog.scss .dialog { //[...] &--user-intent { width: 43.75rem; height: auto; } }

Slide 44

Slide 44

//_dialog.scss .dialog { //[...] &--wizard { width: 43.75rem; height: 35rem; } &--game-intent { width: 43.75rem; height: auto; } &--save-results { width: 23.75rem; height: auto; } } How many variants do we have to account for?

Slide 45

Slide 45

What works This practice allows for flexibility, giving a reasonable control and keeping all the variants in proximity.

Slide 46

Slide 46

What really doesn't 1. The generic component style have knowledge of specific implementations. 2. The file size might be effected by unused code. 3. It doesn't scale

Slide 47

Slide 47

Specialised patterns I'm special

Slide 48

Slide 48

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

Slide 49

Slide 49

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

Slide 50

Slide 50

//_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; } }

Slide 51

Slide 51

//_dialog.scss .dialog { //[...] The semantic value of the modifiers is different from the ad-hoc ones. &--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; } }

Slide 52

Slide 52

What works The patterns are at the centre: no special cases, but pre-defined flavours of the basic components.

Slide 53

Slide 53

What really doesn't 1. It might drive to preemptive abstraction 2. It does account for a finite number of use cases

Slide 54

Slide 54

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

Slide 55

Slide 55

Classname injection Ad hoc modifiers Specialised patterns A no go: it defies the point of having a pattern library A code smell, it's an hack and it should be treated like one The best approach, even though sometimes I still wish I could sleep

Slide 56

Slide 56

I'm stuck Basically

Slide 57

Slide 57

It's not that simple “It isn’t really that simple” Alla Kholmatova · June 2015

Slide 58

Slide 58

The issue How do we re-use our patterns in slightly different use cases?

Slide 59

Slide 59

What am I trying to solve?

Slide 60

Slide 60

Arrangement within parent components

Slide 61

Slide 61

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

Slide 62

Slide 62

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

Slide 63

Slide 63

//_dialog.scss .dialog { width: 100%; height: 100%; //[...] } //_game-intent.scss .game-intent { //[...] &__dialog { width: 43.75rem; height: auto; } }

Slide 64

Slide 64

//_dialog.scss .dialog { width: 100%; height: 100%; //[...] } //_game-intent.scss .game-intent { //[...] &__dialog { width: 43.75rem; height: auto; } } Each component has its own responsibility

Slide 65

Slide 65

What works This practices defines responsibilities in a neat way and it enables for specific implementations without invalidating patterns.

Slide 66

Slide 66

<Dialog className="custom-class"> <!-- [...] --> </Dialog> <div className="custom-class"> <Dialog> <!-- [...] --> </Dialog> </div>

Slide 67

Slide 67

What really doesn't Potentially you might need a wrapper HTML element that could have been avoided.

Slide 68

Slide 68

Space in relation to other components

Slide 69

Slide 69

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

Slide 70

Slide 70

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

Slide 71

Slide 71

What works It reduces the need to come up with new class names and it moves the conversation regarding component relationships back to the pattern library.

Slide 72

Slide 72

What really doesn't 1. The positional classes might get stale if not codified properly in the pattern lib. 2. The flexibility of the helper classes is limited 3. Do you like atomic css? https://acss.io/

Slide 73

Slide 73

<Dialog className="M(defSpace) P(defSpace)"> <!-- [...] --> </Dialog>

Slide 74

Slide 74

"Open" components

Slide 75

Slide 75

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

Slide 76

Slide 76

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

Slide 77

Slide 77

//_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; } }

Slide 78

Slide 78

//_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; } }

Slide 79

Slide 79

//_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; } } The responsibility of being flexible it back to the component itself

Slide 80

Slide 80

<Icon size={32} />

Slide 81

Slide 81

What works 1. Every base component can be as flexible as it defines itself to be. 2. Developers always have control on what they expose.

Slide 82

Slide 82

What really doesn't 1. This technique involves more complexity in thinking about the components 2. It's a slippery slope 3. How does an "open" component fit in the patterns?

Slide 83

Slide 83

Does it get easier? Basically

Slide 84

Slide 84

Slide 85

Slide 85

The more you know who you are and what you want, the less you let things upset you

Slide 86

Slide 86

I just don't know what I'm supposed to be

Slide 87

Slide 87

“A common language is a first step towards communication across cultural boundaries. ” Ethan Zuckerman

Slide 88

Slide 88

The issue How to understand - and convey the meaning of an exception in our patterns?

Slide 89

Slide 89

Learn what the pattern your are building is supposed to be

Slide 90

Slide 90

Get involved early

Slide 91

Slide 91

Talk to people

Slide 92

Slide 92

and remember that…

Slide 93

Slide 93

You are not hopeless marco@fromthefront.it http://cedmax.com @cedmax