디자이너와 소통하기 위한 개발자의 노력 (storybook,chromatic)

김인태·2025년 3월 6일
0

🤩 개요

개발자들은 서버, 페칭, 클라이언트 등 데이터와 자신들이 가진 CS 지식을 바탕으로 대화를 나눕니다. "응답에 대한 인터페이스는 어떻게 정의되어 있나요?", "요청은 어떤 파라미터와 값을 보내야 하나요?" 등과 같은 기술적인 이야기들이죠.
하지만 디자이너와 소통할 때는 조금 다른 접근이 필요합니다. 물론 피그마를 통해 "A는 이렇게 움직이고, B는 이런 행동을 해서 C 링크로 이동합니다"라고 설명하면 충분히 이해할 수 있습니다. 그러나 실제로 컴포넌트들이 디자이너가 의도한 대로 동작하는지 확인하기 위해서는 추가적인 과정이 필요합니다.

테스트 서버에 배포하는 경우를 생각해볼까요? 테스트 서버에 배포하고 → 디자이너가 확인하고 피드백을 주면 → "괜찮아요!"라는 답변을 받고 → 메인으로 머지하는 과정을 거치게 됩니다. 여기서 문제는 배포 과정에서 발생합니다. 배포하는 동안 다른 개발 작업을 할 수 있다고 생각할 수 있지만, 이는 몇 가지 중요한 한계를 가지고 있습니다.

  1. 테스트 서버에는 여러 기능들이 함께 올라가 있어서 특정 컴포넌트만 깨끗하게 확인하기가 어렵습니다.
  2. 로딩 상태, 에러 상태, 다양한 데이터 상황 등 여러 케이스를 검증하려면 매번 특정 조건을 만들어야 하는 번거로움이 있죠. 디자이너가 수정을 요청할 때마다 다시 배포하고 확인하는 과정을 반복해야 한다는 것도 큰 비효율입니다.

이러한 맥락에서 스토리북이라는 도구가 우리에게 필요한 이유를 살펴보려 합니다. 스토리북은 단순히 "배포하고 다른 일 하면 되지 않나?"라는 질문을 넘어서는 가치를 제공할 수 있기 때문입니다!

저희 회사에 3/4일부터 UI/UX 디자이너 분이 오시기 때문에, 스토리북을 만들어서 최대한 소통하고자 하는 노력을 보여드리고 간극을 좁히고자 스토리북을 세팅하기로 결정하였습니다!

🌸 스토리북 설치

저희 프로젝트는 React + Vite 를 사용하고 있기 때문에

https://storybook.js.org/docs/get-started/frameworks/react-vite?renderer=react ← 여기 접속하셔서

npx storybook@latest init 이 명령어만 입력하시면 세팅이 끝납니다!

참쉽죠? 사실 쉬운 것은.. 설치뿐입니다..

이제 문제는 어떻게 디자인 시스템을 정립할 것인가에 대해서 연구해야합니다..

👀 스토리북을 나누는 기준

이미 셋팅과 개발이 되어있는 상황에서 어떻게 폴더를 나누고, 어떻게 나눠야할지 고민이 많았습니다.

왜냐하면 제가 아주 얕게 알기로는 보통 스토리북은 아토믹 패턴을 가지고 사용한다고 알고 있었거든요!

저는 스토리북을 설치한 이후에 폴더를 열어보고 조금 한숨이 나왔습니다.

이 많은 컴포넌트들과 페이지 등을 어떻게 스토리북을 통해서 보여주고, 아토믹 패턴을 사용하면 이 얽히고 섥혀있는 컴포넌트들을 어떻게 나눠야하지? 라고 생각했습니다

이것저것 자료도 찾아보고, ai에도 물어보니 아래처럼 답을 줬습니다.

  1. 반드시 스토리로 작성해야 하는 컴포넌트:
    • 재사용되는 공통 컴포넌트 (버튼, 인풋, 카드 등)
    • 디자이너와 자주 소통이 필요한 복잡한 컴포넌트
    • 여러 상태를 가진 컴포넌트 (로딩, 에러, 성공 등)
  2. 선택적으로 작성할 수 있는 컴포넌트:
    • 페이지별 특정 레이아웃 컴포넌트
    • 간단한 래퍼(wrapper) 컴포넌트
    • 비즈니스 로직이 많은 컴포넌트
  3. ⭑ 스토리 작성이 불필요한 경우:
    • 단순 레이아웃용 컨테이너
    • 데이터 fetching만 담당하는 컴포넌트
    • 페이지 라우팅 관련 컴포넌트

아하! 그렇다면 단순 레이아웃 컨테이너나, fetching 만을 담당하거나 페이지 라우팅 관련 컴포넌트는 만들 필요없겠구나! 그렇다면 조금 공수가 줄어들 수 있겠네! 라고 생각했습니다. 또한 굳이 꼭 아토믹 패턴을 사용해서

나눌 필요는 없으며, 중요하고 확인해야하는 부분만 스토리 컴포넌트로 만들면 되겠구나~ 라고 생각했습니다.

좋습니다! 이제 한 번 적용해보도록 하겠습니다.

현재 코드는 이렇게 배치되어있습니다!

src/
  components/
    home/
      button.tsx
    profile/
      button.tsx
    dashboard/
      button.tsx

src/components/[pages] 와 같은 형식이죠.

사실 그렇게 복잡하거나, 찾기 어려운 구조는 아닙니다. 도메인 별로 사용되는 컴포넌트가 나눠져 있죠.

그러나 이러한 구조는 같은 버튼 컴포넌트가 여러 페이지에 중복되어 있어

디자이너 분이 보기에 혼란스러울 수 있을 것 같습니다.

디자이너 관점에서는 이 버튼이 왜 여러곳이 있는 것일까? 라고 의문이 들 수도 있습니다.

그래서 아래처럼 바꿔보려고 해요!

src/
  components/
    common/
      Button/
        Button.tsx
        Button.stories.tsx
        variants/ 
          PrimaryButton.tsx
          SecondaryButton.tsx
    home/
      HomeHeader/
        HomeHeader.tsx
        HomeHeader.stories.tsx
      HomeFeature/
        HomeFeature.tsx
        HomeFeature.stories.tsx
    profile/
      ProfileCard/
        ProfileCard.tsx
        ProfileCard.stories.tsx

위에 대한 구조를 간단하게 설명하자면

공통적인 특성을 가지면서, 여러군데에서 사용되는 컴포넌트는 common 폴더!

시각/기능적인 차이가 확연하고, 독립적인 특성을 가지는 컴포넌트들은 variants 폴더에 넣기

variants 폴더로 분리하지 말아야 하는 경우

  1. 단순히 색상이나 크기만 다른 경우
  2. props로 쉽게 관리 가능한 스타일 변형
  3. 공통 로직을 많이 공유하는 경우
  4. 일관된 디자인 시스템 내의 변형

나머지들은 페이지별로 관리되는 컴포넌트들입니다!

🔥 개발하기!

예시를 한 번 들어보겠습니다!

공통으로 사용되는 input이 있습니다! 디자인은 같으나, 다양한 값들을 컨트롤하는 그런 input이죠

react-hook-form 을 사용해서 유효성 검사를 진행하는데요, 어떻게 하는지 한 번 알아보죠~

실습에 사용될 input

일단 만들고자 하는 위치에 CommonInput.stories.tsx를 만듭니다.

저는 src/common/input/CommonInput.stories.tsx를 만들었습니다.

코드를 한 번 보겠습니다.

import { useForm } from "react-hook-form";
import type { Meta } from "@storybook/react";
import CommonInput from "./CommonInput";
import type { SignUpFormData } from "@/types/signup/types";

//Storybook에서 이 메타객체를 설정하면 폴더나, 어떤 컴포넌트를 렌더링할지 결정합니다.
//꼭, export default meta; 로 meta 객체를 내보내야 스토리북이 스토리파일로 인식합니다. 
const meta: Meta<typeof CommonInput> = {
//스토리북의 경로
  title: "Components/Common/CommonInput",
  //표시할 컴포넌트
  component: CommonInput,
  //만들어진 컴포넌트가 중앙에 위치할 수 있도록 설정
  parameters: {
    layout: "centered",
  },
  //컨트롤 부분은 나중에 설정
   
  //컴포넌트를 그 말대로 데코할 수 있다. 최대한 페이지랑 비슷한 환경에서 보여지는 걸 원해서
  //데코레이터를 설정하였다.
  decorators: [
    (Story) => (
      <div className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4 w-[800px]">
        <Story />
      </div>
    ),
  ],
};

export default meta;

export const HospitalNameInput = () => {
  const {
    register,
    formState: { errors },
  } = useForm<SignUpFormData>({
    mode: "onChange",
  });

  return (
    <CommonInput
      label="상호명"
      type="text"
      id="hospitalName"
      register={register}
      placeholder={"상호명을 입력해주세요"}
      isRequired={false}
      errors={errors.hospitalName}
      registerOptions={{
        required: "상호명는 필수 항목입니다.",
      }}
    />
  );
};

사실 더 많은 기능들이 있습니다!

스토리북을 사용해서 테스트(접근성, 시각적, 스냅샷 등) 다양한 테스트를 진행할 수 있는데

그것들은 디자이너분과 더 이야기를 통해서 추가할 수 있을 것 같습니다!

👍 결과!

아주 잘 나옵니다!

근데 추가적인 고민이 생겼습니다..

오케이 스토리북 설정하는 건 오케이.. 이게 6006번 포트를 사용하는 것도~ 오케이 근데,

원래 도메인이 https://abc.com 이라고 했을 때 이거는 내가 3000번으로 포트포워딩 되어있는데, 6006번을

어떻게 뚫어서 디자이너분에게 결과를 공유할 수 있을까..?

그답은 chromatic에 있습니다!

크로매틱을 사용해서 빌드된 파일을 올리고, 공유할 수 있습니다~

Chromatic 설치방법!

https://storybook.js.org/tutorials/intro-to-storybook/react/ko/deploy/ 에 들어가셔서 설치하면 되는데,

저는 있는 레포지토리에 세팅하는 거다 보니 레포지토리 만드는 부분은 생략하겠습니다.

설치합니다

#npm
npm install -D chromatic

#yarn
yarn add -D chromatic

패키지가 설치 되고, 앞서 설정한 깃허브 저장소와 동기화 합니다.


npm chromatic --project-token=<project-token>

위 명령어를 입력하면 빌드된 컴포넌트들이 나옵니다.

이런식으로 말이죠!

🤔 마무리

저도 사실 실무에서 디자이너분과 일해보는 것은 처음이라 어색하기도 하면서 기대가 많이 됩니다 ㅎㅎ

디자인적으로 더욱 발전된 프로덕트를 보면 굉장히 흐뭇할 것 같아요!!

더 효율적인 협업 방법이 있다면 좀 더 알아봐야겠습니다! 예를 들어 디자인 시스템을 어떻게 스토리북에 적용하고

argTypes의 control 부분들을 사용해서 변경할 수 있는 부분도 수정하면 더욱 좋은 협업을 할 수 있지 않을까?

싶습니다! 감사합니다!

[출처]

https://storybook.js.org/tutorials/intro-to-storybook/react/ko

profile
새로운 걸 배우는 것을 좋아하는 프론트엔드 개발자입니다!

0개의 댓글