ㄱ사에서 프로덕트를 만들며 atomic design을 적용하고 storybook을 토대로 디자인 시스템을 구축해보기로 했다. 프로젝트 진행 초기에는 디자이너도 동의하는 부분이었지만 제대로 진행되지 못했고 결국 디자인 시스템을 구축하는 것은 실패로 돌아갔다.

실패에 대한 이유와 적용 경험으로 얻은 것들을 풀어보고자 한다.
참고로 atomic design이나 storybook이 무엇인지는 글에 포함 시키지 않는다. 내가 글을 쓰는 것보다는 이미 좋은 글들이 많으니까 😁

적용기

실패 경험

앞서 언급한 것처럼 입사 초 디자이너와 이야기 할 때에는storybook을 통한 디자인 시스템 구축에 대한 합의 점이 있었고, 이를 위해서 그 동안 관심을 가지고 있었던 atomic design을 본격적으로 적용해보기로 했었다.

언제나 처음이 어렵듯이 처음 적용해 본 atomic design과 storybook은 제법 쉽지 않았다.
사실 당시의 storybook 버전과 Vue가 궁합이 안 맞아도 너무 안 맞았었기 때문에 발생되는 이슈가 많았던 것...

하지만 이 문제를 미뤄두어도 일단 디자인 시스템 구축과 storybook 도입은 실패로 돌아 갔다.

일정 상의 문제

일단은 개발 일정 상의 문제가 가장 크게 작용되었다.

디자인 시스템을 구축하자면 디자이너와 긴밀하게 이야기가 진행되어야 하는데 도무지 그럴 시간적 여유가 없었다. 그도 그럴 것이 내가 입사한 4월부터 디자인 작업이 시작되었는데, 8월을 오픈 시점으로 둔 상태에서 7월에야 디자인이 나왔고 그마저도 계속 일부분은 완료되지 않고 미확정 상태로 진행되었다.

디자인이 진행되고 있던 초기에는 Vue와 storybook을 통합하느라 시간을 보내고, API도 완료된 디자인 화면을 기준으로 만들고 있었으니 뒤로 갈 수록 개발 시간이 부족했고, 더구나 최초 예상 범위는 시간이 흐를 수록 점점 덩어리가 커져 가더니 MVP가 아니라 그냥 커다란 덩어리가 되어 버리는 통에 개발에만 시간을 쏟아도 모자를 지경이 되어버렸다. (실제로 일정 상에 문제가 생기기도 했다)

디자이너의 컴포넌트 단위에 대한 이해 부족

두 번째 문제는 디자이너의 컴포넌트 단위에 대한 이해가 부족하다는 거였다. (어쩌면 커뮤니케이션의 문제일 수도 있다.)

벡터 툴을 가지고 포토샵처럼 쓰는 것도 문제였지만, 예를 들어 버튼 컴포넌트의 경우 분명 같은 버튼 컴포넌트인데 동일한 스타일을 가지고 있지 않다. 가장 많게는 border-radius 사이즈가 너무 다양하게 나타났고, 종종 font-size나 font-weight가 차이가 났다.

물론 디자이너의 눈에 이 페이지에서는 이렇게 보이는 게 이쁘다가 나올 수는 있다고 생각한다. 하지만 만들어야 하는 프로덕트는 아트웍이나 각각 개별 페이지 전자 인쇄물이 아니라, 여러 페이지로 구성되어 있는 하나의 웹사이트, 하나의 웹 어플리케이션이고 특히 컴포넌트 관점의 개발 도구를 사용하는 환경에서 개별 컴포넌트의 베리에이션 기준이 명확하지 않으면 전부 하드코딩해야 한다는 것이 된다.

또한, 이 프로젝트에서는 디자인 변수를 미리 잡아두고 시작했는데 — 글꼴 크기 세트, 컬러 세트 등, 전달 받은 디자인 상에서 계속 사전 정의된 컬러 이름이 나오다가 갑자기 헥스 코드나 rgb(a) 값이 나타나서 확인해 보면 정의 된 값 이외의 것들이었다.

문제는 이러한 것들이 적지 않게 튀어 나왔다는 것이고, 이미 color set을 정의해 둔 상태에서 어디에도 끼우기가 너무 어렵고 (그레이 색상을 12단계로 설정해 두었는데 갑자기 그 사이 어딘가의 값이 툭...), 해당 컬러 값이 얼마나 자주 사용 되는 지, 또 다른 어딘가의 사이 값이 추가로 존재하는지 확인 하려면 불필요하게 소비되는 리소스가 너무 많이 들어간다는 거였다.

이러한 잦은 예상 외의 베리에이션이 나타나면서 하드 코딩이 잦게 발생되고, 결국은 CSS 규격화는 점점 물 건너 가며 template이나 organism 단위에서 CSS를 override하는 지저분한 상황이 연출 되기도 했다. (심하게는 시안 상에는 button 컴포넌트를 가져다 그려 놓았으나 실제는 체크 박스 기능인 것도 있었다.)

어찌보면 커뮤니케이션이 원활하지 않았기 때문에 이 부분에 대한 협의가 이루어지지 않은 것도 있겠지만, 경험 상 퍼블리셔로서 일할 때부터 늘 디자이너와 겪는 마찰 부분이기도 하다.

Nuxt와 Storybook의 궁합 문제

세 번째 문제는 nuxt와 (당시의) storybook이 서로 궁합이 안 맞아도 너무 안 맞는다는 거였다.

storybook에서 왜 오류가 나지?, 왜 안되지? 하고 구글링 해보면 issue로 등록되어 있거나 storybook 문제라는 stackoverflow의 답변들을 쉽게 발견할 수 있었다.

본래는 온갖 해외 자료들을 뒤져가며 해결했던 그 모든 방법들을 포스팅 해보려고 했었는데, 어느 정도 바쁜 것들이 정리되고 본격적으로 포스팅을 시작해보기 위해 한 단계 한 단계 다시 사례를 만들려고 하니 버전업과 함께 해결되어 버려서 ㅋㅋㅋ (그래서 이슈 해결 보다는 nuxt-storybook으로 통합하는 것과 수동으로 한 땀 한 땀 통합하는 방법을 비교해서 올렸었다.)

가장 짜증(?) 났던 것 중 하나가 mdx 포맷과 addon과 vue의 통합이 거지 같았... (addon-docs와 controls와 vue와 mdx가 만나면... 하하하...) 지금은 mdx를 이용해 넘나 잘 쓰고 있다.

그리고 다른 개인 작업에서 storybook과 pug를 통합해보고 있다(읭?)

재 시도

작년 11월 IAT 세미나를 준비하면서 시연에 필요한 페이지를 Vue로 만들면서 다시 적용해봤다.

이미 storybook 버전업으로 통합이 잘 되었고, 자잘한 버그 등의 이슈도 있었지만 다행히 github을 통해 issue로 등록할 때마다 nuxt-storybook 커뮤니티에서 빠르게 대응해줘서 금방 처리되었다.

거기에 이직을 진행하는 과정에서 사전 과제가 나올 때마다 atomic design 방법론을 적용해서 만들면서 계속해서 storybook을 적용해갔고, 덕분에 이전 회사에서 완성하지 못했던 디자인 시스템을 page 단위까지 구축해볼 수 있었다. (뭐 그렇다고 잘 구축했다는 건 아니다. 그냥 해 봤다고...)

그리고 현재는 hexo 블로그 테마를 새로 제작하면서 storybook + pug를 시도해보고 있다. (응??)

실패를 피하려면,

실패해보고 개인적으로 끝까지 storybook을 간소하게(?) 만들어보고 나니 드는 생각이, 컴포넌트 관점에서의 디자인 시스템 도입에 실패를 피하려면,

  • 일단 일정이 많이 들어갈 소지가 높다는 것을 염두해 두어야 하고

  • 디자이너의 역할이 상당히 필요한 듯 하다,

    구체적으로 이야기 해보면, 디자이너가 컴포넌트 관점에서의 개발이라는 컨셉을 이해하고 있어야 하고 베리에이션의 기준을 명확히 할 수 있어야 할 것 같다.
    디자인부터 atom, molecule, organism 등에 대한 이해를 바탕으로 각 컴포넌트가 설계되고 규격화 되어야 갈아엎고 다시 만들어야 할까 고민하는 상황이 없을 것 같다.

  • 컴포넌트를 어떻게 그룹핑하고 분류할 것인지, 서로 유기적으로 엮여야하는 인터랙션이 있다면 어떻게 조합해서 이벤트 처리를 어떻게 할 것인지 등을 잘 고려해 두어야, 조립하다가 재그룹핑하고 재분류하는 일을 줄일 수 있겠더라 (아, 이건 어쩔 수 없는 숙명이려나...) 사실 이 부분은 지금도 만들어 볼 때마다 반복 중인 것 같기도 하다.

고민 포인트

atomic design과 storybook을 적용해가면서 몇 가지 고민 되는 포인트가 있었는데,

첫째는 이걸 atom으로 두어야 하는가 molecule로 두어야 하는가의 고민이었다.

한 예로 텍스트 필드 컴포넌트를 만드는데 참고한 UI Kit에서는 텍스트 필드에 항상 레이블과 오류 메세지가 함께 존재했고, 이 세 가지 요소 — 레이블, 입력 상자, 오류 메세지를 최소 단위로 보고 atom으로 두는 것이 적절할지, 아니면 아토믹 디자인에서 설명하는 텍스트 그대로 HTML 엘리먼트 단위를 atom으로 보고 컴포넌트는 molecule로 두어야 하는가의 고민이 반복될 수 밖에 없었다. (해당 UI Kit에서는 각 구성 요소가 분리된 더 작은 컴포넌트가 없었기 때문에 그 묶음을 최소 단위로 간주해서 atom으로 두는 걸 최종적으로 선택했다.)

둘째는 Vue에서 이벤트 핸들링을 할 때는 emit을 사용해서 커스텀 이벤트를 상위 컴포넌트로 올려서 처리하는 방식을 권장하고 있는데, 이게 코드를 너무 지저분하게 만드는 듯한 느낌을 지우기 어려웠다. 더불어 Vue devtools에서도 한 번의 액션에 컴포넌트 중첩 수준 만큼에 해당하는 로그가 연달아 발생하니 추적 자체에도 제법 많은 시간을 써야 했다. 내 경우엔 이벤트 핸들러를 props로 내려주는 방식을 선택했는데, 이를 안티 패턴으로 보는 블로그 게시글도 있어서 다소 찜찜한 기분은 남아있다.

셋째는 Vuex의 사용이었는데, atomic design의 컨셉 상 실제 데이터가 page 단위에서 바인딩 되는 형태를 따르다보니 atom, molecule, organism, template 단위에서는 Vuex 바인딩을 피하는 쪽으로 만들어야해서 적지 않게 props가 발생되는 느낌도 있었고, 때로는 너무 과하게 제한하는 건 아닐까 하는 생각도 들기도 했다. (하지만 내가 깊게 이해하지 못할 경우에는 우선 명세 같은 것을 최대한 존중하자는 주의라... 일단은 page에서만 Vuex에 접근하는 쪽을 유지하고 있다.)

넷째는 앞서 "실패를 피하려면"에서도 마지막에 언급했던 것이지만, 어떤 컴포넌트를 조합하다 보면 어떻게 그룹핑 하고 어떻게 분류할 것인가가 계속 고민의 연속이 된다.

예를 들어, modal dialog를 만드는데 dialog 껍데기와 닫기 버튼을 하나의 컴포넌트로 두고, dialog 콘텐츠를 slot으로 처리해서 다른 컴포넌트가 slot으로 삽입되는 구조로 만들었는데 초점 관리에서 문제가 되어 버렸다. tab sequence가 양쪽 컴포넌트에 걸쳐 있다 보니 focus trap을 만들어야 하는데 이벤트 관리를 어떻게...
이리 저리 컴포넌트를 재그룹핑 해봐도 해결책이 보이지 않아 결국은 modal dialog 쪽에서 tabbable 엘리먼트들을 DOM에서 직접 가져와서 처리하는 방식으로 해결해두기는 했는데 인터랙션에 의한 컴포넌트 간의 상호작용을 고려했을 때 컴포넌트가 이렇게 두는 게 맞는지 계속 고민이다.

다섯째는 내가 아직 Storybook을 어떻게 활용할 수 있는가에 대한 경험치 부족과 지식 부족이겠지만, docs와 story를 어떻게 구성해야 하는가다...

현재는 생각 나는 대로 구성해보고 있지만, 썩 마음에 드는 건 아니다.
다른 기업들은 어떻게 생각하고 고민해서 어떤 방향으로 만들고 있는지, 어떻게 했더니 어떤 점이 어려웠었는지 이야기를 심도 있게 들어보고 싶다 ㅠㅠ

어려웠던 점

일단, 레퍼런스가 생각보다 많지 않았다. 다른 기업의 기술 블로그를 통해서 결과물의 일부분을 살짝 맛을 볼 수는 있는데, 결과물만 보는 것이지 과정을 보는 것이 아니다보니 어떤 목적과 목표를 가지고 어떻게 고민해서 만들어 왔는지의 여정을 보거나, 어떻게 하는 것이 모범 사례인지를 알기가 어렵다.
그냥 계속 남의 것을 염탐(?)하고 과정을 추측해 보는 방법 밖에는 없는걸까? 😥😥

또, storybook이 기본적으로 react를 사용하고 있어서 그런지 다소 Vue에는 궁합이 부족한 부분이 더러 있고, 이걸 해결할 다른 방법을 찾는 게 쉽지 않다.
일례로 storybook의 소스 코드 뷰어가 react 문법을 기반으로 보여주기 때문에 실제로 보여주고 싶은 Vue 문법이 아니라서 이걸 별도로 보여줄 방법을 찾아야 하는가 혹은 그냥 둘 것인가 등의 고민 포인트가 생기고 해결은 당연히(?) 쉽지 않다. (내가 할 수 있는 건 github 이슈에 질문을 남기는 것 뿐...)

더구나 주변에 이거 쓰는 사람 찾기가 어렵... 나란 놈은 인맥이 왜 이 모냥인거지...

좋았던 점

  • 우선, atomic design의 컨셉 상 page 단위에 이르러서야 데이터가 바인딩 되기 때문에 외부로부터 주입받아야 하는 데이터에 의존적이지 않은 컴포넌트 구현이 이루어지고 따라서 재사용성이 매우 높아졌다.
    물론 반대로 이야기 하면, 그만큼 확장성과 추상성에 대한 고민을 해야 하고 생각 이상으로(?) 수 많은 props가 탄생하기도... 쿨럭...

  • storybook이 있으니 컴포넌트에 어떤 props가 필수였는지 값에 대한 제한 사항은 무엇인지 코드 레벨에서 확인하지 않아도 되니 편하더라.
    단지 한 쪽 브라우저에 storybook을 띄워 놓기만 하면 찾는 건 금방이니 코드를 보고 인식하는 것보다 더 직관적이고 빠르다. (아, 물론 문서를 잘 작성했을 때의 이야기...)

    그러고 보니, storybook이 jsdoc를 통한 유추가 좀 더 잘 되었으면 싶다. 내가 아직 몰라서 그런 것일 수도 있지만, storybook + vue에서 props에 대한 문서화가 jsdoc으로는 이루어지지 않는 것 같다. 이것만 잘 되어도 문서화가 코드 레벨에서 많이 정리 될 수 있을 거 같은데... (아, 오히려 컴포넌트 코드가 더 지저분해 보일 수도 있으니 별도 문서로 빼는 게 나을 수도 있겠다는 생각도 들기도 한다.)

  • 내가 가진 기술 부채 중 한 가지가 TDD다. 그래서 컴포넌트에 대한 테스트가 다소 우려 사항 중의 하나인데, storybook이 그 우려를 조금이나마 완화시켜 주고 있다.

    storybook이 없을 때에는 한 개 컴포넌트만 렌더링 시켜서 확인하기에는 다소 불편해서 페이지 단위에서 확인했었는데, storybook 이후로는 개별 컴포넌트 별로 바로 확인이 가능하니 적어도 props나 event 처리에 대한 오류를 빨리 줄일 수 있었다.

  • storybook에는 다양한 addon들이 존재하는데 viewport(responsive), a11y, dark mode, zeplin·figma viewer embedding 등과 같은 것들은 꽤나 도움이 될 만한 것들이라고 생각된다.
    접근성에 지대한(?) 관심을 가지고 있는 나로서는 addon-a11y는 컴포넌트 단위부터 접근성에 대한 정량 평가를 직관적으로 확인 할 수 있어 좋다고 생각한다.