June 2021
제품 팀의 생산성 향상으로 가설을 빠르게 검증하는 것도 중요했지만 지금 마주하고 있는 사용자에게 가치를 전달하는 것이 더욱더 중요했습니다.
'마이뮤직시트'의 제품 팀은 총 다섯 명으로 한 명의 프로덕트 리드 겸 디자이너인 저와 세 명의 프론트엔드 엔지니어 그리고 두 명의 백엔드 엔지니어로 구성되어 있었습니다. 그 때문에 당장의 사용자 문제를 해결하는 것을 멈추지 않으면서도 한정된 개발 자원으로 디자인 시스템을 구축해야 했습니다. 개발자와 디자이너 간의 커뮤니케이션 시간이 구축에 있어서 제일 큰 비용이라고 판단하였기에 이를 효과적으로 줄일 수 있는 '도구'를 찾고자 하였습니다.
구축 시 컴포넌트별로 스펙을 확정 짓는 단계에서 많은 시간이 소요 되었지만, 이 단계의 시간 비용은 오히려 바람직하다고 생각했습니다. 초기에 컴포넌트의 명확한 책임과 역할을 이야기하며 작업자들 간의 공감대를 형성하는 것이 궁극적으로는 미래의 소통 비용을 절감할 수 있었기 때문입니다.
하지만 컴포넌트 스펙 확정 이후 디자인 과정에서 컴포넌트를 관리하고 전달하는 방식은 미래의 소통 비용에 큰 영향을 미쳤습니다. 이는 디자이너와 개발자가 서로 다른 '언어'를 사용하기 때문이었습니다. 그렇기에 컴포넌트 스펙 확정 짓고, 디자인 도구에서 이를 전달할때 사용할 '공용어'가 필요했습니다.
이러한 필요에 따라 디자인 시스템 구축 및 전달 도구로 '프레이머'를 채택하였습니다. 프레이머에서는 컴포넌트 UI 디자인 단계에서부터 prop과 variant 그리고 adornment를 '코드 베이스'로 정의할 수 있습니다. 또한 Nested Coponents 디자인할 때도 하위 컴포넌트에서 사용할 prop들을 object로 관리할 수 있어 개발자에게 더욱 명확한 스펙 전달이 가능했습니다.
addPropertyControls(MPInput, {
pseudoClass: {
type: ControlType.Enum,
displaySegmentedControl: true,
defaultValue: "normal",
options: ["normal", "hover", "focus"],
},
status: {
type: ControlType.Enum,
displaySegmentedControl: true,
defaultValue: "normal",
options: ["normal", "error", "disabled"],
},
size: {
type: ControlType.Enum,
displaySegmentedControl: true,
defaultValue: "l",
options: ["m", "l"],
},
required: {
type: ControlType.Boolean,
defaultValue: false,
},
customHeight: {
type: ControlType.Boolean,
defaultValue: false,
},
_height: {
type: ControlType.Number,
title: "ㄴ Height",
defaultValue: 40,
hidden(props) {
return props.customHeight === false
},
},
label: {
type: ControlType.String,
placeholder: "Label",
defaultValue: "Label",
},
placeholder: {
type: ControlType.String,
placeholder: "Placeholder",
defaultValue: "내용을 입력해주세요",
},
value: {
type: ControlType.String,
placeholder: "Value",
},
helperText: {
type: ControlType.String,
placeholder: "Helper Text",
},
prefix: {
type: ControlType.String,
placeholder: "prefix",
},
suffix: {
type: ControlType.String,
placeholder: "suffix",
},
...inheritProps("Icon_L", "leftIcon2", mpIconProps, ["iconName"]),
...inheritProps("Icon_R", "rightIcon2", mpIconProps, ["iconName"]),
customBG: {
type: ControlType.Boolean,
defaultValue: false,
},
backgroundColor: {
type: ControlType.Color,
title: "ㄴ Background",
defaultValue: colors.White,
hidden(props) {
return props.customBG === false
},
},
customRadius: {
type: ControlType.Boolean,
defaultValue: false,
},
...fusedNumber({
variableName: "radius",
defaultValue: 5,
type: "corner",
hidden(props) {
return props.customRadius === false
},
}),
shadow: {
type: ControlType.Boolean,
defaultValue: false,
},
shadowLiteral: {
title: "ㄴ Literal",
type: ControlType.String,
defaultValue: "0px 0px 1px rgba(0,0,0,0.2)",
hidden(props) {
return props.shadow === false
},
},
})
결과적으로 위 이미지처럼 디자인 과정에서 합의된 컴포넌트의 Prop과 Variant만 사용하여 플로우를 전달 할 수 있게 되었습니다.
'마이뮤직시트'는 글로벌 서비스로 다섯 개의 번역 정보를 관리하고 있었습니다. 하지만 캡처 화면을 주고받으며 번역되었던 기존 방식은 플로우를 파악하기 어려워 오역을 빈번하게 발생시켰습니다. 또한 슬랙에서 관리 되던 번역 파일(json)은 메세지 특성상 쉽게 휘발되어 많은 관리 비용을 야기시켰습니다.
디자인 시안 상에서 번역자가 플로우를 확인하며 컴포넌트에 번역 정보를 적을 수 있도록 하여 복잡했던 번역 워크플로우를 디자인 툴로 개선하였습니다. 이를 통해 슬랙에서 번역 파일(json)을 주고받는 것이 아닌 디자인 시안에서 번역 파일(json)을 효율적으로 관리하며 의도에 맞는 번역을 할 수 있게 되었습니다.
초기 70%의 구축까지 3.5개월의 시간이 걸렸지만, 그 후 '디자인 시스템'을 만들고자 했던 목적에 맞게 제품팀의 생산성이 향상되면서 빠른 가설 검증할 수 있어 졌습니다.
그뿐만 아니라 제품팀의 주된 대화가 표현적인 UI 가 아닌 사용자 문제를 발견하고 해결하는 대화에 집중할 수 있게 되었습니다. MVP를 만드는 데도 '디자인 시스템'이 '촉매제' 기능을 하며 동일 시간 대비보다 다양한 가설 검증을 할 수 있게 되었습니다.
컴포넌트 목록 (2021년 6월 기준)
· Aside Button
· Badge
· Button
· Callout
· Check
· Dialog
· Divider
· File Upload Item
· Helper Text
· Icon Button
· Icon
· Input
· Menu Cell
· Pagination
· Progress
· Radio
· Slider
· Spacing
· Spinner
· Switch
· Tab Item
· Text
· Textarea
· Toast
· Tooltip