The Art and Science of Designing Robust Design Systems

design systems

Explore the multifaceted role of design engineering, from visual aesthetics to API design and performance. Discover key principles for building effective, maintainable, and developer-friendly design systems.

The author confesses a non-designer background, admitting challenges with pixel-perfect work, CSS, and Figma. Starting as a backend engineer with JVM languages (Java, Scala, Groovy), they transitioned to full-stack React before specializing in "the back of the frontend"—a role shaped by five years of maintaining TanStack Query, a headless library. This background naturally leads to the question of how the author came to join Sentry's Design Engineering Team, tasked with building their new "Scraps" design system.

Design Engineering

A Design Engineering team typically requires a diverse skill set. While some engineers, like Nate Moore, excel at crafting effortless, cohesive, and aesthetically pleasing interfaces, others must focus on API design, performance, developer experience (DX), and the underlying infrastructure that ensures smooth operation. A design system transcends mere component collections; it serves as a critical gateway, empowering other teams to deliver consistent products swiftly and efficiently.

This blend of expertise enables high-level team performance. The author, while not specializing in visual design elements like gradients or CSS transitions, contributes significantly to areas ensuring the system's robustness, maintainability, and ease of use.

Beyond maintaining the design system, the team's overarching mission is clear: to "Help Teams Ship" their products. With a codebase that has evolved organically over more than a decade, opportunities for improvement abound. A robust design system is a vital tool, but equally crucial are developer education, efficient CI pipelines, and an uncluttered project structure. In this context, the author views their role as a developer experience (DX) engineer. While the design system significantly accelerates development, it's just one facet of a broader strategy to simplify, automate, or eliminate any obstacles that hinder developer productivity.

What Makes a Good Design System

The author has extensively contemplated the characteristics of an effective design system, acknowledging a multitude of insights too vast for a single post. Consequently, a list of principles is provided, with a commitment to explore specific topics in greater detail in future articles.

Design System Principles

  • Have props, but not too many. Avoid booleans.
  • Embrace robust type-safety, exceeding standard expectations.
  • Lint for things you can't enforce on a type level.
  • Be pragmatic and allow escape hatches, but don't leak internals.
  • Favor Composition.
  • Compound Components are great, but should be type-safe.
  • Constraints are good, but need to be balanced and intentional.
  • Consistency is key, both visually and for component APIs.
  • Documentation is crucial, yet types hold even greater importance; leverage JSDoc extensively.
  • Integrate accessibility (a11y) intrinsically, rather than as an afterthought.
  • Know your use-cases, and build for them specifically.
  • Tooltip Components should not exist.
  • Design tokens first, components second.
  • Performance isn't optional.
  • Have patterns, not just primitives.
  • Optimize for 90%, not 100%.
  • Headless is good if possible.
  • Adoption is cultural, not technical.
  • Ship Codemods.
  • Welcome external contributions, and have good guides for them.
  • Have one way to do a thing, avoid redundancy, and don't repeat yourself.
  • Offer Providers to inject behavior.
  • Choose defaults wisely, and be opinionated.
  • Do visual regression testing for important things.
  • State syncing is the root of all evil.
  • Controlled first, uncontrolled if necessary. And make it typed.
  • data-test-id is an a11y smell.
  • Build for the future of React.