From 37bac8ca8600e1d02d5111e95c4b5f055d473ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A7=84=EC=9A=B1?= Date: Tue, 2 Jun 2026 00:02:22 +0900 Subject: [PATCH] Change greeting from 'Hello' to 'Goodbye' --- week03/jinukeu.md | 561 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 561 insertions(+) create mode 100644 week03/jinukeu.md diff --git a/week03/jinukeu.md b/week03/jinukeu.md new file mode 100644 index 0000000..9d44243 --- /dev/null +++ b/week03/jinukeu.md @@ -0,0 +1,561 @@ +# Scale 05·06 정리 — 토큰과 디자인 시스템, 그리고 그것을 스케일에서 굴리기 + +> Mobile System Design 시리즈 Book 2 (Scale) 의 여섯 번째·일곱 번째 챕터. +> 핵심 질문 — *"UI 라이브러리 다음의 논리적 단계인 '토큰'을 어떻게 정의하고, 디자인과 코드를 어긋나지 않게 동기화하며, 그걸 다중 플랫폼·다중 팀 규모로 어떻게 확장하는가?"* + +> *"토큰은 버전 번호가 있는 디자인 결정이다(Tokens are design decisions with version numbers)."* — Ch.5 에피그래프 +> *"토큰이 플랫폼 전반에 드리프트하면, 여러분의 브랜드가 자기 자신과 논쟁하게 된다(When tokens drift across platforms, your brand is arguing with itself)."* — Ch.6 에피그래프 + +--- + +## Scale-05 · Tokens and the Design System (워크플로·협업 챕터) + +> Ch.2~4 가 UI 라이브러리의 *기초 요소* 를 완성했다면, Ch.5 는 그 위에 *토큰* 이라는 공용어를 얹고 — 디자인과 코드를 *정렬* 시키는 *사람·워크플로* 를 다룬다. 코드보다 *조직* 이 주인공인 챕터다. + +디자인 시스템의 목표는 룩을 통일하는 게 아니다. 팀들이 어떻게 사고하고 함께 일할지를 정렬하는 것이 목표다. + +--- + +### § 5.1 UI 라이브러리 재방문 — 무엇이 빠졌는가 + +UI 라이브러리는 잘 만들어졌지만 디자인 시스템의 한 조각일 뿐이다. 다음으로 채울 *논리적 다음 단계* 가 토큰이다. + +저자는 시리즈를 시작할 때 완벽함을 처음부터 목표로 하지 않았다고 다시 강조한다. 대신 중앙화된 시멘틱 UI 를 도입해 UI 라이브러리를 형태로 만드는 데 집중했다. 이제 그 위에 적절한 디자인 시스템 통합을 얹을 차례인데, 이것이 궁극의 확장 가능 UI 목표다. + +> Figure 5.2 의 메시지: 토큰은 UI 라이브러리 *밖의 별도 엔티티* 로 그려진다. 디자인 시스템의 빈 칸들을 *점점 더 채워가며* 성숙시키는 그림. + +--- + +### § 5.2 UI 요소에서 토큰으로 — 토큰이란 무엇인가 + +#### 문제: 이름이 너무 많다 + +지난 두 챕터에서 마이크로 레벨에서 수많은 UI 요소를 정의했다. 폰트 프리미티브, 시멘틱 컬러, 시멘틱 텍스트 스타일, color primitive, semantic border… 말할 요소가 너무 많다는 게 단점이다. + +저자가 든 디자이너-개발자 대화가 이걸 잘 보여준다. + +> *Developer*: 우리가 정의한 이 주황 컬러들. +> *Designer*: 아 *warning 컬러* 말이죠? +> *Developer*: 아니 *border 컬러*. +> *Designer*: *primary border 컬러*? +> *Developer*: 아니 *실제 컬러* `#FCA103`. +> *Designer*: 아 *eyedropper* 에서 뽑았군요. + +컬러처럼 단순한 것조차 누구와 이야기하느냐에 따라 오해에 빠진다. 여러 용어를 저글링하는 대신, 모든 것을 한 산업 표준 우산 용어인 *"토큰"* 아래로 단순화한다. + +> **Note** — "우리는 px 가 아니라 *pt* 와 *dp* 를 쓴다" 라고 반사적으로 생각했다면 — 축하한다, 당신이 그 *팀 안의 그런 사람* 이다. (책의 농담) + +#### § 5.2.1 토큰의 정의 + +> *토큰은 구조화된 형식으로 저장되는 재사용 가능한 디자인 결정이다.* 컬러·spacing·타이포그래피 같은 핵심 디자인 속성을 *캡슐화* 하여 디자인 시스템 전반에 *일관* 되게 적용 가능하게 한다. + +다른 말로, 토큰은 디자인을 앱·웹사이트 전반에 일관되게 유지하는 *"명명된 값"* 이다. + +| 토큰 이름 | 값 | +|---|---| +| Primary Color | `#0057B8` | +| Alert Color | `#FF5733` | +| Spacing Small | `8px` | +| Spacing Medium | `16px` | + +이름이 붙어 있으니 디자이너가 Primary Color 를 업데이트하면 그 컬러가 쓰이는 *모든 곳에 자동 적용* 된다. + +> **Note** — 이전 챕터에서 정의한 UI 요소와 *이상하게도 비슷* 하다. 거의… *우리가 내내 토큰을 쓰고 있었던 것* 같다. + +한마디로 토큰은 이름과 구조가 부여된 디자인 결정이다. + +--- + +### § 5.3 토큰을 프로젝트에 추가 — 이미 쓰고 있었다 + +희소식은 이미 토큰을 쓰고 있다는 것이다. `Color.primaryBackground`, `Shadow.large` 같은 시멘틱 이름의 UI 요소를 정의한 순간, 디자인 결정을 변수로 캡처한 셈이다. 그렇게 부르지 않았을 뿐 토큰이다. + +#### § 5.3.1 프리미티브 토큰 vs 시멘틱 토큰 + +- *UI 프리미티브 = 프리미티브 토큰*: 의미·컨텍스트 없는 재사용 raw 값(컬러/크기). +- *시멘틱 UI = 시멘틱 토큰*: `Icons.delete` 는 아이콘이 어떻게 생겼는지가 아니라 *삭제 액션* 을 신호한다. 시각이 trashcan→cross 로 바뀌어도 토큰 값만 갈아끼우면 나머지 코드는 손대지 않는다. + +#### § 5.3.2 토큰 ≠ 디자인 시스템 (핵심) + +> *토큰을 쓴다고 디자인 시스템을 쓰는 건 아니다.* 우리는 토큰을 UI 라이브러리에 추가했지만 여전히 주로 *개발자 소유* 다. + +둘을 가르는 건 공유 소유권(shared ownership)이다. 디자이너와 개발자가 *함께* 토큰을 소유한다. 디자이너는 토큰의 의도를 결정하고, 개발자는 구현을 정의하도록 돕는다. 토큰은 그 사이의 공유 언어가 된다. UI 라이브러리는 dev 팀 안에 머물지만, 디자인 시스템은 부서를 가로지르는 노력(디자인·브랜딩·웹/Android/iOS)이다. + +#### § 5.3.3 명명을 함께 + +토큰 명명을 함께 하면 디자이너와 개발자가 *같은 언어* 를 말하게 된다. + +- `Color.accent` vs `Color.brandPrimary`? +- `Spacing.large` 가 너무 모호하면 `Spacing.listItemPadding`? + +> 좋은 시멘틱 토큰은 *외관* 이 아니라 *의도* 를 묘사한다. + +명명 공식에 합의할 수도 있다. 예를 들어 `` → `colorBackgroundHighlighted`, `shadowLargeElevated`. + +#### § 5.3.4 왜 처음부터 토큰으로 시작하지 않았나 + +대부분의 팀은 디자인 시스템으로 시작하지 않기 때문이다. 앱을 시작할 때 최우선은 출시이지 미래 확장 아키텍처가 아니다. 전체 토큰 시스템을 떨어뜨리고 따르라 강요하는 대신, 팀이 함께 빌드하며 점진 학습한다. 토큰은 중복과 불일치에서 자연스럽게 등장한다. + +--- + +### § 5.4~5.5 토큰이 정의되는 곳, 그리고 단일 플랫폼 수동 동기화 + +#### 토큰은 어디에 사는가 + +코드에서 토큰은 UI 라이브러리에 살지만, 디자이너도 디자인 파일에 같은 정의를 가지고 있다. 이상적으로 토큰은 *디자이너·개발자 모두 접근·업데이트할 수 있는 공유·중앙 위치* 에 있다. + +- **디자인 도구**(Figma/Sketch): 디자이너가 시각 스타일 정의, 개발자가 직접 참조. +- **문서**: 합의된 토큰 이름 참조점. Google Doc, README, Wiki, hosted style guide 등 형식은 무관하다. +- **코드**: 디자이너가 마찰 없이 값에 영향 줄 수 있다면 가능. 아니면 다시 개발자 소유로 회귀. + +> Figure 5.3 — 토큰은 *UI 라이브러리 밖* 에 있다. 현재 토큰은 라이브러리 안에 있지만 그건 *구현* 일 뿐이고, *정의는 디자인에서 시작* 한다. *토큰 정의와 토큰 구현 사이의 단절* 이 다음 절들의 주제. + +형식화의 3축은 *소유권*(누가 정의·보호?), *진실의 원천*(디자인 vs 코드 어느 쪽이 주도?), 그리고 동기화 방법이다. + +#### § 5.5 단일 플랫폼 수동 동기화 — 작게 시작 + +주요 도전은 업데이트에 걸쳐 토큰이 정렬되도록 보장하는 것이다. 어긋나면 "디자이너가 컬러를 계속 바꾼다!" 또는 "이 개발자가 또 잘못된 폰트 크기를 쓴다!" 같은 좌절이 생긴다. + +아직은 자동화에 기대지 않는다. 디자이너 1명, 개발자 몇, 단일 앱 정도의 규모에선 수동 접근이 종종 가장 빠른 출발이다. 이어지는 세 워크플로(§5.6~5.9)가 그 수동 방법들이다. + +--- + +### § 5.6 디자인이 진실의 원천 — 개발자가 동기화 + +가장 단순한 방법은 디자이너가 디자인을 업데이트하고 "새 UI 있다" 고 알리면, 개발자가 가서 토큰을 추출해 코드에 반영하는 것이다. 디자인 파일이 진실의 원천이라, 어긋나면 코드가 디자인을 다시 따라야 한다. + +문제는 디자인 파일에 "표준" 이 없다는 것이다. 디자이너마다 정리 방식이 다르고, 버전·레이어 명명이 꼼꼼하지 않을 수 있다. + +> 개발자로서, `design_version_3_final_really_final` 파일 안 `Background Copy (2)` 레이어의 `symbol003` 에서 컬러를 가져와야 한다는 사실이 항상 명확하지 않다. + +결과적으로 무엇을 얻을지가 도박에 가깝다. 개발자는 디자이너의 깔끔함과 규율의 인질이 된다. 끝에 가선 개발자가 적절한 토큰을 해석하고, 변경 후 디자이너에게 특별 빌드로 검증받아야 한다. + +#### § 5.6.1 디자이너가 도울 수 있는 것 + +이상적으론 *컬러 팔레트·타이포그래피의 별도 디자인 파일* 을 둔다. 그래도 변경 비교는 어렵기 때문에, 디자이너가 작은 changelog(변경 전후를 날짜 표시된 시각 영역으로) 를 유지하면 추출 개발자의 삶이 훨씬 쉬워진다. + +--- + +### § 5.7 코드가 진실의 원천 — 디자이너가 PR 로 동기화 + +반대로, 디자이너가 직접 개발자 환경에 들어올 수도 있다. 디자인을 업데이트한 후, 소스 코드에서 토큰 정의를 찾아 값을 바꾸고 PR 로 변환한다. IDE 풀 셋업도 필요 없이 Git 웹 클라이언트로 가능하다. + +```swift +struct Colors { + static let warningColor = UIColor { traits in + traits.userInterfaceStyle == .dark ? Palette.purpleColor : Palette.orangeColor + } +} +struct Palette { + static let orangeColor = UIColor(hex: "#FFA500") + // ... +} +``` + +#### § 5.7.1 코드가 더 중앙화되어 있다 + +디자인 파일에는 *중앙화된 스타일 개관이 항상 있지도 않고, 있어도 자동 동기화되지 않는다*. 한 화면 헤더를 조정해도 스타일 가이드가 저절로 갱신되진 않는다. 반면 개발자는 이미 코드에서 요소를 그루핑하고 나머지가 그 정의를 참조한다. 그래서 코드의 토큰이 기본적으로 더 중앙화된다. 경험상 디자이너가 코드의 토큰을 고치는 게 개발자가 디자인 파일에서 추출하는 것보다 더 작업 가능하다. + +#### § 5.7.2~5.7.3 완벽하지 않아도 된다 + +> *디자이너의 변경이 컴파일될 필요도 없다!* 올바른 토큰만 업데이트하면 OK — 구문 에러는 *개발자나 AI agent* 가 해결한다. + +어려우면 PR 코멘트로 넘긴다. "라이트는 `primaryBlue`, 다크는 `orangeLightest` 로 해줘." 정도면 된다. + +#### § 5.7.4~5.7.5 이점과 단점 + +- **이점**: 매우 단순. 자동 export/import 같은 메커니즘도, "공식 디자인 시스템 문서" 같은 세 번째 엔티티도 도입하지 않는다. 디자이너가 모든 변경을 미리 소통할 필요가 없다. 어떤 토큰을 고칠지 알고 그냥 적용하면 된다. +- **단점**: 디자이너에게 수동 동기화 부담이 쏠린다. 디자이너가 동기화 메커니즘이자 실패 지점이 되는 것이다. 토큰 제거·이름 변경은 *deprecation* 처리가 필요해 손이 더 간다. 가장 큰 단점은 디자이너 피드백 루프가 없다는 점이다. 코드만 고치니 시각 확인도 자동 빌드도 없다. 이상적으론 페어 프로그래밍으로 마무리 후 함께 빌드를 확인하고 머지. + +--- + +### § 5.8 권력 불균형 인식 — 공유 소유권의 전제 + +두 워크플로 모두 작은 팀에선 잘 굴러간다. 그러나 팀이 자라면 마찰이 생긴다. + +- 한 디자이너가 시각 디자인 + 코드 토큰 업데이트 + PR 제출 + 여러 라운드 리뷰까지 떠안으면 부담이 압도적이다. 게다가 대부분의 앱 팀에서 디자이너는 개발자보다 적다. +- 반대로 개발자가 추출하는 셋업도 불균형하다. 개발자가 코드베이스에 들어갈 것의 게이트키퍼가 되고, 디자이너는 자기 변경이 어떻게 해석·이름변경·우선순위화되는지 가시성이 부족하다. + +> *공유 소유권은 양측이 책임을 공유할 때만 작동한다.* 협업으로 시작해도, 디자이너는 의도가 존중받지 못한다 느끼고 개발자는 컨텍스트 없이 해석을 강요받는다 느끼면 좌절로 끝난다. + +이 인식이 다음 절의 *구조화된 핸드오프* 동기다. + +--- + +### § 5.9 핸드오프 시스템 — 각자 자기 세계에 머무르며 공유 + +지금까지는 한쪽이 다른 쪽 환경에 들어가야 했다. 약간의 노력으로 모두 자기 "세계" 에 머무는 방식이 가능하다. + +디자이너가 'Before and After' 문서, 곧 *시각적 changelog* 를 추가로 작성한다. + +> 예: "`tertiaryButtonBackground` hover state was `#4CAF50` and now it's `#388E3C`" / "Medium spacing is now 10 instead of 12" + +개발자는 이 문서로 코드의 토큰을 업데이트한다. 핵심 효과는 두 가지다. + +1. **공정한 권력 균형** — 한 명 vs 한 명이 아니라 *각자 자기 쪽에서 기여*. +2. **사고방식 전환** — *디자이너가 "token exporter", 개발자가 "token importer"* 가 된다. + +여전히 디자인이 진실의 원천이며, 핸드오프 문서는 진실의 원천이 아니라 소통 도구다. + +#### § 5.9.1 토큰 결정은 여전히 공유된다 + +핸드오프를 디자이너가 준비한다고 토큰을 완전 통제하는 건 아니다. 디자이너가 `modalOverlayBackground` 같은 새 토큰을 제안하면, 개발자가 기존 시스템에 어떻게 맞을지 질문하는 게 완벽히 유효하다(이미 `surfaceTint` 가 있을 수도, 플랫폼 default 와 겹칠 수도 있다). + +> *핸드오프 문서는 사양이 아니라 제안* 으로 다뤄야 한다. *좋은 신호* 는 토큰 결정이 *짧은 토론* 을 촉발하는 것 — 긴 오해가 아니라. + +--- + +### § 5.10~5.11 결론과 요약 — 목표는 정렬 + +사람들은 "디자인 시스템" 하면 대규모 툴링·자동화·플러그인을 떠올린다. 그것대로 자리는 있다. 그러나 몇 가지 단순한 워크플로만으로도 멀리 갈 수 있다. + +> *디자인 시스템의 목표는 툴링 셋업이 아니다.* 목표는 *다양한 팀 사이에 공유 정렬과 워크플로를 만드는 것* — 구조화된 방식으로 일하게 돕고, UI 일관성을 가져오며, 팀이 *확장* 에 대비하게 한다. + +**Ch.5 한눈에:** + +| 주제 | 요점 | +|---|---| +| 토큰의 정의 | 이름·구조가 붙은 디자인 결정. 디자인↔개발의 *공유 어휘*. | +| 프리미티브 vs 시멘틱 | raw 값 vs 의도(warning 컬러, caption). | +| 토큰 ≠ 디자인 시스템 | 차이는 *공유 소유권*. 디자이너=의도, 개발자=구현. | +| 명명을 함께 | 명명 공식 표준화. *짧은 토론* 이 나중의 긴 혼란을 막음. | +| 왜 나중에 시작하나 | 출시가 우선. 토큰은 중복·불일치에서 자연 등장. | +| 단일 플랫폼 동기화 | design-source-of-truth / code-source-of-truth / 핸드오프 — 3가지. | +| 권력 불균형 | 디자이너가 적어 부담 쏠림. 양측 가시성·기여 지원이 있어야 작동. | +| 핸드오프 문서 | 시각적 changelog. 각자 환경에 머물며 공정 분담. | + +--- + +## Scale-06 · Tokens at Scale (인프라·자동화 챕터) + +> Ch.5 가 *사람·워크플로* 였다면, Ch.6 은 그 워크플로가 *다중 플랫폼·다중 팀* 에서 무너지는 지점을 짚고 — *토큰 리포지토리·JSON·CI 자동화* 라는 인프라로 넘어간다. 코드/구조가 다시 주인공. + +이 챕터를 관통하는 키워드는 *토큰 드리프트(token drift)* 다. 팀이 자라며 토큰 값이 플랫폼 전반에 점진적으로 어긋나는 현상을 말한다. + +--- + +### § 6.1 다중 플랫폼 수동 동기화 — 핸드오프의 한계 + +Ch.5 의 핸드오프는 단일 플랫폼에선 잘 작동했다(디자인이 진실의 원천, 코드가 따라감). 문제는 플랫폼이 늘 때다. + +#### § 6.1.1 핸드오프 두 배, 통신 두 배 + +디자이너가 iOS·Android·… 여러 팀에 비슷한 핸드오프 문서를 배포해야 한다. 변경이 잦지 않은 작은 팀엔 OK 지만, 곧 문제가 불거진다. + +- 디자이너에게 모든 통신 부담이 쏠리고, +- 어떤 팀 다이내믹에선 디자이너가 개발자를 베이비시팅하게 된다. "토큰 업데이트 했어?", "빌드 좀 줄래?", "새 토큰이 어느 릴리스에 들어가?" 같은 식이다. +- 확장이 안 된다. 큰 조직에선 10,000 파일 중 하나가 되어 Slack·Confluence·Google Docs 어딘가에 묻힌다. + +해법은 단일 진실의 원천을 한 곳에 두는 것, 곧 토큰 리포지토리다. + +--- + +### § 6.2 토큰 리포지토리 도입 — JSON, 양방향, 버전 관리, aliasing + +토큰이 Figma 같은 도구 안에만 살면 시스템이 자랄수록 드리프트·메모리 의존이 심해진다. 중앙 토큰 리포지토리가 필수가 되는 지점이다. + +> 토큰 리포지토리는 *구조화·버전 관리* 되는 곳(보통 *Git repo*)으로, *플랫폼 무관 형식(JSON)* 으로 토큰을 저장한다. 디자인·개발의 *단일 진실의 원천*. + +디자인 파일과 달리 제공하는 것: + +- 버전 이력과 추적성 +- 검증과 명명 강제 +- 자동화 기회(iOS/Android/web 출력 생성) +- 디자인↔엔지니어링 협업 개선 +- 제품/플랫폼 전반 확장의 토대 + +#### § 6.2.1 JSON 이 가장 흔한 선택 + +읽기 쉽고 플랫폼 무관하며, 디자인 도구·플러그인·자동화가 모두 지원한다. + +> **Note** — 작성 시점의 그런 플러그인: *Style Dictionary*, *Tokens Studio*. + +#### § 6.2.2 디자이너는 왜 import 도 하는가 + +직관과 반대로, 디자이너는 토큰을 export 만 하지 않고 import 도 한다. 진실의 원천이 리포에 있다면 디자이너는 Figma 를 그것과 동기화해야 한다. 안 그러면 개발자(또는 토큰 유지보수자)의 업데이트가 디자인 파일에 나타나지 않는다. 결과는 양방향 워크플로다. Figma 와 플랫폼 코드가 같은 토큰을 반영한다. + +#### § 6.2.3 버전 관리와 공유 이력 + +디자인 도구 안의 토큰 변경은 보이지 않는다. commit 이력도 changelog 도 롤백도 없다. 토큰이 Git 에 살면 모든 변경을 추적하고, diff 검토, 릴리스 태그, 제품 작업과의 연결이 가능하다. + +#### § 6.2.4 토큰 JSON 의 생김새 + +```json +{ + "color": { + "background": { "primary": "#007AFF" }, + "text": { "...": "..." } + }, + "spacing": { "small": "8", "medium": "16", "large": "24" }, + "font": { + "header": { "size": "20", "weight": "regular" } + } +} +``` + +이 구조는 크로스플랫폼이라 플랫폼별 구문/타입을 가정하지 않는다. 자동화 도구가 이 공유 JSON 을 Android XML, iOS Swift, 웹 CSS 변수로 변환한다. + +#### § 6.2.5 토큰 aliasing + +토큰이 literal 값이 아니라 다른 토큰을 가리킬 수 있다. + +```json +{ + "color": { + "grey": { "light": { "value": "#cccccc" } }, + "background": { "value": "{color.grey.light}" } + } +} +``` + +`color.background` 가 `color.grey.light` 를 alias 한다. 디자인 결정과 실제 값을 분리하는 것이다. grey 를 바꾸려면 한 곳만 손대면 된다. *테마링* 셋업에도 맞는다. background 를 한 곳에서 override 하면 그걸 참조하는 모든 토큰이 적응한다. (§5.3.1 의 프리미티브↔시멘틱 분리와 같은 패턴의 데이터 버전.) + +--- + +### § 6.3 플랫폼 간 토큰 공유 — 이름은 공유, 값은 분리 + +각 플랫폼이 자기 이름(Android `groupSpacing`, iOS `sectionPadding`)을 만들면 토큰은 로컬에서만 쓸모 있다. 그러면 디자인 팀이 "플랫폼 전반에 그루핑된 블록 사이 spacing 을 조정한다" 라고 말할 수 없다. 각 플랫폼에서 그 개념이 뭐라 불리는지 일일이 추적해야 하기 때문이다. 그래서 명명에 미리 정렬한다. + +#### § 6.3.1 토큰 이름을 값에서 분리 + +> *토큰 이름은 공유 디자인 의도이지, literal 값이 아니다.* + +`Font.header` 는 모든 플랫폼에 "메인 헤더 스타일" 을 신호하되 실제 값은 다를 수 있다. + +| 토큰 | iOS | Android | +|---|---|---| +| `Font.header` | size 20, weight regular | size 18, weight bold | +| `Spacing.small` | 8pt | 10dp | + +이름을 참조함으로써 각 플랫폼은 *네이티브 값* 을 쓰면서도 목적에서는 정렬된다. + +#### § 6.3.2 플랫폼별 override + +단일 `tokens.json` 에 모든 플랫폼 값을 욱여넣으면 지저분해진다. 파일을 쪼갠다. + +``` +tokens/ +├─ base.json # 공유 default +├─ ios.json # iOS 특정 값 +└─ android.json # Android 특정 값 +``` + +```json +// android.json — base 의 16 대신 20 +{ "spacing": { "medium": { "value": "20" } } } +``` + +공유 토큰을 깨끗하고 플랫폼 중립으로 유지하고, 각 팀이 자기 override 를 독립 관리한다. *관심사 분리* 습관이자 미래 자동화의 토대다. + +#### § 6.3.3 플랫폼별 extension + +어떤 토큰은 특정 플랫폼에만 의미 있다. Android 는 `Elevation.low` 로 깊이를 다루고, iOS 는 *그림자* 가 더 친숙하다. 반대로 iOS 의 `Corner.radius.small` 은 Android 에선 *shape* 에 가깝다. 한 세트로 묶으면 네임스페이스를 오염시켜, iOS dev 가 Android 전용 토큰에 placeholder 를 넣거나 그 반대 실수를 부른다. + +```json +// android.json — override + extension +{ + "spacing": { "medium": { "value": "20" } }, + "elevation": { "low": { "value": "2" }, "medium": { "value": "8" } } +} +``` + +> *`elevation` 토큰은 base.json 에 없다 — 괜찮다.* 플랫폼 토큰 파일은 *override 할 뿐 아니라 extend 도* 한다. + +--- + +### § 6.4 문서화 도입 — 의도와 사용법을 명확히 + +토큰이 공유 JSON 에 있으면 다음 도전은 명료성이다. 모두가 토큰을 볼 수 있어도 이해하고 있을까? `spacing.medium` 은 실제로 무엇을 위한 것인가? 언제 `color.surface.low` 를 쓰고 언제 `color.background.primary` 를 쓰는가? + +#### § 6.4.1 문서가 사는 곳 + +초기엔 화려할 필요 없이 가볍게 간다. 가장 중요한 건 찾기 쉬움이다. + +- 토큰 리포 안의 *마크다운 파일*(예: `TOKENS.md`) +- 디자인 시스템에서 링크된 *Notion/Confluence 페이지* +- 공유 *Google Doc* 이나 내부 *위키* + +완벽한 솔루션을 기다리기보다 단순·공유 참조를 갖는 게 낫다. + +#### § 6.4.2 누가 유지보수하나 + +디자이너·개발자 모두 기여한다. 디자이너가 작동·사용법 초안을, 개발자가 디테일·헷갈리는 이름·플랫폼별 동작을 추가한다. 한 번에 다 문서화할 필요는 없다. 질문이나 혼란이 가장 많은 토큰부터 손대면 된다. + +#### § 6.4.3 문서에 무엇을 담나 + +```markdown +## color.background.primary +- Value: #FFFFFF (light), #000000 (dark) +- Purpose: 콘텐츠 영역의 메인 배경 +- Use for: 화면 배경, 카드 배경, 모달 배경 +- Don't use for: 텍스트, 테두리, 버튼 배경 +- Platform notes: iOS 는 navigation bar 에도 사용, + Android 는 surface 컬러를 대신 씀 +``` + +*시각 예시* 가 문서를 훨씬 유용하게 만든다. 추상 swatch 가 아니라 컨텍스트 안의 토큰 스크린샷, 변경 전후 예시가 그렇다. 값이 플랫폼 간 다를 때는 *플랫폼별 노트* 가 결정적이다. + +--- + +### § 6.5~6.6 자동화 — 검증 → 생성 → CI 완전 통합 + +#### 자동화는 통증이 생긴 *다음* 에 + +투자 전 먼저 물어야 한다. 토큰 동기화가 정말 문제인가? 얼마나 자주 업데이트하고, 약간 어긋나 있어도 얼마나 나쁜가? + +자동화가 가치 있는 건 토큰 업데이트가 잦거나(주간 이상), 수동 복사가 정기적으로 실수·지연을 내거나, 다중 플랫폼이 밀접한 동기화를 요구하거나, 조정이 부담일 때다. + +> *실용 조언*: 동기화가 *통증 지점* 이 된 *후* 자동화에 투자하라. 아니면 토큰을 수동 업데이트하는 것보다 자동화 유지에 *더 많은 시간* 이 든다. + +#### § 6.5.1~6.5.2 첫 단계 — 검증(validation) + +빌드 스크립트가 중복 이름, 잘못된 타입, 잘못된 값을 검사한다. 로컬(PR 전) 또는 CI(PR 후)에서 돌린다. 검사 항목은 파일 간 중복 이름, 잘못된 hex, 누락된 필드(`value`), 일관성 없는 명명(camelCase vs kebab-case 혼합), 잘못된 단위 등이다. (Ch.4 의 린팅과 같은 CI 패턴.) 초기 승리는 토큰 검증에서 나온다. + +#### § 6.5.3 플랫폼별 파일 생성(generation) + +플랫폼 무관 JSON 을 플랫폼별 출력으로 변환한다. + +```json +{ "color": { "background": { "primary": "#007AFF" } } } +``` + +```swift +// iOS +struct Colors { static let backgroundPrimary = UIColor(hex: "#007AFF") } +``` + +```xml + +#007AFF +``` + +#### § 6.5.4~6.5.5 갱신된 워크플로 + 아직은 수동 분배 + +이 가벼운 자동화는 검증으로 에러를 줄이고, 생성 파일이 수동 변환을 제거하며, 모든 플랫폼이 같은 값을 보도록 보장한다. 단, 아직 분배는 수동이다. 개발자가 생성 파일을 각 코드베이스에 복사한다. 이건 제한이라기보다 기능에 가깝다. 개발자가 토큰 적용 시점을 통제하기 때문이다. + +워크플로: (1) 디자이너가 토큰 PR (2) 검증 자동 실행 (3) 머지 후 개발자가 생성 스크립트 실행 (4) 생성 파일을 플랫폼 코드베이스에 복사 (5) 플랫폼 팀이 출시 전 검토·테스트. + +#### § 6.6 완전 통합 자동화 (엔터프라이즈) + +시스템이 토큰 파일 생성에서 멈추지 않고 다운스트림 코드베이스에 자동 푸시한다. 두 방식이 있다. + +**(1) PR 자동 생성** — 중앙 리포 업데이트 시 CI 가 플랫폼별 파일 생성 → 각 타깃 리포 클론 → 새 브랜치 → *서술적 제목·changelog* 로 PR 생성 → 팀 알림. + +```markdown +# Token Update: v2.4.0 +Changes: +- color.background.secondary: #F2F2F7 → #F5F5F5 +- Added spacing.xs (4px) +- Removed deprecated color.legacy.blue +Generated Files: Colors.swift, colors.xml, tokens.css +Review Notes: Settings 화면 배경 변경 테스트, + xs spacing 이 좁은 레이아웃을 깨지 않는지 확인 +``` + +**(2) 패키지로 배포** — CI 가 *semantic versioning* 으로 모듈 패키지 릴리스. *단일 플랫폼의 다중 앱* 이 같은 디자인 시스템을 공유할 때 잘 맞는다. + +**(3) 문서도 파이프라인에** — CI 가 토큰 목록·참조를 문서에서도 갱신해 *최신 토큰 버전과 동기화*. 같은 source JSON 에서 생성되니 실제 값과 *완벽 동기화*. + +**(4) 완전 워크플로**: 디자이너가 중앙 리포 업데이트 → PR 에 검증 자동 → 머지 시 CI 가 *파일 생성·문서 갱신·다운스트림 PR/패키지* → 플랫폼 팀 검토 → 승인 후 프로덕션. + +> *트레이드오프는 복잡성.* 완전 통합은 *선투자·유지보수* 가 크지만, 다중 플랫폼/제품을 관리하는 팀에겐 *빨리 본전* 을 찾는다. + +--- + +### § 6.7 웹과 모바일이 토큰을 공유해야 하는가 + +이 챕터는 모바일끼리의 동기화에 집중했다. 비슷한 내비게이션, 터치, 화면 제약이라 공유 이점이 크기 때문이다. 웹은 다르다. + +- **인터랙션/레이아웃**: 모바일은 nav/tab bar·swipe, 예측 가능한 폰/태블릿. 웹은 menus·sidebars·mouse, 좁은 모바일 브라우저~ultra-wide 데스크탑. +- **타이포그래피**: 모바일은 arm's-length 의 큰 터치 친화 텍스트(보통 4~8 크기). 웹은 desk-distance 의 작은 텍스트로, *복잡한 위계* 가 필요하다. +- **Spacing**: 모바일은 수직 스크롤용 *일관 그리드*. 웹은 *반응형 브레이크포인트* 에 적응하는 유연한 시스템. + +> *웹과 모바일을 강제로 같은 토큰 시스템에 넣으면 해결보다 더 많은 복잡성.* 겹침이 적을 때(예: 컬러만 공유)는 *분리된 토큰 세트* 가 낫다. + +단, 같은 세트가 아니어도 토큰 리포지토리는 공유할 수 있다. 검증·스크립트는 공유하되 웹·모바일이 *자기 JSON 파일* 을 가지면 된다. + +--- + +### § 6.8~6.9 결론과 요약 — 어느 단계에서든 멈출 수 있는 여정 + +전체 궤적은 이렇게 흐른다. 수동 핸드오프로 시작해 플랫폼이 늘며 토큰 드리프트를 겪고, 중앙 토큰 리포지토리와 JSON 형식화·양방향 동기화를 거쳐, 가벼운 문서와 검증을 지나 결국 CI 완전 자동화에 이른다. + +> *깊이 다루지 않은 한 주제 — 거버넌스(governance)*: 토큰 변경을 *언제* 결정하고, 값 충돌을 해결하며, 성숙기의 *승인 프로세스* 를 두는 일. 이런 조직 도전은 흔히 기술 도전보다 중요하지만 *컨텍스트 의존적* — 스타트업과 대기업이 다르다. + +> 이 접근의 *아름다움은 어느 단계에서든 멈출 수 있다* 는 것. 토큰 + 수동 동기화만 원하면 OK, 자동화에 투자하고 싶으면 OK. *반복적* 으로 성숙·정제한다. + +**Ch.6 한눈에:** + +| 주제 | 요점 | +|---|---| +| 다중 플랫폼의 취약성 | 수동 동기화는 *토큰 드리프트* 야기. 통신 비용이 확장 안 됨. | +| 중앙 토큰 리포 | 공유 *진실의 원천*. 버전 관리·이력·일관성. JSON 교환 형식. | +| 디자이너 import/export | 디자이너도 *import* 한다 — Figma 를 리포와 동기화. | +| 명명·override | 이름은 *공유*(시멘틱), 값은 플랫폼별 *override/extension*. | +| 가벼운 문서 | 분리된 문서가 의도·사용 명확화. 완벽·자동화 불필요. | +| 자동화 진화 | 검증 → 파일 생성 → CI 가 PR 생성/패키지 배포. *통증 후* 투자. | + +--- + +## Android / Jetpack Compose 매핑 + +> 토큰 챕터는 대부분 *워크플로·인프라* 라 플랫폼 독립적이다. 코드 산출물이 닿는 지점만 Compose 등가로 옮긴다. + +#### 토큰의 Compose 표현 — `MaterialTheme` 슬롯 + 커스텀 CompositionLocal + +시멘틱 토큰은 Material 3 의 `ColorScheme`/`Typography`/`Shapes` 슬롯에 직접 매핑되고, 그 밖(spacing·elevation 등)은 커스텀 `CompositionLocal` 로 노출한다. SwiftUI 의 `Color.primaryBackground` 정적 접근이 Compose 에선 테마 주입으로 바뀐다. + +```kotlin +// 프리미티브 토큰 (palette) +object Palette { val blue500 = Color(0xFF007AFF) } + +// 시멘틱 토큰 — alias 패턴 (§6.2.5 와 동일) +@Immutable +data class AppColors(val backgroundPrimary: Color) + +val LocalAppColors = staticCompositionLocalOf { + AppColors(backgroundPrimary = Palette.blue500) +} + +// 사용처는 의도만 참조 +val bg = LocalAppColors.current.backgroundPrimary +``` + +#### 다크 모드 alias — `isSystemInDarkTheme()` + +§5.7.2 의 라이트/다크 분기(Swift 의 `UITraitCollection`)는 Compose 에선 테마 진입점에서 한 번 결정한다. + +```kotlin +val colors = if (isSystemInDarkTheme()) DarkAppColors else LightAppColors +CompositionLocalProvider(LocalAppColors provides colors) { App() } +``` + +#### JSON → 플랫폼 생성물 (§6.5.3) + +같은 `tokens.json` 에서 생성되는 Android 산출물은 두 갈래다. + +- **리소스 XML**(`colors.xml`, `dimens.xml`) — 뷰 시스템·접근성 도구와 호환. 책의 `` 예시가 그대로. +- **Kotlin object** — Compose 친화. `object Tokens { val backgroundPrimary = Color(0xFF007AFF) }`. + +Style Dictionary 는 Android(`compose`, `android/resources`) 와 iOS(`ios-swift`) 출력을 같은 소스에서 동시 생성한다. §6.6 의 "한 JSON, 다중 플랫폼 PR" 이 실제로 도는 방식이다. + +#### override/extension 의 자연스러운 대응 + +`base.json` + `android.json` 분리(§6.3.2~3)는 Android 의 리소스 *qualifier*(`values/`, `values-night/`, `values-sw600dp/`)와 개념이 겹친다. elevation extension(§6.3.3)은 Android 가 *1급 개념*(`Surface(tonalElevation = …)`, `Modifier.shadow`)이라, iOS 그림자보다 토큰화가 더 직관적이다. + +#### CI 패턴 (§6.5~6.6) + +검증·생성·PR 자동화는 플랫폼 무관이다. Android 쪽에선 생성된 토큰 모듈을 Gradle *버전 카탈로그* 나 별도 `:core:designsystem` 모듈로 배포(§6.6.2 패키지 방식)하는 게 자연스럽다. 이건 Scale 후반 *모듈화* 챕터(Ch.7~)와 곧장 이어진다. + +--- + +## 정리 — *Ch.5 는 정렬, Ch.6 은 인프라* + +두 챕터를 합쳐 보면 디자인 시스템이 "제품" 이라기보다 "여정" 에 가깝다는 책의 일관된 주장이 또렷해진다. + +- **Ch.5** 는 토큰을 *공유 어휘* 로 세우고, 디자인↔개발을 정렬시키는 **사람·워크플로** 를 다룬다. 가장 큰 통찰은 토큰을 쓴다고 디자인 시스템이 되는 건 아니라는 것, 둘을 가르는 건 공유 소유권이라는 것이다. 그리고 핸드오프 문서로 각자 자기 세계에 머물며 공정하게 기여하는 균형점을 찾는다. +- **Ch.6** 은 그 워크플로가 다중 플랫폼에서 *토큰 드리프트* 로 깨지는 지점을 짚고, **중앙 토큰 리포지토리 + JSON + CI** 라는 인프라로 답한다. 그러나 끝까지 "통증이 생긴 다음에 자동화하라" 는 실용주의를 놓지 않는다. + +> *"디자인 시스템의 목표는 툴링 셋업이 아니라, 다양한 팀 사이에 공유 정렬과 워크플로를 만드는 것이다."* + +이 한 문장이 두 챕터를 관통한다. 토큰은 수단이고, 목표는 디자이너와 개발자가 같은 언어로 같은 결정을 공유하는 것이다. 그래서 책은 화려한 자동화보다 어느 단계에서든 멈출 수 있는 점진적 진화를 권한다. UI 를 확장하는 건전한 방법을 갖췄으니, 다음은 코드베이스의 나머지를 *모듈러 아키텍처* 로 확장할 차례다(Ch.7~).