thumbnail thumbnail
  • 개발

Storybook 어디까지 사용해봤니?

Moon

스토리북이란?

Storybook은 UI 컴포넌트 개발을 위한 도구로, 프론트엔드 개발자들이 개발한 컴포넌트들을 테스트하고, 문서화하고, 개발자 간에 공유하기 쉽게 만들어줍니다.

일반적으로 프론트엔드 개발에서는 컴포넌트를 개발할 때, 해당 컴포넌트가 다른 컴포넌트와 어떻게 동작하며, 어떤 속성을 가지고 있는지 등을 개발자들끼리 소통하며 개발합니다. 이 때, Storybook을 사용하면 개발한 컴포넌트를 직접 실행해 보지 않고도, 컴포넌트의 동작과 속성 등을 미리 확인할 수 있어 개발 시간을 단축시키고, 오류를 줄일 수 있습니다.

또한, Storybook은 컴포넌트들을 시각적으로 정리하고, 컴포넌트마다 문서화를 할 수 있어, 다른 개발자들과 공유할 때도 편리합니다. 이를 통해, 다른 개발자들이 컴포넌트를 쉽게 이해하고, 재사용할 수 있도록 도와줍니다.

위는 스토리북에 대해 ChatGTP가 답변한 내용입니다. 즉 스토리북은 웹 컴포넌트의 문서화를 쉽게 해주는 도구 입니다. 아래는 adobe에서 스토리북으로 컴포넌트 문서를 작성한 예시입니다.

Action Button / Static Black - XS ⋅ Storybook (adobe.com)

스토리북을 키고 사이드메뉴를 클릭하면 각 컴포넌트들을 열람할 수 있습니다. adobe에서는 정말 많은 컴포넌트들을 만들어 놨네요. 보시다시피 스토리북을 통해 컴포넌트 문서를 자동으로 만들어주는 걸 볼 수 있습니다. 그런데 말이죠. 스토리북의 강점은 여기서 끝이 아닙니다.

스토리북엔 VisualTest가 있다!

네! 스토리북은 Chromatic과 연동하여 시각적 회귀 테스트를 할 수 있습니다.

Introduction - Docs ⋅ Storybook (chromatic.com)

위는 chromatic에 배포하여 visual testing을 한 결과입니다. 왼쪽이 Baseline, 오른쪽이 새로 배포한 내용입니다. 보시다시피 새 커밋이 의도치 않게, 컴포넌트의 디자인을 망가뜨렸네요. 하지만 이렇게 다 테스트 할 수 있으니 든든합니다.

테스트 장치를 마련하면 코드 수정이 부담스럽지 않아, 리팩토링 주기를 짧게 가질 수 있습니다. 리팩토링 주기가 짧아지니 첫 코드 작성할때도 고민하는 시간이 단축되죠. 일단 짜고 본다는 마인드! Visual Test 는 실제로 스토리북에 작성된 컴포넌트들을 화면에 랜더링하고 스크린샷을 찍어 비교합니다.

Vusual Test는 dom 엘리먼트와 css 만을 비교하는 테스트와는 완전히 다르게 동작합니다. 그래서 랜더링하는 환경을 똑같이 만들어야하고, 그럴려면 온프렘 서버를 운영하든가, 해외에 있는 프론트엔드 테스트 서비스를 결제해야하는데요. Chromatic은 이걸 무료로 해줍니다.

(backstopjs 라는 라이브러리를 통해 로컬로 테스트 해보았는데, 테스트 환경마다 결과가 달라서 힘들더라구요)


스토리북을 활용하면 위처럼 컴포넌트들을 문서로 남길수도 있고 시각적 회귀 테스트 하기도 쉽습니다. 언뜻보기에 스토리북은 갓 라이브러리인데 말이죠.

그런데 솔직히 Storybook 안써도 되지 않음?

맞아요; 회사가 작으면 작은대로, 크면 큰 대로 스토리북을 작성안하게 되는 이유가 있습니다.

회사가 작은경우

제가 다니는 회사는 개발자 3명, 전원 풀스택인데요. 솔직히 컴포넌트들을 스토리북으로 문서화 해도 아무도 안봅니다. 사용법이 궁금하면 옆자리에 앉아 있는 개발자에게 물어보면 되고요. 애초에 쓰는 사람은 컴포넌트 만든 사람 뿐입니다.

나열하면 다음과 같은 이유가 있습니다.

  • 규모가 작아 문서로 공유할 필요가 적다

  • 다른 컴포넌트 라이브러리 (daisy ui, mui)를 사용하게 된다. (그러면 라이브러리 문서를 보면 됩니다)

  • 컴포넌트를 아무리 만들어도, 실제 화면에서 컴포넌트가 차지하는 비중은 적다.

네! 특히 마지막, 컴포넌트를 아무리 만들어도 실제 화면에서 가장 많은 영역을 차지하는 것은 컴포넌트가 아닙니다. 아래의 네이버 메인 페이지를 봐주세요. 저기서 컴포넌트화해서 공통적으로 사용할 수 있는 부분이 몇개가 될까요?

스토리북을 통해 아무리 컴포넌트들을 문서화하고, 테스트할 수 있다고 해도, 실제 화면을 이루고 있는 대부분의 요소는 1회용 소모품입니다. 즉 해당 화면을 떠나면 다시 못볼 버튼이나 레이아웃이죠.

회사가 큰 경우

회사가 크면 여러 개의 개발팀이 각자의 서비스를 담당하고 있습니다. 이렇게 규모가 커지면 매 팀마다 컴포넌트를 각자 만드는 것은 부담스러운 일입니다. 위에서 실제 화면을 그릴때는 대부분의 요소가 1회용 소모품이라 컴포넌트화 하는게 큰 효력이 없을 수 있다고 했는데요. 컴포넌트가 화면에 차지하는 비중이 작을 수 있을뿐 아예 없는 것이 아닙니다. 만드는 페이지가 많아지고 개발팀이 계속 증가한다면 공통적으로 사용하는 요소를 컴포넌트화 해서 공유하는 일은 의미 있습니다.

그런데 컴포넌트화 해서 사내 팀들과 공유한다는게 좋다는거지, 그게 곧 Storybook이 좋다는 아닙니다. Storybook은 가독성 측면에서 문제가 되는데요. 문서를 작성하는데 정해진 레이아웃에 맞춰야 하니 아무리 커스텀이 가능하다고 해도 한계가 있습니다.

한번 생각해보세요. 오픈소스로 공개된 UI 라이브러리들의 문서가 Storybook으로 작성된걸 본적이 있나요? 맨 처음에 보여준 adobeStorybook (adobe.com)도 실제로 들어가보면 자체적으로 만든 컴포넌트 문서 링크를 걸어둔걸 알 수 있습니다.

Action Button: Spectrum Web Components (adobe.com)

아 그래도 Storybook으로 만들어 놓으면 Visual Test 하기 쉽다메?

흠.. 글쎄요.. Visual test를 꼭 해야할 만큼 복잡한 컴포넌트가 있을까요? 게다가 서로가 서로의 컴포넌트에 독립적일테니 Visual test를 만들지 않더라도 코드 수정에 부담은 없을거 같습니다. 예를들어 Button을 고친다고 Alert 컴포넌트에 영향을 미치진 않으니까요

아 제가 만들고 있는 라이브러리는 UI라이브러리가 아니라 SVG 프레임워크에 가까워서 한 쪽 코드수정이 다른 쪽에 미칠 확률이 매우 높습니다. 그래서 같은 라이브러리라도 저는 Visual Test를 100% 누리고 있지요 ㅎㅎ


여기까지가 Storybook에 대한 저의 이전 생각입니다.

본론부터 말하자면 현재 저는 Storybook holic입니다. 이제부터 Storybook을 사내 팀 및 사이드프로젝트 팀에서 어떻게 활용하고 있는지 경험을 공유할게요.

Storybook에서 페이지 자체를 그려보자

Storybook에 올릴 수 있는게 버튼과 같은 UI 컴포넌트 뿐만은 아닙니다. 페이지 자체를 스토리북에 올릴 수도 있지요. 감이 잘 안오신다고요? 예시 화면을 보여 드리겠습니다.

https://cozyblog.io/

보시다시피 CozyBlog의 페이지 자체를 스토리북으로 올렸습니다. 이제는 스토리북 하나만 들어가도 실제 페이지들을 다 보게 될 수 있는거죠. 그런데 저렇게 하려면, 데이터 fetching은 어떻게하고.. 이미지가 바뀌는건 또 어떻게 대응 해야하는거지..? 저런식으로 페이지 자체를 올리는 것은 득보다 실이 더 많은거 아닐까?

즉 이게 뭐하는 짓인가 의구심이 드실겁니다. 장점을 설명하기 전에 제가 지금 하고 있는 시도는 전혀 새로운 것이 아님을 말하고 싶네요.

Pure presentational pages

Teams at the BBC, The Guardian, and the Storybook maintainers themselves build pure presentational pages. If you take this approach, you don't need to do anything special to render your pages in Storybook.

It's straightforward to write components to be fully presentational up to the screen level. That makes it easy to show in Storybook. The idea is that you do all the messy “connected” logic in a single wrapper component in your app outside of Storybook. You can see an example of this approach in the Data chapter of the Intro to Storybook tutorial.

위 내용은 Storybook 공식 문서에 나와있습니다. 즉 Pure하게 UI만 있는 페이지를 컴포넌트처럼 스토리북에 올리는 일은 Storybook에서도 제안하는 방식입니다. BBC, Guardian에서도 한다니까 저희도 시도해볼만 합니다.

이렇게 페이지 자체를 Storybook으로 올리는 일엔 어마어마한 장점들이 있습니다.

그전에 단점을 언급하자면 2가지가 있겠네요.

  1. 1

    순수하게 UI 페이지를 만드는 것은, 데이터나 fetching 함수를 외부로부터 주입받게끔 설계해야 해서 불필요한 코드가 증가한다.

  1. 2

    기존에 운영중인 서비스를 스토리북에 맞게 개선하는 일은 어렵다.

그러나 이 두가지 모두 단점이 될 수 없다는게 제 입장입니다.

순수하게 UI 페이지를 만드는 것은, 불필요한 코드를 증가시킨다.

스토리북에 올릴 페이지를 만들려면 페이지 컴포넌트 안에서 직접 api를 받아오는 코드를 짜서는 안됩니다. 밖에서 주입을 받도록 prop을 노출시켜야 하죠.

이런 작업은 페이지를 만드는데 드는 코드가 증가할 수 있음을 의미합니다. 스토리북에 올릴때는 mockApi를 주입하고 실제 서비스 코드에서는 실제 api를 구현해서 주입해야하죠. mockApi를 만들어야 하기 때문에 스토리북 작성도 일반적인 컴포넌트에 비해 시간이 걸릴 수 있습니다.

그러나 api를 mocking 할 수 있도록 설계하는 것은 불필요한 코드를 늘리는게 아닙니다. 오히려 스토리북을 쓰지 않는다고 해도 많은 이점이 있습니다. 그것은 프론트 개발이 백엔드로부터 독립함을 선언하는것과 다름없습니다. 자세한 내용은 아래 장점 소개글에서 기술하도록 하겠습니다.

기존에 운영중인 서비스를 스토리북에 맞게 개선하는 일은 어렵다.

이 말은 스토리북에만 해당되는게 아닙니다. 모든 개선은 마이그레이션에 비용이 들어갑니다. mybatis에서 jpa로 이전한다든가, react에서 svelte로 이전한다든가, 카페24에서 온프렘 쿠버네티스로 이전한다든가 등등 모든 개선에는 비용이 수반합니다.

(위의 내용은 모두 실제로 회사에서 진행 했거나 하고 있습니다. 저는 곧 퇴사하지만요 ㅋ)

중요한것은 이득이 비용보다 클지 안클지 인 것이지요. 지금 회사도 개발중인 웹 서비스를 스토리북에 올리도록 마이그레이션 하고 있습니다. 초기 비용이 좀 들긴 했지만 앞으로 얻을 이득에 비하면 새발의 피도 못되죠. 그럼 스토리북으로 Page를 올렸을때 어떤 장점이 있는지 살펴볼까요

장점1: MockApi로 프론트 개발 마이웨이로 진행하자

자 앞으로 프론트 개발할때

🚫

npm run dev

이게 아니라

👌

npm run storybook

이렇게 하자구요~

페이지 그릴 때, 실제 api 연동 신경쓰지 말고 개발서버 api가 꺼져있든, 아직 개발이 안되는 상관없이 mockApi 만들어서 스토리북 키고 개발하는 겁니다.

포스팅을 보여주는 페이지라면 PostApi를 이렇게 만들어 놓을 수 있겠죠.

Typescript
interface PostApi { findAll(): Promise<{title: string; content: string;}[]> } class MockPostApi implements PostApi { private posts: {title: string; content: string}[] = [ { title: 'Storybook 어디까지 써봤니?', content: '매우 좋음' }, { title: 'Flutter ContraintBox에 대해 알아보자', content: '다음에 알아보자' } ] override async findAll(): Promise<{ title: string content: string }[]> { return this.posts } }

페이지는 아래처럼 구현하면 됩니다.

Typescript
// PostsPage.svelte <script lang="ts"> export let fetchPosts: () => Promise<{title: string; content: string;}[]> </script>

실제 postsApi의 리턴타입이 예상과 달라지면 어떻게 할지 걱정되시나요?

Dto 변환을 만들어주면 그만입니다~

Typescript
class RealPostApi implements PostApi { override async findAll(): Promise<{ title: string content: string }[]> { const result = await fetch(new URL('/posts', 'https://api.{realApiHost}')) .then(res => res.json()) return result.map(this.convertDto) } private convertDto(post: {name: string, decription: string}) { return { title: name, content: description } }

이렇게 만들어 놓으면 Storybook 사용과는 별개로 테스트도 용이하고, 더 이상 백엔드 개발자에게 api 언제 완료되냐고 눈치주지 않아도 됩니다. 프론트는 마이웨이로 개발하면 그만! 스토리북을 통해 화면을 랜더링하면서 개발하다가 약간의 스토리만 추가해서 chromatic으로 배포하면 페이지 자체가 문서로 승격되니 더할나위 없이 좋습니다.

장점2: 디자이너, 기획자와 소통하기 편함

  1. 1

    화면 갱신 주기가 빠르다.

    아무리 개발서버에 CI/CD를 잘해놔도, 개발서버 배포는 비용이 많이드는 작업입니다. github workflow로 풀리퀘가 수락되면 배포되게 해놨는데, 풀리퀘가 수락되기 전에 먼저 작업한 내용을 디자이너에게 컨펌받아야 한다고 생각해보세요.

    이번만 manual하게 개발서버에 다시 배포해야할까요? 첫 한두번은 그럴수 있어도 반복되면 개발자에게는 매우 피로한 일이 됩니다. 개발자가 화면 갱신 주기가 늦으면 늦을수록 디자이너도 답답할거고요. 디자이너가 기껏 열심히 작업했는데 한참뒤에 개발서버에 반영된 화면은 기대와 다르면.. 빡치시겠죠..?

    Storybook을 chromatic을 통해 배포하는 일은, 명렁어 한줄 입력하면 완료! 보다 손쉽게 디자이너에게 피드백을 요청할 수 있습니다.

    왼쪽을 보시면 chromatic의 사용예시를 알 수 있습니다. 디자인이 변화된거에 대해 팀원들이 피드백들 남기는 것이죠.

    사내에서도 풀리퀘를 올릴때 chromatic으로 화면도 배포하게 해서 디자이너와 같이 리뷰를 진행하고 있습니다.

    디자이너분도 리뷰를 남길 수 있게 Github에 가입했고요!

    사내 chromatic 리뷰 (전체 화면은 보여주기 어렵..)
  1. 2

    각 화면의 단계를 한눈에 살펴 볼 수 있다.

    실제 서비스 페이지를 들어가는 일은 비용이 많이 드는 행위 입니다. 예를들어, 쇼핑몰의 장바구니 화면 디자인 반영된 모습을 보고 싶다면? 그리고 장바구니에 아이템이 들어가있을때 어떻게 표시되는지를 확인하려면 어떤 과정이 필요할까요?

    디자이너나 QA 담당자는 아래와 같은 과정을 거칠 것입니다.

    1. a

      먼저 서비스에 로그인한다.

    1. b

      마이 페이지에 들어간다

    1. c

      장바구니에 들어간다

    1. d

      장바구니에 아이템을 채운다

    이렇게 확인한 화면에 UI, UX 버그가 있다면요? 개발자에게 이를 전달하고 개발자는 수정하겠죠? 그러면 디자이너는 위의 과정을 1번부터 다시 거쳐야합니다. 이게 반복될수록 디자이너와 개발자의 사이는 돌이킬 수 없게 되버립니다 -.-

    Storybook에서는 위 문제을 쉽게 해결할 수 있습니다. 각 화면의 단계를 Story의 형태로 표시해 놓으면 바로 원하는 화면을 볼 수 있으니까요. 아래는 CozyBlog의 노션 연동 화면 단계입니다.

    노션 연동페이지
    노션 연결 페이지 로딩 화면
    연결할 수 있는 페이지가 없음

    스토리만 클릭하면 각 조건에 따른 화면들을 볼 수 있으니 엄청 편리하죠? 스토리북 없이 노션 연동 로딩바 디자인을 보기위해 실제 서비스에 들어가서 매번 브라우저 새로고침을 누를 생각하면 아찔합니다.

    아 그리고 당연히 모바일 view port의 화면도 쉽게 가능합니다. 요즘 웹 서비스 반응형이 기본인 시대에 모바일 화면 체크는 필수잖아요

장점3: A/B Test가 쉽다

브랜치 별로 다르게 화면을 작업하고 각각 배포하세요

그리고 비교하면 끝입니다!

디자인만 봐선 모르는게 있잖아요? 버튼을 클릭하고 직접 입력해봐야죠

왼쪽은 Cozy 블로그 연동 스토리북 화면입니다. 실제 서비스 화면처럼 보이면 좀 뿌듯할지도요 ㅎ. 중복이름 검사 api를 mocking해서 실제로 동작하는 듯한 느낌을 내봤습니다.

나중에는 storybook으로 인터렉션 테스트도 작성할거에요. 이렇게 말이죠

Interaction tests (storybook.js.org)

결론

스토리북으로 페이지 전체를 작성하는 일은 개발할때와 개발된 내용을 받아볼 때 모두 만족스러운 경험을 가져다 주었습니다. 특히 스토리북에서는 작동에 문제가 없는데 npm run dev로 실행시켰을때 화면이 터진다거나, 레이아웃이 깨질때마다 모종의 희열이 느껴지더라구요.

이미 스토리북에서 동작을 다 확인했으니 문제의 원인이 될 수 있는 후보가 매우 좁혀집니다. 스토리북 없이 바로 페이지 데이터 연동해서 개발했다면, 문제 상황을 파악하는것이 꽤나 스트레스였을 거에요.

저는 svelte를 통해서 스토리북을 배포했는데, 스토리북은 스벨트뿐만 아니라 다른 프레임워크도 거의 다 지원을 합니다. 리액트도 거기에 당연히 포함되고요(스토리북이 리액트로 만든거라네요)

아직 도입이 망설여진다면 개인 플젝에서 한번 찍먹해보세요. 분명히 매력을 느낄것입니다 ㅎㅎ 그럼 이만~

참고자료