안녕하세요. 사람인HR IT연구소 UI개발2팀 정영환입니다.

지난 등용문S 개발기에 이어 Vue로 프로젝트를 진행하였습니다. 그 당시와 달리 작년 9월에 릴리즈한 Vue3로 개발하면서 storybook을 활용했다는 차이가 있겠네요. Vue3에 대한 이야기는 안수미 연구원님께서 정리한 Vue, 원피스로 떠나는 여정에 담았으니 이 글은 storybook에 집중해볼게요.

vuejs3 releases

커넥트는 기업과 핵심인재를 연결하는 인재 발굴 플랫폼입니다. 인사담당자 관점에서 만든 서비스로 해당 플랫폼인 커넥트를 만들면서 겪었던 이슈와 함께 어떻게 대응하였는지 회고하기 위하여 기록합니다. 분석과 설계, 구현 그리고 산출물에 이르기까지 단계별로 진행하면서 느꼈던 고민과 경험담을 담았습니다. 개인적인 의견이 많이 들어간 글이라 읽으실 때 참고해주세요.


목차

분석
설계
구현
산출물, storybook
마침표



분석

디자인 분석, 기술 분석 그리고 벤치마킹

1) 디자인 분석

디자인이 나오면 UI를 구현하기에 앞서 디자인 산출물에 대하여 전반적인 분석을 진행합니다.

컴포넌트 디자인이 선행되어야 컴포넌트를 코드로 녹일 수 있습니다. 프로젝트 초기 디자인을 분석할 당시에는 컴포넌트에 대한 디자인이 나오지 않아 Atomic Design 형태로 요청을 드렸습니다. 전체 그림을 그리기 전에 컴포넌트 디자인을 활용하여 화면을 구상했다면 시간을 아낄 수 있을 것처럼 보였지만, 현실은 다르더군요.

만약 디자인 분석부터 시작하신다면 동적 스타일에 대한 디자이너 요구사항도 확인하는 게 좋습니다. 흔하디 흔한 버튼도 hover, active, disabled와 같은 인터렉션을 놓치고 지나가는 경우가 종종 발생하거든요. 또한 props로 제어 가능한 공통 컴포넌트와 예외처리되는 부분도 디자이너와 함께 상의해야 개발이 수월합니다. 작업을 하다보면 처음에 제작한 컴포넌트로 표현하지 못하는 디자인 요소들이 생기기 마련입니다. 미리 관리해야 전체 일정을 파악하고 조율하기 수월합니다. 사전에 논의하고 명시하면서 정책을 정하는 게 중요합니다.

2) 기술 분석

프로젝트에 새로운 기술을 적용하기 전에 기술 분석을 꼭 거쳐야 합니다. 평소에 사용하지 않던 기술이나 버전을 올릴 때조차 사전에 기술 분석하는 절차가 필요합니다. 발생할 수 있는 이슈에 대하여 미리 파악해야 도입 여부를 판가름하기 좋습니다. 사전에 기술 검토를 꼼꼼히 진행할수록 프로젝트 진행 시 시행착오를 줄이고 원활하게 마무리 지을 수 있습니다.

이번에 개발한 커넥트는 Vue3, vuex, SCSS, swiper, EsLint, storybook을 사용하기로 결정했었습니다. 기술 분석할 시점에서 Vue3가 크게 문제가 되지 않을 거라고 판단했었습니다. 프로젝트를 진행하다 보니 라이브러리 제한이 생각보다 크게 다가와 다소 애를 먹었습니다. 한편 컴포넌트 운영 가이드로 사용한 storybook도 Vue3와 mdx 방식으로 시행착오를 겪었습니다. 이 부분은 산출물(storybook) 단계에서 다시 이야기해드릴게요.

3) 벤치마킹

컴포넌트를 개발하면서 UI Framwork Open Source(vuetifyvuematerial를 참고했습니다. 다른 개발자들이 고민하여 만든 오픈소스 가이드는 어떤 식으로 구조화되었는지 벤치마킹하였습니다. 이 외에도 널리 사용되는 컴포넌트 구조를 살펴보며 프로젝트에 적용하였습니다.



설계

Atomic Design 구조 그리고 EsLint + prettier 설정

1) Atomic Design 구조

Atomic Design 구조를 기반으로 componets 디렉토리를 구성하였습니다. atoms 레벨은 아직 크게 사용하지 않더라도 molecules와 organisms의 원형이 되는 단계이므로 미리 구조를 잡았습니다. 디자이너 분께도 Atomic Design에 맞추어 컴포넌트를 디자인하도록 요청드렸습니다. 디자인 단계부터 이를 고려하여 그림을 그리지 않으면 기존 아토믹 컴포넌트는 갱신되지 않은 채 예외 처리가 늘어날 수 밖에 없습니다.

src
 ├─ components
 │  ├─ atoms
 │  ├─ molecules
 │  ├─ organisms
 │  └─ template
 │
 └─ views
    └─ ...

일반적인 Atomic Design은 templates와 pages를 구분하여 사용하지만, 이번 프로젝트는 templates를 layout으로 활용하고 views에 pages를 구성하였습니다.

2) EsLint + prettier 설정

작업자 간 원활한 의사소통을 위하여 코드 작성에 대한 규칙, 컨벤션을 정한 뒤 개발하는 게 좋습니다. 통일된 formatterlinter를 적용하면 코드 전반적인 가독성이 향상되어 다른 사람이 작성한 코드도 수월하게 파악됩니다.

프로젝트 초기에 고려해야 할 문제가 산재하여 미처 신경을 쓰지 못 하였던 부분이었으나, 함께 프로젝트를 진행했던 안수미 연구원님께서 대신 챙겨주셨습니다. 덕분에 프로젝트를 잘 마무리 지을 수 있었네요. eslintprettier는 기본적으로 제공되는 rules를 크게 건들지는 않았습니다. build 시 작업자 간 동일한 소스 코드를 바라보는 게 목적이었습니다.

"eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "eslint:recommended",
      "plugin:vue/vue3-recommended",
      "@vue/prettier"
    ],
    "parserOptions": {
      "parser": "babel-eslint"
    },
    "rules": {
      "prettier/prettier": [
        1,
        {
          "useTabs": false,
          "printWidth": 120,
          "tabWidth": 2,
          "semi": true,
          "singleQuote": false
        }
      ]
    }
  },


구현

컴포넌트 제작 그리고 views 제작

디자이너에게 요청한 컴포넌트 디자인을 받아 이를 분석하면서 컴포넌트 코드를 작성하였습니다. 초기에는 organisms 영역이 분명하지 않고 동적 UI에 대한 상세스펙이 표현되지 않았습니다. 디자이너와 수차례 협의하며 컴포넌트를 구성해나갔습니다. 디자인 분석 단계를 여러 번 거쳐야 비로소 완성된 컴포넌트가 만들어집니다.

-Component design

예시1 예시2
컴포넌트 디자인01 컴포넌트 디자인02

결과적으로 foundation 3개, atomic 15개, molecules 20개, organisms 19개, 여기에 template 4개를 추가하여 총 61개의 컴포넌트를 개발하였습니다. 함께 논의하며 만든 컴포넌트를 기반으로 views 제작에 들어갔습니다.

이번 프로젝트를 진행하면서 organisms에 대해 다시금 깊게 고찰을 하였습니다. atomic과 molecules, molecules와 molecules의 조합을 모아둔 organisms는 views 페이지에서 큰 덩어리 역할을 수행합니다. 처음 Atomic Design 구조로 구상할 때 atomic내 컴포넌트는 공통으로 사용하는 요소로 인지하여 store나 API는 props로 받아와 처리할 계획이었습니다. 하지만 개발을 하면 할수록 몇몇 organisms 컴포넌트에서 store 나 API를 직접 연동하게 되었습니다. 개발해보니 공통 component라는 기준점이 사라지게 되었습니다.

이처럼 organisms 컴포넌트에서 다른 API를 호출해야 하는 경우가 생긴다면 동일한 디자인임에도 불구하고 새로운 컴포넌트를 만들던지 API호출부를 분기처리 해야 하는 문제가 생겨버린 겁니다. 가급적 organisms 컴포넌트에서 store나 API를 직접 호출해서 사용하지 않아야 재사용성이 높아집니다.



산출물, storybook

connect storybook

만들어진 컴포넌트를 기반으로 디자인시스템을 구축하고자 storybook을 활용했습니다. storybook을 이용하여 현재 프로젝트에 구축된 컴포넌트를 한눈에 확인 가능합니다. 또한 각 componets가 가진 스타일과 특성을 storybook 자체에서 제공하는 addon을 통해 확인할 수 있습니다. (참고 : Design Systmes for Developers)

  • actions에서 인터렉션에 의해 전달된 값을 미리 확인할 수 있습니다. connect storybook

  • controls를 이용하여 각 props에 따라 component가 어떻게 변하는지 살필 수 있습니다. connect storybook

  • docs에 component들에 대한 간략한 가이드를 제공하였습니다. connect storybook

vue3에 storybook MDX방식을 적용해보니 두 가지 이슈가 발생했습니다.

첫 번째는MDX문서에서 component를 import 할 수 없었습니다. storybook을 인스톨하는 과정 중에 storybook은 번들로 webpack4를 제공하는데, 그로 인하여 생긴 문제입니다. webpack@5, @storybook/builder-webpack5@next, storybook/manager-webpack5@next로 다시 인스톨하고 .storybook/main.js 에 core 추가한 후 문제가 해결되었습니다.
참조 : storybook experimental Webpack5 support

  • npm install
    //Upgrade
    npx sb@next upgrade --prerelease
       
    //Install
    npm i -D @storybook/builder-webpack5@next @storybook/manager-webpack5@next webpack@5
    
  • package.json
    //Add
    devDependencies:{
        "webpack": "^5.0.0",
        "css-loader": "^5.0.0",
        "dotenv-webpack": "^6.0.0",
        "html-webpack-plugin": "^5.0.0",
        "style-loader": "^2.0.0",
        "terser-webpack-plugin": "^5.0.0",
        "webpack-dev-middleware": "^4.1.0",
        "webpack-virtual-modules": "^0.4.2"
    }
    
  • /.storybook/main.js
    module.exports = {
      "core": {
        "builder": "webpack5"
      },
    }
    

두 번째는 optional chaining 문법을 사용하기 위해 babel-loader에 plugins 설정을 해줘야 한다는 겁니다.
참고 : Optional chaining not working

  • /.storybook/main.js
    webpackFinal: async (config, { configType }) => {
      config.module.rules.push({
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@vue/cli-plugin-babel/preset', '@babel/preset-env'],
            plugins: ['@babel/plugin-proposal-optional-chaining']
          }
        },
      });
    }
    

앞으로 커넥트를 위한 디자인시스템을 가꾸어 나가기 위해 디자이너와 개발자 간 협의하고 결정해야 할 일들이 산더미처럼 남았습니다. 현재도 운영하기에는 무리가 없지만 조금 더 보완 한다면 운영에 할애하는 시간을 줄일 무기가 될 겁니다.



마침표

새로 릴리즈 된 Vue3 경험하고 storybook을 활용하여 디자인시스템을 구축하고, 커넥트와 함께 새로운 영역에 도전을 해보았습니다. 처음에는 새로운 시도에 대한 막연한 두려움도 없잖아 있었지만 새로운 방법론을 접하고 익히면서 점차 성취감을 느낀 제 모습을 보았습니다.

마지막으로 함께 프로젝트에 참여한 UI개발2팀 김선미, 안수미 연구원님 고생하셨습니다.