Paving the adoption path of your Design System for engineers

Important take-aways

  • To help you maintain a centric tool in your organization's architecture

  • To guard yourself from possible failures and even be ready for them to happen

import { me } from '../speakers'

Jeremias Menichelli

Front end engineer, focusing on animation, web architecture and design systems for the last years

From Argentina, living in Barcelona

I don't put pineapple on pizza

@jeremenichelli on twitter,

jeremenichelli.io on the internets

There are some gifs anD animations!

WHAT IS A DESIGN SYSTEM?

What A DESIGN SYSTEM doES...

  • Enables a new level of efficiency in your design and engineering teams
     
  • Scalable by default
     
  • Distributes consistency

Design systems need to be first a design TEAM effort, with engineering outcomes

DESIGN SYSTEM

ENGINEERING TEAM

ENGINEERING TEAM

ENGINEERING TEAM

ENGINEERING TEAM

DEVELOPER EXPERIENCE IS KEY

import React from 'react'

import Dialog from 'your-design-system'
import Modal from 'your-design-system'
import Drawer from 'your-design-system'


const Screen = () => (
  <>
    <Dialog visible />
    <Modal open />
    <Drawer closed={false} />
  </>
)

requires the user to re-learn a new interface

puts engineers in a focus switching situation

import React from 'react'

import Dropdown from 'your-design-system'

const Screen = ({ dropdownValue }) => (
  <>
    <Dropdown
      value={dropdownValue}
      options={[ 'leia', 'luke' ]}
      renderHeader={value => <span className="custom-header">{value}</span>}
      renderOption={value => <span className="custom-option">{value}</span>}
    />
  </>
)

an interface open to an unexpected behavior leads to unexpected usage, which leads to unexpected bugs

you are distributing behavior, you are not distributing design

NO tests!

  • Engineers collaborating ad-hoc are usually in a context switching situation, so "no time for tests"
  • But it bites back, "I don't want to modify this cause I might break it for others"
  • But "this component doesn't do what I need, so I build my own thing"
  • Ergo no tests also break the potential adoption of a design system in an organization

Design systems ADOPTION is not only about usage, it's also collaboration and safe engagement of another codebase

PLAN

  • Make an audit and decide on common interface
  • Refactor and align code style and project structure
  • Write unit tests on each step
  • Write contribution guides and document decisions

HYPOTHESIS

  • People will have questions on technical decisions, stay in the open, give them transparency and reasons why
  • Homogeneus codebase and unit tests will give engineers confidence when collaborating
  • Less buggy and more predictable artifacts will drive adoption on early iterations

VALIDATE

  • Talk to engineers directly, one per team at least
  • Run a survey

RESULTS

  • "After a lot of time, the API and naming has become messy and hard to predict"
  • "I don't collaborate because I don't know if I'm breaking the component for other teams"
  • "We don't have tests"

HAVING A Product VISION IS KEY

THE EXECUTION

  • Write tests for legacy interface in components
  • Refactor component
  • Write new interface
    • support legacy interface
    • warn about new one
    • announce and document
    • automate the migration

Example

import React from 'react'
import styled from 'styled-components'

const DialogWrapper = styled.div`
  display: ${props => props.visible ? 'flex' : 'none'};
  position: fixed;
  top: 0;
  left: 0;
  height: 100%;
  align-items: center;
  justify-items: center;
`

const Dialog = props => <DialogWrapper {...props}>

export default Dialog

First Step: tests for legacy behavior

import React from 'react'
import styled from 'styled-components'

const DialogWrapper = styled.div`
  display: ${p => p.visible ? 'flex' : 'none'};
  position: fixed;
  top: 0;
  left: 0;
  height: 100%;
  align-items: center;
  justify-items: center;
`

const Dialog = props => <DialogWrapper {...props}>

export default Dialog

✅ shows using "visible" prop

✅ hides when "visible" prop is false

SECOND Step: EXTRACT LEGACY BEHAVIOR

function getVisibility(props) {
  if (props.visible) {
    return 'flex'
  }

  return 'none'
}

const DialogWrapper = styled.div`
  display: ${p => getVisiblity(p);
  position: fixed;
  top: 0;
  left: 0;
  height: 100%;
  align-items: center;
  justify-items: center;
`

✅ shows using "visible" prop

✅ hides when "visible" prop is false

THIRD STEP: ADD SUPPORT FOR NEW API

function getVisibility(props) {
  if (props.visible) {
    return 'flex'
  }

  if (props.isOpen) {
    return 'flex'
  }

  return 'none'
}

const DialogWrapper = styled.div`
  display: ${p => getVisiblity(p);
  position: fixed;
  top: 0;
  left: 0;
  height: 100%;
  align-items: center;
  justify-items: center;
`

✅ shows using "visible" prop

✅ shows using "isOpen" prop

✅ hides when "visible" prop is false

Fourth STEP: WARN ABOUT LEGACY USAGE

import { VISIBLE_PROP_MESSAGE } from './messages'
import warn from '../utils/warn'

function getVisibility(props) {
  if (props.visible) {
    if (process.env.NODE_ENV !== 'production') warn(VISIBLE_PROP_MESSAGE)
    return 'flex'
  }

  if (props.isOpen) {
    return 'flex'
  }

  return 'none'
}

✅ shows using "visible" prop

✅ warns about "visible" usage

✅ shows using "isOpen" prop

✅ hides when "visible" prop is false

FIFTh STEP: REMOVE LEGACY INTERFACE

import { VISIBLE_PROP_MESSAGE } from './messages'
import warn from '../utils/warn'

function getVisibility(props) {
  if (props.visible) {
    if (process.env.NODE_ENV !== 'production') warn(VISIBLE_PROP_MESSAGE)
    return 'flex'
  }

  if (props.isOpen) {
    return 'flex'
  }

  return 'none'
}

⛔️ shows using "visible" prop

⛔️ warns about "visible" usage

✅ shows using "isOpen" prop

⛔️hides when "visible" prop is false

WHEN migrations GET COMPLICATED...

  • Create a second version of the component, internally exported when detected legacy shape
  • Create a second version of the component (ie: "dropdownv2")
  • Complete deprecation of component

ALWAYS WARN, THROW A WARNING IN THE RIGHT PLACE AT THE RIGHT TIME

For your developers...

  • Support legacy interfaces so consumers can migrate at their own pace
  • Write clear changelogs explaining the changes, what to do and even code snippets if necessary
  • Announce releases in your organization preferred channel
  • Write meaningful warnings, link to changelogs, documents and migration guides to speed up the changes

If you are a maintainer...

  • Start small and check on the way, instead of releasing a big major version, we went component by component
  • Always be listening, to everyone
  • Don't feel bad when saying no, you have a broader vision of the project and might know better if something is going to backfire
  • Don't feel bad if something didn't work, the important thing is the user, and as a maintainer the developer is the user
  • From time to time, jump into a migration task to get the developer experience from first hand

YOU PAVE THE WAY, THE TEAMS make THE MOVE

YOU NEED SPACE FOR MAINTAINANCE, PLANNING AND EXPERIMENTATION in the project

DESIGN SYSTEM

ENGINEERING TEAM

ENGINEERING TEAM

ENGINEERING TEAM

ENGINEERING TEAM

DESIGNER

YOU

YOU

YOU

COMMUNICATION IS KEY

RECAP

  • Observe, serve and maintain
  • Plan, explain and stay in the open
  • Validate with users
  • Execute
  • Revalidate

TIPS

  • Be incremental and care for developer experience
  • Treat your design system as a product
  • Communication is key

ACTUAL Example in the wild

  • Observe
  • Planned and explain
  • Validated with users
  • Revalidated

WORKING ON THE ENGINEERING OF A DESIGN SYSTEM IS LIKE BEING AN OSS MAINTAINER

but paid

HAVE FUN!

THANKS

Jeremias Menichelli

@jeremenichelli on twitter,

jeremenichelli.io on the internets

"Paving the adoption path of your Design System for engineers"

Made with Slides.com