안녕하세요, 로건입니다 👋
여러분, 반갑습니다. 이 글은 시리즈의 0편이에요.
RN 앱에 Storybook을 도입하면서 검증 단계에서 모은 결정과 발견들을, 본편 8편 + 이 인트로로 풀어내려고 합니다. 도입을 막 시작하는 시점이라 회고라기보다는 결정의 정리에 가까워요. 본편으로 바로 들어가기 전에 — Storybook이 정확히 뭔지, 왜 도입하기로 결정했는지, 시리즈에서 어떤 순서로 어떤 이야기를 풀 건지를 한 번 정리하고 가는 게 좋을 것 같아서요.
이미 Storybook을 써본 분이시라면 "정의" 섹션은 건너뛰셔도 좋고요, 도입을 고민 중이신 분이시라면 1편 표 한 장을 보고 결정을 내리실 수도 있을 거예요.
Storybook이란 — 한 줄 정의
Storybook은 UI 컴포넌트를 앱과 분리해서 카탈로그처럼 띄워보는 도구입니다.
조금 더 풀어볼게요. 보통 React 컴포넌트는 어떤 화면 안에서, 어떤 데이터를 받아서, 어떤 상태일 때 비로소 그려집니다. 그래서 디자이너가 "이 버튼의 disabled 상태 좀 보고 싶어요"라고 하면 — 개발자는 보통 코드를 임시로 수정하거나, 그 상태가 나오는 화면까지 클릭해서 들어가야 했어요.
Storybook은 그 과정을 뒤집습니다.
기존: 앱 → 화면 → 컴포넌트의 한 상태
(찾아 들어감)
Storybook: 컴포넌트의 모든 상태 ←─ 사이드바에서 클릭만
(펼쳐 보임)
각 컴포넌트의 각 상태가 "스토리(story)" 라는 단위로 사이드바에 색인되고, 클릭 한 번이면 그 상태가 화면에 떠요. 디자이너든 QA든 개발자든, 같은 카탈로그를 보면서 검수할 수 있게 됩니다.
왜 Native가 아니라 Web Storybook을 쓰나
여기서 RN 개발자에게 한 가지 갈림길이 등장해요. Storybook은 두 가지 종류가 있거든요.
@storybook/react-native | @storybook/addon-react-native-web | |
|---|---|---|
| 어디서 도나 | 실제 디바이스 / 시뮬레이터 | 브라우저 (RN 컴포넌트를 web 요소로 매핑) |
| 띄우는 비용 | 빌드 → 디바이스 설치 → 부팅 | pnpm storybook 한 줄 |
| 핫리로드 속도 | 느림 (네이티브 번들) | 빠름 (vite/webpack HMR) |
| 시각 회귀 자동화 | 어려움 (디바이스 영상) | 쉬움 (headless chrome 캡처) |
| 잡을 수 있는 회귀 | gesture, IME, perf 등 모두 | JS 레이어 회귀 (props/state/render) |
저희는 처음엔 두 번째 — RN-Web Storybook을 골랐어요. 이유는 한 줄로 말하면 "속도와 자동화"입니다. PR마다 자동으로 돌고, 1분 안에 결과가 나오는 안전망이 필요했거든요.
물론 "그러면 디바이스 회귀는 누가 잡냐" 라는 정당한 질문이 따라옵니다. 그 답을 1편에서 풀어드릴 거고, 도입 막판에 @storybook/react-native도 같이 얹기로 결정한 이야기는 8편에서 따로 풀어드려요 — 갈림길이라기보다는 분담이 됐습니다.
핵심 개념 4가지
본편 들어가기 전에, 시리즈에서 반복해서 등장할 단어 네 개를 짧게 정리해둘게요.
Story (스토리)
컴포넌트의 한 상태를 표현하는 단위. 같은 <Button> 컴포넌트라도 Default, Disabled, Loading, Danger 같이 상태마다 별도 스토리가 됩니다.
export const Default: Story = { args: { tone: "primary" } };
export const Disabled: Story = { args: { tone: "primary", disabled: true } };play 함수 (인터랙션 테스트)
스토리가 렌더된 직후 자동으로 실행되는 시나리오. 클릭, 입력, 검증을 코드로 박아둘 수 있어요. 핸들러가 끊겼거나 분기가 사라지면 빨갛게 떨어집니다.
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
await userEvent.click(canvas.getByRole("button"));
expect(args.onPress).toHaveBeenCalled();
};argTypes (콘트롤 패널)
컴포넌트의 props를 사이드바 콘트롤로 노출하는 메타데이터. 디자이너가 코드 안 보고도 props를 바꿔가며 검수할 수 있게 됩니다.
argTypes: {
tone: { control: "select", options: ["primary", "danger"] },
size: { control: "select", options: ["sm", "md", "lg"] },
}Chromatic (시각 회귀 자동화)
스토리들의 픽셀 스냅샷을 PR마다 비교해주는 SaaS. 디자인이 의도치 않게 바뀐 곳을 자동으로 잡아내고, 의도된 변경이면 accept로 baseline을 갱신합니다.
PR push → build-storybook → chromatic upload → diff dashboard
│
Accept or Deny
이 네 단어는 시리즈 내내 반복돼요. 만약 익숙한 분이시라면 그냥 넘어가셔도 좋고요, 처음 보시는 분이시라면 이 글을 책갈피처럼 두고 본편 읽다가 막힐 때 돌아오시면 됩니다.
왜 도입했나 — 한 페이지 결정 메모
도입을 결정하기 전에 case study를 정리하면서 표 한 장을 만들었어요. 풀어 적으면 이런 내용이었습니다.
Pain points (도입 전)
- 디자이너가 컴포넌트 상태 검수할 때마다 "그 화면 어디서 볼 수 있어요?" 질문이 반복됨
- props 시그니처 변경 → 어디서 어떻게 부서지는지 PR diff로 추적 불가
- 디자인 토큰 적용 누락이 디바이스 QA 마지막 날에 발견됨
- 컴포넌트 disabled/empty/error 분기는 어쩌다 화면에서 마주쳐야 검증됨
Goals (도입 후 기대)
- 컴포넌트별 카탈로그가 사이드바에 자동 색인
- PR마다 자동 회귀 테스트 (play + Chromatic)
- 디자이너·QA·개발자가 같은 화면을 보고 합의
- 작성 비용은 컴포넌트 한 개당 10분 안쪽
Risks (예상되는 리스크)
- RN-Web과 실제 RN의 차이 → 잘못된 안전 신호
- 페이지 단위 스토리는 mock 비용이 큼
- false positive로 인한 PR 머지 마찰
- styled-components 같은 비결정적 렌더링 → false diff
이 세 항목이 case study의 골격이었어요. 1편이 그 중 첫 번째 리스크에 대한 정직한 답변이고요, 3편이 두 번째 리스크에 대한 회고예요. 4편과 5편이 실제 작업 중에 마주친 디테일이고, 6편이 자동화의 정점이며, 7편이 그 위에 사내 도구를 직접 만들어 얹은 창작 기록(Visual Builder), 8편이 그 옆에 한 겹을 더 얹은 on-device Storybook 이야기, 그리고 9편이 도입 과정에서 손에 남은 것과 앞으로의 활용 기대입니다.
도입 결정은 도구가 좋아 보여서가 아니라, 우리 팀의 어떤 통증을 어디까지 해결해줄지를 표로 정리한 다음에 내려야 해요. 그 표가 만들어지면 결정은 거의 자동입니다.
시리즈 가이드 — 10편 한 페이지
각 편이 어떤 질문에 답하는지 한 줄로 요약해드릴게요.
| 편 | 답하는 질문 |
|---|---|
| 0 (지금) | Storybook이 뭐고, 왜 RN-Web을 골랐는가 |
| 1 | RN-Web Storybook은 어떤 회귀를 잡고 어떤 회귀를 못 잡는가 |
| 2 | 검증 단계에서 굳어진 스토리 작성 표준은 무엇인가 |
| 3 | 99% 완성된 페이지 스토리 106개를 왜 한 번에 지웠는가 |
| 4 | Figma URL을 어떻게 자동으로 스토리로 변환하는가 |
| 5 | RN-Web 검증 중 마주친 함정 6가지는 무엇이고 어떻게 우회하는가 |
| 6 | Chromatic 시각 회귀 자동화를 어떻게 안정적으로 운영하는가 |
| 7 | Storybook 위에 자체 Visual Builder를 어떻게 만들어 얹었는가 |
| 8 | Storybook을 RN 앱 안(DebugView)에 어떻게 같이 심었는가 |
| 9 | 도입 과정에서 손에 남은 것과 앞으로의 활용 기대는 무엇인가 |
어떤 순서로 읽으면 좋은가
- 도입 고민 중: 0편 → 1편 → 9편 (의사결정 메모)
- 표준 정착 중: 2편 + 5편 (실전 작성 규칙)
- 자동화 단계 진입 중: 4편 + 6편 (Figma 변환과 Chromatic)
- 자체 도구 만들기 고민 중: 7편 (Visual Builder 창작 기록)
- 디바이스 회귀가 신경 쓰이는 분: 1편 + 8편 (on-device 그물)
- 의사결정 / 경영진 공유용: 0편 + 3편 + 9편 (결정과 결과)
각 글은 독립적으로 읽혀도 되고, 처음부터 순서대로 읽으셔도 좋습니다.
한 가지만 미리 약속드릴게요
이 시리즈는 가이드가 아니에요. 경험입니다.
도입 절차 매뉴얼이나 모범 답안이 아니라, "이 결정 내릴 때 이런 트레이드오프가 있더라", "이 문제는 이렇게 풀었더니 이런 부작용이 있더라" 같은 손에 남은 자국을 풀어내려고 해요. 모든 팀에 그대로 들어맞지는 않을 거예요. 다만, 비슷한 갈림길에 서신 분이 의사결정을 조금이라도 빠르게 내릴 수 있도록 자료가 됐으면 합니다.
자, 그럼 1편으로 가볼게요. RN 앱에 Storybook을 도입하는 게 정말로 의미 있는지, 그 답이 들어있는 표 한 장에서 시작합니다.