본문으로 건너뛰기
cheonbi
PostsSeriesTagsAbout🎥 Kinetograph
EN

Tweaks

theme
accent palette
film grain
minimal mode
BACK TO INDEX
◆ ESSAY
--min
--year
KOoriginal

mailMail icongithub
cheonbi
•
© 2026
•
https://cheonbi.kr
BACK TO INDEX
◆ SERIES · 경계를 긋는 디자인 시스템

디자인 시스템의 진짜 문제는 바꾸는 것이다

avatar
cheonbi
2026-09-22 · 13분
13min
2026year
KOoriginal
design-systemfrontendarchitecturea11y
시리즈

경계를 긋는 디자인 시스템

3 / 4
목록 보기
  1. 01디자인 시스템을 만드는 공장 뜯어보기
  2. 02설계 결정 일곱 가지와 정직한 비용
  3. 03디자인 시스템의 진짜 문제는 바꾸는 것이다
  4. 04작은 팀은 어디에 경계를 그어야 하는가
설계 결정 일곱 가지와 정직한 비용작은 팀은 어디에 경계를 그어야 하는가

Table Of Contents

  • 저장소의 절반은 '바꾸기 위한 장치'다
    • codemod 19개의 구성이 말해주는 것
    • deprecations 원장, 그리고 흉터 하나
    • 복붙 배포의 대가를 치르는 도구
    • packages/archive/ — 스타일링 기술의 묘지
  • V2는 왜 무너졌나 — 결함이 맨 아랫단에 박혀 있었다
    • 토큰은 늘리는 게 아니라 줄이는 것
    • 철학 반전: '제한'에서 '분해'로
  • "54명"은 착시였다
  • 그리고 화면 하나로 증명했다
  • 성숙도를 재는 기준

저장소의 절반은 '바꾸기 위한 장치'다

이 관점으로 저장소를 다시 보면, 만드는 파이프라인 옆에 변경을 감당하는 장치가 그만큼의 부피로 서 있다.

codemod 19개의 구성이 말해주는 것

packages/codemod/src/transforms/에 변환기가 19개 있다. 종류별로 세어 보면 분포가 한쪽으로 쏠린다.

분류개수예
색상 토큰 이동9replace-alpha-color, replace-semantic-stroke-color, replace-tailwind-color
타이포그래피 토큰 이동6replace-tailwind-typography, replace-seed-design-token-typography-classname
vars 일반2replace-seed-design-token-vars
컴포넌트 API2replace-react-icon, replace-custom-seed-design-text-component

19개 중 17개가 토큰 이름 이동이다. 컴포넌트 API 변경은 2개뿐이다.

디자인 시스템에서 실제로 깨지는 건 컴포넌트 API가 아니라 토큰 이름이다. 컴포넌트는 prop을 하나 더 받고 기본값을 주면 대부분 호환이 유지된다. 토큰 이름은 그럴 수가 없다. 수백 개 파일에 문자열로 박혀 있고 타입 시스템이 잡아주지 않는 자리도 많다.

토큰 네이밍은 컴포넌트 API 설계보다 되돌리기 어려운 결정이다. 그리고 되돌리는 방법은 "안 바꾸는 것"이 아니라 "codemod를 같이 내는 것"이다.

deprecations 원장, 그리고 흉터 하나

docs/content/docs/migration/deprecations.mdx는 deprecated 항목을 항목 / 종류 / Deprecated 버전 / 제거 예정 버전 / 대체안 / 비고 표로 관리한다. 그중 한 줄이 눈에 걸린다.

항목Deprecated제거 예정비고
$color.bg.layer-fill1.2.x3.0.02.0.0에서 제거했으나 대안 부재로 2.1.0에서 deprecated 상태로 부활

토큰을 지웠는데 대안이 없어서 되살렸다. 그리고 그 사실을 지우지 않고 문서에 남겼다. 이 한 줄이 어떤 아키텍처 다이어그램보다 정직하고 읽는 쪽에 더 쓸모 있다.

deprecation 정책 자체도 흉터를 안고 진화했다.

  • 기본 정책: 마이너/패치 릴리스에서 deprecated 선언 → 다음 메이저 릴리스에서 제거
  • 2.0.0부터 breaking change(deprecated 항목 제거 포함)는 메이저 릴리스에서만 수행합니다.
  • (레거시) 1.x에서는 마이너 릴리스에서 제거했습니다.

예전엔 마이너에서 깨뜨렸고 그게 문제라서 규칙을 바꿨다. 정책 문서에 옛 규칙을 지우지 않고 "(레거시)"로 남겨둔 것도 같은 태도다.

2.0.0에서 제거한 항목들을 보면 무엇을 정리했는지가 드러난다. Checkbox weight=stronger → bold, Switch size=small → size=16(티셔츠 사이즈에서 절대값으로), StyleProps camelCase → kebab-case, BottomSheet direction 제거(항상 아래에서 올라오므로). 대부분이 "이름을 잘못 지었다"의 정리다.

복붙 배포의 대가를 치르는 도구

packages/cli/src/commands/compat.ts는 프로젝트에 복사해 넣은 registry 스니펫이 현재 설치된 @seed-design/react·@seed-design/css 버전과 맞는지 semver intersects/satisfies로 교차 검증한다.

왜 필요한가. 복붙한 코드는 npm update가 못 고치기 때문이다. shadcn 스타일 배포는 "사용자가 코드를 소유한다"는 장점을 주는 대신 업그레이드 경로를 잃는다. SEED는 그 대가를 알고 진단 도구를 따로 만들었다. 장점만 취하는 배포 모델은 없고 대가를 아는 쪽이 도구를 만든다.

packages/archive/ — 스타일링 기술의 묘지

여기가 이 글에서 가장 인상 깊었던 디렉터리다.

패키지첫 커밋의미
react-stitches2021-09Stitches 어댑터
styled-components-theme2022-08styled-components 어댑터
react-emotion-theme2022-08Emotion 어댑터
react-theming2022-08자체 테마 런타임
design-token2022-08구 토큰 패키지
gatsby-plugin-seed-design2024-10Gatsby 플러그인

CSS-in-JS 라이브러리별로 테마 어댑터를 각각 만들었다가, 전부 버리고 CSS 변수로 갔다.

4년 동안 스타일링 기술은 네 번 바뀌었는데 토큰은 살아남았다.

이게 토큰 계층에 투자해야 하는 진짜 이유다. 컴포넌트 구현 기술은 반드시 바뀐다. 지금 확신을 갖고 고른 CSS 도구도 4년 뒤에는 archive/에 들어가 있을 가능성이 높다. 그러니 의미는 토큰에 저장하고 컴포넌트에는 저장하지 않는다. 컴포넌트에 저장한 의미는 구현 기술과 함께 버려진다.

V2는 왜 무너졌나 — 결함이 맨 아랫단에 박혀 있었다

회고는 V2의 실패 원인을 이렇게 적는다.

당근만의 의미를 담은 토큰과 프레임워크의 토큰이 뒤섞여 체계가 일관되지 않았어요. 쓰이지 않는 토큰이 쌓였고, 무엇보다 색상이 충분한 명도 대비를 보장하지 못하는 한계가 있었어요. 접근성의 한계가 시스템의 가장 아랫단에 박혀 있던 셈이에요.

그래서 V3에서는 색을 fg/bg/stroke로 쪼개고 조합이 대비를 보장하도록 다시 짰다. 터치 영역은 targetSize라는 스펙 값으로 만들었다. 가이드 문서의 권고와 달리 기계가 읽는 값이다.

접근성이 토큰 계층에서 보장되지 않으면, 나중에 시스템 전체를 다시 짓게 된다.

접근성을 컴포넌트 단계의 체크리스트로 다루면 컴포넌트마다 통과 여부가 갈리고 새 컴포넌트가 추가될 때마다 같은 검사를 반복한다. 토큰 조합 단계에서 보장하면 그 아래로는 자동으로 따라온다. V2는 이 순서를 반대로 밟았고 그래서 아랫단을 갈아엎어야 했다.

토큰은 늘리는 게 아니라 줄이는 것

같은 회고에서 타이포 스타일을 38개에서 24개로 줄였다고 밝힌다. 이유는 "용도가 분명한 스타일에만 역할을 부여해, 본래 목적대로 쓰이도록 정리했어요"다.

토큰이 늘어나면 선택지가 늘고 선택지가 늘면 같은 상황에 서로 다른 토큰이 쓰인다. 그 시점부터 토큰은 일관성을 만들기는커녕 흩는 도구가 된다.

철학 반전: '제한'에서 '분해'로

가장 의외였던 문장이다.

기존 라이브러리는 디자인 통일성을 지키기 위해 커스터마이징을 '제한'하는 방향으로 설계돼 있었어요. 그런데 곰곰이 따져보니, 통일성은 디자인 단계에서 풀어야 할 문제이지, 라이브러리가 닫힌 인터페이스로 제약을 거는 건 불필요한 일이더라고요.

이 한 문장이 headless 분리와 Figma Slot, registry 복붙 모델을 동시에 설명한다. 앞 글에서 본 registry의 3단 결합도도 같은 철학의 표현이다. registry-ui는 seed에 의존하고 registry-block은 조합 예제이며 registry-breeze는 의존성이 없는 순수 복붙이다.

닫힌 컴포넌트는 통일성을 지켜주는 대신, 요구사항이 인터페이스를 벗어나는 순간 사용자가 통째로 복제해 나가게 만든다. 그렇게 복제된 컴포넌트는 디자인 시스템의 통제 밖에 있고 다음 토큰 변경 때 조용히 어긋난다. 제약을 걸어 얻은 통일성은 그 지점에서 되돌려진다.

"54명"은 착시였다

앞 글에서 나는 "4년 반, 54명, 39패키지"라고 썼다. 누적 기여자 수는 맞지만 그 숫자가 주는 인상은 틀렸다.

최근 1년 기준 상위 3명이 사람 커밋의 약 91%를 쓴다.

의미가 뒤집힌다. "54명이 붙어야 가능한 일"로 읽었지만 "전담 두세 명이 4년 반 동안 꾸준히 하면 가능한 일"이었다. 나머지 50여 명은 자기 제품을 만들다 필요한 것을 보태고 지나간 사람들이다.

파트타임으로는 안 된다는 나쁜 소식이 있다. 곁다리로 만들면 V2처럼 "고치기 두려운 시스템"이 된다. 그래도 조직 규모의 문제가 아니라 전담 여부의 문제라는 점은 좋은 소식이다. 54명을 모을 수 없어도 한 명을 전담시킬 수 있으면 시작할 수 있다.

SEED가 why-we-hired-a-design-engineer.mdx라는 글을 따로 쓴 이유도 여기 있을 것이다.

그리고 화면 하나로 증명했다

V3 전환은 기술 배포 대신 학습 과정으로 설계됐다. Figma 키트 배포, 전사 소개, 팀별 온보딩, PV 상위 페이지 연내 전환 목표, 어려운 팀은 직접 마이그레이션 지원 순이다.

그리고 프로필 화면 하나에 V3를 적용한 뒤의 지표를 남겼다. 모아보기 +44%, 체류시간 Android +68%, iOS +83%.

디자인 시스템 투자를 정당화한 건 아키텍처 문서가 아니라 지표가 붙은 화면 하나였다. 39패키지짜리 파이프라인을 설명해서 예산을 받는 게 아니라, 한 화면을 제대로 고쳐서 숫자를 보여주고 나머지를 설득하는 순서다.

성숙도를 재는 기준

앞 글의 결론은 "가져올 것은 컴포넌트가 아니라 경계를 긋는 방식"이었다. 이제 한 겹 더 들어간다.

경계를 긋는 이유는 나중에 고치기 위해서다. 디자인 시스템의 성숙도는 컴포넌트 개수가 아니라 "이걸 바꾸면 뭐가 깨지는지 말할 수 있는가"로 잰다. 그 질문에 답할 수 없는 시스템은, 규모와 무관하게 이미 굳은 시스템이다.

당근은 그 질문에 답할 수 없어서 V3를 다시 지었다. 컴포넌트가 부족해서가 아니라 토큰 하나를 바꿀 때 어디까지 번지는지 몰라서였다.

그러면 토큰이 수십 개뿐인 시스템은 어떤가. 다음 글에서 실제로 영향도 추적기를 만들어 돌려본다.

← 이전 편설계 결정 일곱 가지와 정직한 비용다음 편 →작은 팀은 어디에 경계를 그어야 하는가

관련 글

  • #next#react#typescript

    Kineto 저널을 씬 단위 스크롤 화면으로 확장하기

    세 장의 정적 카드로 시작한 Kineto를 씬 단위 저널로 확장하며 스크롤 인덱스, 미디어 변형, 숫자 대비와 반응형 제목 배치를 다듬은 과정을 기록한다.

    2026-09-16·11분
  • #next#react#typescript

    스크롤에 맞춰 5개씩 움직이는 페이지 인덱스 만들기

    스크롤 위치를 페이지 번호로 바꾸는 일반적인 방법과 Kineto의 씬 단위 RailIndex 구현을 정리한다.

    2026-09-15·19분

새 글을 놓치고 싶지 않으시다면 RSS로 구독해 주세요.

RSS 구독 →

cheonbi — 소프트웨어 엔지니어입니다.

← Back to the blog