ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 디자인 시스템 구축하기
    Studying/Proj 과정 2023. 5. 25. 19:05

    디자인 시스템이란?

    디자인 시스템(Design System)은 디자인 원칙부터 재사용할 수 있는 UI 패턴과 컴포넌트, 코드로 구성된 시스템을 의미한다. 이는 전체 서비스에 효율적이고 일관된 디자인을 적용할 수 있도록 도와준다.

     

    간단히 말하자면, 기업의 이미지와 컨셉을 고려하여 하나의 디자인 틀을 마련하는 것입니다. 이는 어쩌면 디자이너들의 역량이 더 강화된 업무라고 생각할 수도 있겠습니다. 하지만 디자이너의 요구사항에 맞춰 재사용 가능한 컴포넌트를 구현하는 것도 일련의 과정 중 하나입니다.

     

     

    디자인 시스템 구축 과정

    대략적인 디자인 시스템 구축 과정은 아래와 같습니다.

     

    1. 디자인 원칙 정의

    • 일관된 사용자 경험, 시간/비용 절약, 팀 간 협업 등 Design System을 통해 달성하고 싶은 목표를 설정한다.
    • 설정 된 목표와 브랜드 가치를 고려하여 Design System 전반에 적용되는 디자인 원칙을 설정한다.

     

    2. 제품 검토

    • 디자이너와 개발자가 제품에서 사용하는 공통 컴포넌트 및 패턴을 분석하여, 디자인 시스템에 포함할 요소를 선장한다.
    • 버튼, 인풋, 탭, 카드 등의 UI 요소가 있다.

     

    3. 스타일 가이드 개발

    • 디자인 원칙에 따라 스타일 가이드를 개발한다.
    • 색상 팔레트, 타이포그래피, 아이콘, 간격, 그리드 시스템 등의 디자인 요소들이 포함된다.

     

    4. 컴포넌트 디자인 및 문서화

    • 재사용할 수 있는 컴포넌트와 패턴의 디자인을 완성하고 사용 방법 및 관련 세부사항을 문서화 한다.
    • 이 문서에는 디자인 시스템의 모든 구성 요소가 정확하게 기록되어야 한다.
    • 이를 개발자가 쉽게 적용할 수 있도록 코드 스니펫 또는 컴포넌트 라이브러리를 제공한다.

     

    5. 디자인 시스템 구현

    • 개발자가 디자인 시스템에서 제공하는 컴포넌트와 패턴을 사용하여 실제 웹사이트나 앱을 구현한다.
    • 이 과정에서 디자이너와 개발자 간의 긴밀한 협업이 필요하다.

     

    6. 지속적인 유지보수 및 업데이트

    • 사용자의 피드백을 반영하거나 기존 요소를 개선하는 작업을 수행한다.
    • 기능 확장에 따른 컴포넌트 추가 등이 이루어질 수 있다.

     

     

    여기서 저는 파란색으로 밑줄 친 개발자의 역할에 초점을 두고 리팩토링을 했습니다. 다만 전체 코드를 바꾼 게 아닌 아주 기초적인 일부분만 연습 겸 진행해보았습니다.

     

     

     

    솔로 프로젝트에 Storybook 설치하기

    아래 명령어로 Storybook을 설치합니다.

    npx storybook@latest init

     

    설치가 완료되면 아래와 같이 .storybook 폴더가 생성됩니다.

     

     

    설치된 모습

     

    실행 명령어는 아래와 같습니다.

    npm run storybook

     

     

    UI 인벤토리 작성 및 분석

    UI 인벤토리 작성이란, 프로젝트에서 사용 중인 모든 UI 요소들을 정리하고 분석하는 과정을 말합니다. 프로젝트에서 사용된 모든 UI를 캡처하고 한 곳에 모아두어야 합니다.

     

    사용 툴은 Google Slides 또는 Keynote 가 있습니다.

     

    각 요소들을 컴포넌트, 버튼, 아이콘, 이미지, 색상, 글꼴 등의 카테고리로 분류할 수 있습니다.

     

    이 작업이 끝나면, 디자인 시스템에 포함할 패턴을 선별하고 문제점을 파악하여 개선 방안을 찾아야 합니다. UI 인벤토리와 개선점을 정리해 레포지토리의 이슈로 작성합니다.

     

    🎁 How to create an interface inventory

     

    실습을 진행하면서 이 부분에 대해 딱히 감이 오지 않았습니다. 카테고리 분류 기준도 잘 모르겠고, "UI 인벤토리를 Figma로 옮긴다" 라고 알려주길래 'Figma에 목업이 있어야 UI 인벤토리를 작성하는 거 아닌가?' 의문도 들었습니다.

     

    코치님께 여쭤보니 "그냥 Figma로 만들어 봐라." 라는 답변을 얻었습니다. 일단 그냥 Figma로 만들고, 위 개념에 대해선 포괄적으로 생각하라고 합니다.

     

    더불어 개발자의 영역과는 좀 거리가 있는 부분이기 때문에 훗날 솔로 프로젝트에서나 이런 과정을 거치지 않을까 싶습니다.

     

     

    Figma를 사용해 컴포넌트 디자인

    대망의 디자인 작업, 이 아닌 개발자인 저로서는 그냥 간단하게 구조만 구상하였습니다. 하지만 체계적인 절차는 다음과 같다고 합니다.

     

    • UI 인벤토리를 Figma로 옮긴다.
    • 이를 통해 디자인 패턴을 발견하고, 그에 따르 컴포넌트를 만든다.
    • Figma의 컴포넌트 셋 기능을 활용하여 다양한 상태의 컴포넌트를 만든다.
    • Figma의 스타일 기능을 활용하여, 색상, 폰트, 그림자 등의 스타일을 설정한다.
    • Figma Tokens 플러그인을 사용해 토큰으로 만들어 추출한다.

     

    저는 이미 3월에 카카오 오븐으로 만들어둔 디자인이 있어서 이걸 계속 사용하고자 했습다. 사실 Figma를 사용하여 디자인 토큰을 뽑아야 하는데, 제목만 '디자인 시스템 구축하기' 라고 해놓고 비록 이렇게 되었습니다. 그 대신 다른 홈페이지의 디자인 토큰을 제것처럼(?) 사용해서 만들어보려고 합니다.

     

    UI는 아래와 같습니다.

     

     

    메인 페이지

     

    질문 상세 보기 페이지

     

     

    확장 가능한 컴포넌트 만들기

    디자인 작업이 완료되면 React 컴포넌트를 구현합니다. Storybook을 사용해 각각의 컴포넌트를 독립적으로 개발하고, 여러 상황에 맞게 적용될 수 있도록 확장 가능한 컴포넌트를 개발하면 됩니다.

     

    이에 대한 것으로 다음과 같은 가이드를 따르면 확장 가능한 컴포넌트를 만들기 수월해집니다.

     

    • Props 기반의 커스터마이징: 속성(props)을 통해 컴포넌트의 외형/동작을 제어할 수 있다.
    • 아토믹 디자인 적용 : 텍스트, 버튼, 인풋 등 더이상 쪼개지지 않는 요소를 정의하고 이를 조합해 새로운 UI를 만든다.
    • 상태에 따른 변화: 활성 상태/비활성 상태/로딩 상태 등 하나의 컴포넌트 안에 다양한 상태를 고려하여 설계한다.
    • 테마: styled-components의 Theming 을 사용하여 앱 전체의 테마를 쉽게 바꾸는 구조를 만든다.

     

     

     

    Storybook을 사용해 컴포넌트 UI 문서화

    아주 단순하게 기본 atoms 요소 및 버튼까지 만들어봤습니다.

     

    1) 스토리 작성하기

    컴포넌트에 대한 '스토리'를 작성합니다.

    여기서 스토리란, 컴포넌트의 특정 상태를 보여주는 코드 스니펫(code snippet:재사용 가능한 조각)을 말합니다.

    예를 들어 하나의 컴포넌트에 '기본 상태', '활성화 상태', '비활성화 상태' 등의 스토리를 작성하는 것입니다.

    일단 대략 이만큼의 아토믹한 요소들을 뽑아 보았습니다.

     

     

    common 폴더 구조

     

     

    Button 컴포넌트

    버튼 컴포넌트는 아래와 같은 디자인 토큰들을 사용합니다.

    const { Spacing, borderRadius, Primary, Gray, White, Accent } = globalToken;

     

    버튼 컴포넌트는 아래와 같습니다. 버튼 몸체인 <ButtonContainer> 안에 기본적으로 <LabelText> 요소가 들어가고 필요에 따라 <Icon> 요소가 추가됩니다.

     

    export const Button = ({mode, label, icon, ...rest}) => {
        return (
            <ButtonContainer mode={mode} gap={Spacing[8].value} {...rest}>
                { icon &&
                    <Icon icon={icon}/>
                }
                <LabelText children={label}/>
            </ButtonContainer>
        )
      }

     

    버튼은 다크모드/일반모드가 존재할 예정이므로 그에 맞춰서 styled-component를 잘 생성했습니다.

    사실 다크모드/일반모드를 이렇게 말도 안 되게 구현하지 않는 것으로 알지만 일단 스토리북 연습을 위해 만들고 이후에 라이브러리 등을 알아봐야겠습니다.

    const ButtonContainer = styled.button`
        border: none;
        outline: none;
        background-color: transparent;
    
        display: flex;
        align-items: center;
        gap: ${(props)=>props.gap || 0}px;
    
        cursor: pointer;
        border-radius: ${borderRadius[8].value}px;
    
        & > svg {
            color: inherit;
        }
    
        padding: ${Spacing[8].value}px ${Spacing[16].value}px;
    
        ${(props)=> props.mode === 'DarkMode'?
            css`
                background-color: ${Gray[400].value};
                color: ${Gray[700].value};
    
                &:hover {
                    background-color: ${Gray[300].value};
                }
            `
        :
            css`
                background-color: ${Primary.value};
                color: ${White.value};
    
                &:hover {
                    background-color: ${Accent.value};
                }
            `
        }
      `;

     

     

    컴포넌트 구현이 끝나면 해당 컴포넌트에 대한 스토리를 아래와 같이 작성합니다.

    export default {
      title: 'Basic/Buttons',
      component: Button,
      argTypes: {
        mode: {
            options: ['DarkMode', 'LightMode'],
            control: {type: 'radio'}
        }
      }
    };
    
    // Button 스토리 정의
    export const PrimaryButton = {
      args: {
        mode: 'DarkMode',
        label: 'Button'
      },
    };
    
    // Icon Button 스토리 정의
    export const IconButton = {
      args: {
        ...PrimaryButton.args,
        icon: 'BsBellFill'
      },
    };
    
    IconButton.argTypes = {
        icon: {
            options: iconNames,
            control: { type: 'select' },
        }
    }

     

     

     

    2) 스토리 확인하기

    이제 작성한 스토리를 스토리북에서 확인합니다. 예상치 못한 동작을 할 경우 즉시 바꿔주며 컴포넌트를 만들어가면 됩니다. 늘 App.jsx 파일에 우선 출력하고 확인했었는데 스토리북이란 정말 좋은 것 같습니다.

     

     

     

     

    3) 스토리 문서화하기

    이제 각 스토리에 대한 description을 추가해서 문서화 하면 완성입니다.

    export default {
      title: "Components/Button",
      component: Button,
      // add
      argTypes: {
        [props_name]: {
          description: "원하는 description을 적으세요",
        },
      },
      //
    };

     

    실제 NASA에서 배포한 스토리북 중 일부를 살펴보면, 아래와 같이 각 속성마다 어떤 의미가 있는지 자세히 적혀있는 걸 볼 수 있습니다.

     

    속성 설명

     

     

    그 외 실제 기업에서 사용하는 Storybook을 참고해보는 것도 도움이 될 것 같습니다.

     

     

     

    Plus. 스토리북 배포하기

    이제 제가 만든 스토리북을 배포합니다. 팀 프로젝트를 할 때 스토리북을 작성한 뒤 이렇게 배포하면 보는 사람 입장에서 개발자가 어떤 부분을 구현했는지 명확하게 알 수 있어 좋다고 합니다.

    방법1) 정적 웹사이트로 배포하기

    첫 번째 방법은 로컬 머신에서 Storybook을 빌드하고 정적 웹 사이트로 호스팅 하는 것입니다.

     

    package.json에 정의된 build-storybook 스크립트를 사용하여 빌드를 진행합니다.

    이렇게 생성된 storybook-static 폴더는 Vercel과 같은 클라이언트 배포 플랫폼을 이용하여 외부에서도 접근 가능한 링크로 변환할 수 있습니다.

    이를 통해 어디서나 쉽게 스토리북에 접근할 수 있습니다.

     

    방법2) Chromatic 을 이용하여 배포하기

    두 번째 방법은 Chromatic을 사용하여 클라우드에서 Storybook을 자동으로 빌드하고 배포하는 것입니다.

     

    Chromatic이란 스토리북을 빌드, 호스팅, 변경사항 추적 기능을 제공하는 Storybook의 공식 클라우드 서비스입니다. 

     

    일단 Chromatic 웹사이트에서 계정을 생성하고 프로젝트를 등록해야 합니다.

     

    그 다음 아래 명령어를 통해 Chromatic CLI를 프로젝트에 설치합니다.

    npm install --save-dev chromatic

     

    설치가 완료되면 package.json 파일의 scripts 항목에 아래 명령어를 추가한다.

    {
      "scripts": {
        "chromatic": "npx chromatic --project-token=<your-project-token>"
      }
    }

     

    이제 아래 명령어를 실행하면 Storybook이 빌드되고 Chromatic에 배포 된다.

    npm run chromatic

     

    Chromatic 웹사이트에서 배포된 Storybook을 확인하고 변경사항을 추적해보면 됩니다.

     

     

     

     

    이렇게 가짜(?) 디자인 시스템을 기반으로 컴포넌트를 구현하고 문서화 작업을 진행해보았습니다. 확실히 이전보다 500%는 더 성장한 것 같습니다. 특히 컴포넌트를 아토믹한 요소로 분리하여 조립하는 과정이 너무 편리하고 좋았습니다. 훗날 팀 프로젝트를 한다면 배운 방법을 활용하여 공통 컴포넌트를 구현하고 싶습니다.

Designed by Tistory.