Storybook으로 디자인 시스템 문서화하기


프론트엔드 개발을 하다 보면 가장 자주 드는 질문이 있다.
“이 컴포넌트는 어떤 상태들을 가질 수 있지?”
“이 props 조합에서 UI가 어떻게 보였더라?”

초기에는 컴포넌트를 실제 페이지에 붙여서 확인한다.
하지만 컴포넌트가 많아지고, 상태가 늘어나고, 여러 페이지에서 재사용되기 시작하면 이 방식은 빠르게 한계에 부딪힌다.

특히 카드, 모달, 리스트 아이템 같은 UI 컴포넌트는 로딩 상태, 비활성 상태, 강조 상태, 예외 케이스 등 한 번에 보기 힘든 상태들이 점점 쌓이게 된다.

이 문제를 해결하기 위해 우리가 도입한 도구가 Storybook이다.

Storybook은 컴포넌트를 페이지나 라우터, 데이터 fetch 로직에서 분리해서 UI 자체만 독립적으로 개발하고 문서화할 수 있는 도구다.

Storybook을 도입하면 Dashboard에서 컴포넌트의 상태를 쉽게 파악할 수 있고, 디자이너/기획자가 의도한 UI 상태를 독립적으로 간편하게 확인 가능하다.

특히 우리 서비스도 여느 서비스와 다르지 않게 버튼, 박스, 모달 등 상태 조합이 많은 컴포넌트들이 많았기 때문에 Storybook 도입을 고려하게 되었다.


예시로 CharacterBox 컴포넌트를 보자.

CharacterBox는 캐릭터를 보여주는 카드 컴포넌트다.
이 컴포넌트는 메인 페이지 뿐만 아니라, User Profile Page, Character Card 등 매우 다양하게 재활용된다.

이 컴포넌트 하나만 봐도 상태가 꽤 많다.

  • 랭킹 표시
  • 채팅 중 상태
  • 긴 텍스트 예외 처리
  • 이름
  • 태그
  • …

각각의 상태를 한 눈에 파악하기란 상당히 어렵다.
CharacterBox를 Storybook으로 관리해보자.

우선 Story Meta를 정의한다.

Storybook은 단순히 UI 미리보기 도구가 아니라 컴포넌트 문서로서 사용되기 때문에 우리가 한 눈에 보고 이해하기 위한 정보들을 정의해주면 좋다.

TypeScript
const meta = {
  title: 'CharacterBox/CharacterBox',
  component: CharacterBox,
  parameters: {
    layout: 'centered',
    nextjs: {
      appDirectory: true,
    },
    docs: {
      description: {
        component:
          '캐릭터 정보를 표시하는 카드 컴포넌트입니다. 로딩 상태, 블러 상태, 커스텀 모드 등을 지원합니다.',
      },
    },
  },
  tags: ['autodocs'],

Prop 각각에도 설명을 추가해주면 누가 봐도 각 Prop의 의미를 바로 이해할 수 있다.

TypeScript
argTypes: {
  name: {
    control: 'text',
    description: '캐릭터 이름',
  },
  isLoading: {
    control: 'boolean',
    description: '로딩 상태',
  },
  isBlurred: {
    control: 'boolean',
    description: '블러 상태',
  },
  rankingNumber: {
    control: 'number',
    description: '랭킹 번호',
  },
  ...
}

그 후에는 다양한 상태를 Story로 표현해서 미리보기들을 만들면 된다.

[기본 상태]

TypeScript
export const Default: Story = {
  args: {
    name: 'Luna',
    description: 'A wizard who loves the night sky',
    tags: ['Wizard', 'Night Sky'],
    chatting_count: 1234,
  },
}

[로딩 상태]

TypeScript
export const Loading: Story = {
  args: {
    isLoading: true,
  },
}

이외에도 레이아웃과 클릭 이벤트도 주입할 수 있어서, 매우 다양한 환경에서 컴포넌트를 테스트할 수 있다.

테스트 코드 작성하듯이 더 자세하게 작성할 수록, 많은 케이스를 고려할 수록 이 컴포넌트에 대해 더 자세히 알 수 있다.


아래와 같이 코드로 표현한 Story들은 Storybook Dashboard에서 볼 수 있다.

페이지 하단에서는 상태에 따라 정의한 Stories들을 볼 수 있다.
아래 사진들에서 알 수 있듯이, 상태에 따른 컴포넌트들의 디자인을 한 눈에 파악할 수 있다.


Storybook을 도입하고 나서 크게 체감되는 점은 크게 두 가지였다.

  1. 옛날에 짠 컴포넌트가 기억이 안 날 때, 과거의 내가 작성해놓은 Story를 보고 기억을 떠올릴 수 있다.
  2. 컴포넌트가 디자이너가 의도한 디자인을 가지는지/인터렉션을 하는지 페이지에 직접 넣지 않고도 확인할 수 있다.

Story를 짜는 것은 테스트 코드 짜는 것과 똑같다.
Prop이 늘어나면 가능한 Story는 지수적(Exponential)으로 증가한다.
다행인 건 Dashboard에서 Prop을 동적으로 조정할 수 있어서 필수적인 Story만 짜도 큰 도움을 준다는 거다.


Storybook을 도입하기 전에 아래 질문을 먼저 고민해보고 도입해야 한다고 생각한다.

  • 우리 서비스가 체계적인 문서화가 필요할 정도의 규모인가?
    왜냐하면 문서화나 테스트의 필요성은 서비스의 크기와 어느 정도 비례하기 때문이다.

아주 작은 서비스라면 Storybook을 만드는 시간보다 서비스 위생 관리나 기능을 하나 더 만드는 게 훨씬 중요한 시점일 가능성이 높다.
물론 문서화와 테스트는 항상 있으면 좋은 것이고, 여건만 된다면 갖추는 게 이상적이다.

  • 하지만 현실적으로는 그렇지 않은 경우가 대부분이다.
  • 규모가 작은데도 문서화와 테스트를 꼼꼼히 짤 시간이 충분하다면, 그건 프로젝트가 아직 그렇게 바쁘지 않다는 신호라고 감히 생각한다.

그것과 별개로 디자인 시스템의 체계적인 관리가 필요하다면 Storybook은 강력한 도구이다.

Story를 작성하다 보면 자연스럽게

  • 이 컴포넌트의 책임은 어디까지인지
  • 상태가 과도하게 늘어나고 있지는 않은지
  • props 설계가 직관적인지

같은 질문을 스스로에게 하게 된다.


컴포넌트 수가 늘어나고, 상태 조합이 복잡해지고, 여러 사람이 같은 UI를 만지기 시작할 때, Storybook은 프론트엔드 코드베이스를 정리해주는 좋은 기준점이 되어줄 것이라고 생각한다.

답글 남기기

Dalmeng's Footprints에서 더 알아보기

지금 구독하여 계속 읽고 전체 아카이브에 액세스하세요.

계속 읽기