2022년 마지막 프로젝트의 회고 2 — Atomic Design, CSS Module

아토믹 디자인, CSS Module, Tailwind CSS를 적용하며 경험한 장단점을 정리한 프로젝트 회고.

Design Pattern, Frontend, Next.js

Proem

Next.js를 이용해 작성한 Galaxy-Market 프로젝트에, Lazy Loading과 Suspense를 적용해보다가 디렉터리를 보며 회의감이 와서, 새로이 아토믹 디자인 시스템을 적용하면서 컴포넌트를 모조리 재설계하고, 로직을 리팩토링했다. 그리고 그런 짧지 않았던 기간동안에 느꼈던 점들을 이야기하려 한다.

아토믹 디자인 시스템으로 이식하기
Atom, Molecule, Organism, Templete, 그리고 pages!
Atom, Molecule, Organism, Templete, 그리고 pages!

아토믹 디자인 시스템(Atomic Design System)이란, 이름 그대로 원자적인 설계에 따라 인터페이스 시스템을 만드는 것을 의미한다.

화학에서 분자는 두 개 이상의 원자로 구성되는데, 이처럼 원자에서 시작하여 분자, 유기체, 템플릿, 페이지까지 이르는데, 하위 계층의 컴포넌트끼리 결합하여 상위 컴포넌트를 이루는 것이다.

이번 프로젝트에서는 원자 단계에 가까울수록, 로직과 관계를 최소화하여 가능하면 순수한 컴포넌트로, 페이지에 가까울수록 순수한 HTML/CSS 구조보다는 로직에 보다 집중한 컴포넌트로 분리해 개발하여, 최대한 컴포넌트의 재사용성을 살릴 수 있게끔 노력했다.

이렇게 리팩터링하고 느낀 점은, 컴포넌트들의 단계적인 분리로 디렉터리도 보기 좋아졌고, 어떤 기능 추가를 위한 새로운 컴포넌트 혹은 페이지를 만들 때, 미리 만들어둔, 로직과 분리된 원자와 분자 단계의 컴포넌트들로 빠르게 구성할 수 있었다. 또한, 일관성 있는 디자인을 위한 마크업의 유지 보수도 용이했다.

하지만 무조건 좋은 점만 있던 것은 아니었다. 간단한 애플리케이션이라면 이런 아토믹 시스템을 적용시키기엔 규모에 비해 비교적 많은 시간과 노력이 필요할 것이고, 실제로 하위 계층에 가까운 컴포넌트들을 개발하는 데에 적지 않은 시간이 드는 것을 체감했다.

그래도 애플리케이션의 개발 초기에 아토믹 디자인 시스템을 견고하고 완성도 있게 구성할 수 있다면 컴포넌트의 재사용과 애플리케이션의 확장의 측면에서 굉장히 큰 장점을 오랜 시간 동안 가져갈 수 있다고 생각한다.

CSS Module 스타일, 그리고 CSS-in-JS 스타일
주요 CSS 프레임워크 및 라이브러리의 다운로드 수 비교 by npm trends
주요 CSS 프레임워크 및 라이브러리의 다운로드 수 비교 by npm trends

여태까지 CSS 파일로 스타일을 구성하고 import 하는 전통적인 방식과 styled-components를 이용한 CSS-in-JS 방식의 웹 애플리케이션 스타일 구성 방식으로 프로젝트를 한 적이 있었고, 이번엔 다른 방식인 CSS-in-CSS 방식 중 CSS Module 방식으로 Tailwind CSS를 이용한 스타일 구성을 시도해 봤다.

먼저 CSS-in-JS 방식은, 자바스크립트 코드에서 CSS를 작성하는 방식으로, 2014년에 페이스북의 개발자인 Vjeux가 처음 소개했다고 한다.

Vjeux에 따르면, 모든 스타일을 global에 선언하기에 생기는 클래스 네임과 스타일의 중첩 가능성 문제, 하나의 객체에 적용되는 여러 CSS 간의 의존 관계 관리 문제, CSS와 JS 파일이 분리되어 발생하는 기능 변경에 따른 유지 보수 문제, 중복 방지를 위한 길고 복잡한 클래스 네임을 사용해 발생하는 문서 사이즈 증가 문제, JS-CSS 간의 상태 공유가 난해해지는 문제, CSS 로드 순서에 따라 우선순위가 달라지는 문제, CSS와 JS의 상속에 따른 문제 등을 모두 해결할 수 있다고 한다.

실제로 프로젝트에 적용해 본 후기는, 하나의 컴포넌트 파일에서 스타일과 기능적인 부분을 한 번에 정의하는 게 정말 편하고, 클래스 네임 명명의 어려움도 확연하게 줄어들었었다.

정말 많은 기존의 문제들을 해결할 수 있으나, 새로운 의존성 발생 가능성, 별도의 라이브러리 — styled-components, emotion, glamorous 등 — 설치로 인한 번들링 사이즈 증가, CSS-in-CSS에 비하면 느린 속도 — 자바스크립트 구문 해석 과정이 더 길어지므로 — 등의 문제 또한 존재한다.

이번에 이용한 CSS Module 방식은 CSS를 모듈화하여 사용하는 것으로, CSS 클래스를 만들면 자동으로 고유한 클래스 네임을 만들어 스코프를 로컬로 제한한다.

모듈화된 CSS를 번들러로 불러오면, 사용자가 정의한 클래스 네임에 고유한 클래스 네임이 합쳐진 객체가 반환된다. 그러므로 CSS 모듈은 프로젝트 소스 내에 CSS 클래스 네임이 중복되더라도, 겹치지 않아 중복 및 관리의 위험성이 적고, CSS 클래스 네임 작명의 고충이 줄어드는 장점이 있다.

물론 장점만 있는 것은 아니고, 한 곳에서 모든 것을 작성하는 것이 아니기에 별도로 CSS 파일을 작성해야 하므로 많은 파일들을 작성하고 관리해야 하는 단점도 존재한다. 실제로 이런 단점이 있었지만, 아토믹 디자인 시스템에 입각해 컴포넌트를 설계했기 때문에 큰 불편함으로 다가오지는 않았다.

CSS Module에 Tailwind CSS로 가미하기

그리고 이제 CSS Module 방식으로 사용하여 이번 프로젝트 스타일 구성의 주를 이룬 Taliwind CSS 이야기를 할 차례다. Bootstrap과 비슷하지만, 확실히 다르다.

Bootstrap은 미리 만들어진 컴포넌트를 쉽고 빠르게 사용해서 스타일을 구성할 수 있고, 동시에 컴포넌트 간의 디자인적 일관성도 높게 가져갈 수 있지만, 미리 만들어져있는 컴포넌트로만 스타일을 구축하게 되어 더 디테일한 스타일의 커스터마이즈가 어렵고, 사용하지 않는 요소까지 번들링 파일에 포함되어 사이즈가 커지는 단점도 있다.

하지만 Tailwind CSS는 거의 대부분의 CSS 스타일을 아주 쉽고 편하게 작성할 수 있으며 빌드 시에 사용하지 않는 클래스가 제거되어 번들링 사이즈 최적화도 유리하다.

모든 기술에는 일장일단이 있듯, 이런 완벽해 보이는 Tailwind CSS에도 단점이 있는데, 단위가 기본적으로 rem이기 때문에 다른 단위를 사용할 경우 p-[10px] 같이 직접 기술해 주어야 하며, 애니메이션과 트랜지션 사용에 있어서 animate-spin, animate-pulse 같이 미리 정의된 프리셋 애니메이션만 사용 가능하기 때문에 조금 더 화려하고 복잡한 애니메이션은 직접 추가해서 사용해야 한다. 또한 빌드 타임에 모두 생성되므로, 동적인 변수를 사용할 수 없다. 그래서 이번 프로젝트에서도 프로필 카드의 애니메이션을 직접 정의해 사용했었다.

이번 프로젝트에서 사용한 CSS Module 방식과 Tailwind CSS의 조합이 주는 컴포넌트 개발 경험은, 아직 경험해온 부분보다 경험해 볼 부분이 많지만 그래도 정말 최상이었다. 이전에, 동적 변수를 사용할 수 있는 styled-components에 Framer-motion을 더해 어렵지 않게 재미있는 인터랙션과 다채로운 컴포넌트를 구현한 경험도 있었지만, 일관성 있는 디자인과 성능을 쉽게 챙길 수 있다는 점은 정말 만족스러운 부분이었다.

References

리액트 어플리케이션 구조 - 아토믹 디자인

웹 컴포넌트 스타일링 관리 CSS-in-JS vs CSS-in-CSS

카카오웹툰은 CSS를 어떻게 작성하고 있을까?

CSS vs. CSS-in-JS: How and why to use each - LogRocket Blog

aphrodite vs bootstrap vs emotion vs glamorous vs styled-components vs tailwindcss | npm trends


원문: Medium