문제
디자인 파일과 구현 화면이 갈렸습니다. 파일에서 색을 바꾸면 화면은 그대로였고, 화면에서 급하게 고친 값은 파일로 돌아오지 않았습니다. 둘 다 정본을 자처했습니다. 정본은 고치는 자리가 하나뿐인 기준을 말합니다. 그 기준이 두 벌이면 누가 물어도 답이 두 개고, 결국 매번 사람이 두 벌을 눈으로 대조하게 됩니다.
기준 자리를 코드로 옮겼습니다
디자인 도구를 버린 것이 아니라 기준 자리에서 내렸습니다. 탐색과 시안은 도구에서 계속하되, "무엇이 맞는 화면인가"의 답은 실행되는 코드 한 곳에만 두었습니다. 근거는 단순합니다. 사람이 대조로 유지하는 동기화는 바쁠 때 가장 먼저 끊기고, 끊긴 것이 티가 나지 않습니다.
시스템은 두 층으로 갈랐습니다. 원시 토큰은 값을 갖고, 시맨틱 토큰은 의미를 갖습니다. 화면은 시맨틱 이름만 쓰고 원시값을 직접 참조하지 않습니다. 이 경계가 없으면 "이 파랑은 브랜드색인가 정보색인가"를 매번 사람이 판단하게 되고, 판단은 사람마다 갈립니다.
구조로 막은 실패 모드
토큰을 정해 두는 것만으로는 부족했습니다. 실제로 무너진 자리는 규칙이 아니라 규칙이 조용히 통과되는 자리였습니다.
- 다크 테마에 대응 토큰이 빠져도 빌드는 성공했습니다. 밝은 테마에만 있는 토큰을 기계가 잡도록 완결성 검사를 붙였습니다
- 스캔 글롭을 소비자가 손으로 적게 두면 0건을 매칭해도 빌드가 통과합니다. 빌드는 초록불인데 화면만 깨집니다. 글롭을 패키지 안쪽으로 옮겼습니다
- 프리셋 하나를 가져오면 폰트까지 따라오게 했습니다. "폰트 import 를 빼먹는" 실패를 주의로 막지 않고 구조로 없앴습니다
- 정의되지 않은 색 단계를 쓰면 경고 없이 투명하게 렌더됐습니다. 시맨틱 이름만 허용해 애초에 쓸 수 없게 했습니다
같은 조각이 제품마다 다시 그려졌습니다
제품이 넷으로 늘자 같은 것이 네 번 만들어졌습니다. 배지, 드롭다운, 카테고리 아이콘, 지표 카드처럼 어느 제품에나 있는 조각들입니다. 각각은 그럴듯하게 동작했고, 그래서 아무도 문제로 신고하지 않았습니다. 문제는 고칠 때 드러났습니다. 배지 하나의 여백을 바꾸려면 네 곳을 찾아야 했고, 네 곳이 조금씩 달라 같은 편집이 아니었습니다. 한 곳을 빠뜨리면 그 제품만 옛 모양으로 남는데, 그 사실은 나란히 놓고 보기 전에는 보이지 않습니다.
중복을 세는 일부터 막혔습니다. "화면이 몇 개인가"에 기획은 기획서 목차로, 개발은 라우트로, 디자인은 시안 수로 답했습니다. 셋 다 틀리지 않았고 세는 단위만 달랐습니다. 그래서 세는 단위를 URL 로 고정했습니다. 화면은 사람의 개념이라 합의가 필요하지만 URL 은 있거나 없습니다. 목록은 사람이 적지 않고 코드에서 뽑았고, 그 위에 제품별 카드를 깔아 상태와 담당 제품 영역을 붙인 판을 세웠습니다. 기획과 개발과 디자인이 같은 판을 보게 하려는 것이었습니다. 실측하고 나서야 미리보기 사본과 패키지 사본이 갈려 있다는 것과, 같은 제품의 구세대와 신세대가 공존한다는 것이 드러났습니다. 그 전에 한 번은 화면 목록으로 검수하다가 배포본에만 있는 페이지 다섯 장을 통째로 빠뜨렸습니다. 목록에 없으니 검수 대상이 아니었고, 검수는 통과했습니다.
승격을 합의가 아니라 상태로 만들었습니다
공용으로 올릴지 말지를 그때그때 합의로 정하지 않기로 했습니다. 합의는 바쁠 때 건너뛰어지고, 건너뛴 것이 기록에 남지 않습니다.
대신 화면과 조각마다 핸드오프 상태를 붙였습니다. 초안, 검토, 확정, 폐기입니다. 확정으로 바뀌는 순간이 곧 승격 대상이 되는 순간입니다. 사람이 "이제 공용으로 올릴까요" 라고 묻지 않아도 상태가 그 말을 대신합니다.
구조는 공용 코어 한 벌과 제품별 패키지 네 벌로 갈랐습니다. 코어는 어느 제품에도 기대지 않고, 제품 패키지는 코어를 쓰되 서로를 참조하지 않습니다. 이 방향을 정해 두지 않으면 공용이 특정 제품의 사정을 안고 자라서, 나중에 다른 제품이 그것을 쓰지 못합니다.
승격을 막던 것들
절차를 세운 뒤에도 승격은 자주 실패했습니다. 실패한 자리는 규칙이 아니라 규칙과 실제가 어긋난 자리였습니다. 화면이 셸과 공유 조각에 기대고 있으면 꺼내는 순간 깨졌고, 같은 라우트가 목록에 두 번 올라가 서로 다른 상태를 들고 있었으며, 이미 배포되어 있는데 목록에는 검토로 남은 화면이 백 건 넘게 있었습니다.
전부 사람이 눈으로 잡던 것들이고, 눈으로 잡는 것은 한 번은 되고 두 번째부터 안 됩니다. 그래서 승격 여부를 목록이 아니라 실제 패키지 구성에서 읽어 자동으로 표시하게 했습니다. 목록과 실제가 어긋나면 검사가 막고, 확정뿐 아니라 검토로 올리는 편집까지 막도록 조였습니다.
결과
색 하나를 바꾸는 일이 파일 수십 개를 여는 일에서 토큰 한 줄을 고치는 일이 되었습니다. 공용 조각을 고치는 일도 한 곳을 고치는 일이 되었습니다. 그리고 "이 화면은 공용인가" 라는 질문이 사람에게 오지 않고 화면에 표시됩니다. 승격이 개인의 부지런함이 아니라 절차의 결과가 되었습니다.
남은 생각
기준을 하나로 만든 대가는 있습니다. 디자인 논의가 코드 리뷰 동선으로 들어오니 비개발 직군의 진입 비용이 올라갑니다. 화면을 사람이 훑을 수 있는 판을 따로 세운 것이 그 대가를 덜기 위한 것이었습니다. 다만 판을 세워도 그 판을 읽는 습관까지 만들어지지는 않습니다. 거기까지는 이 설계가 하지 못했습니다.
