Alive

샵라이브 입사 첫날, 2주 동안 제품을 사용하며 디자이너의 시선으로 샵라이브를 리뷰하라는 과제가 주어졌습니다. 익숙한 일이라 생각했고, 늘상 하던 것처럼 사용자의 관점에서 불편한 지점을 기록하면 되겠다 생각했는데요, 실제로 제품을 사용해보니 제 생각보다 좀 더 복합적인 문제를 안고 있었습니다.

컴포넌트의 파편화

샵라이브에는 사용자가 클릭하여 특정 동작을 실행시키는 버튼 <Button> 컴포넌트가 있습니다.

Button

버튼 컴포넌트는 서로 다른 디자이너들의 요구사항에 따라 서로 다른 엔지니어들이 구현하여 파편화가 되었습니다. 겉으론 비슷해 보여도, 요구사항이나 구현 방식에 따라 서로 다른 맥락을 갖게 됩니다.

방송 추가
<Button>
삭제하기
<DialogButton>
다운로드
<AntdButton>
피드 보기
<CustomButton>

그러나 같은 역할을 하는 컴포넌트가 파편화되면 조직 개편이나 신규 입사로 인해 처음 제품을 접하는 구성원은 혼란을 겪게 됩니다. 먼저 버튼이 여러 개로 분산된 원인과 맥락을 파악하고, 디자이너는 어떤 형태의 버튼을 활용할지, 엔지니어는 디자이너가 설계한 버튼을 어떤 방식으로 구현할지, 작업자의 고민 시간이 길어지고 이로 인한 리소스가 소모됩니다.

D
방송 다시보기에 구간 설정 미리보기를 실행하는 트리거가 있는데요, 어떤 버튼을 써야 할까요?
미리보기처럼 주요 기능이 아니라면 흰색 배경 버튼을 사용하는 게 좋을 것 같아요!
J
D
비슷한 피드 보기 기능은 투명 버튼이더라구요..
😱
J

행동 패턴의 파편화

샵라이브 어드민의 필터에는 다양한 행동 패턴이 존재합니다. 필터를 실행하면 동작이 저마다 조금씩 다른데요, 새로운 창이 뜨기도 하고, 테이블 위에서 팝오버가 뜨기도 하고, 다중 선택을 할 수도 있고, 단일 선택만 가능한 경우도 있습니다.

Filter 1
Filter 2
Filter 3

테이블에서 여러 항목을 선택하는 경우, 체크박스를 눌러야 선택되기도 하고, 각 Row을 눌러 선택할 수도 있습니다. Row을 눌러서 선택하는 패턴에 익숙해진 사용자가 선택을 위해 Row를 눌렀더니 해당 데이터의 상세 페이지로 이동한다면, 예상치 못한 결과로 당황스러울 것 같습니다.

Product Title
체크박스를 눌러야 선택되는 테이블

사용자가 소프트웨어에서 가장 많이 실행하는 행동은 이런 데이터 선택, CRUD, 필터, 정렬같은 행동인데요. 이런 기본적인 행동들에 일관성이 없는 경우 각 서비스마다 다른 경험을 하게 되고, 사용자의 학습 비용이 증가하며 제품에 대한 이미지 저하로 이어지게 됩니다.

서비스의 파편화

샵라이브 어드민에서 업로드, 다운로드, 전처리 등 다양한 비동기 작업의 진행 상황을 표시하는 프로그레스 팝업은 라이브, 숏폼, AI 서비스에서 각각 구현되어 사용자의 화면에 동시 최대 5개까지 나타날 수 있습니다.

Progress popups

이 경우, 동일한 기능에 대한 QA 및 유지보수 리소스가 배로 소모되고 비효율과 낭비가 발생합니다.

이렇듯 사소한 파편화가 방치되면 사용자의 행동 패턴 뿐만 아니라 서비스 전반적으로 깨진 유리창이 퍼지게 되고, 심미적 문제나 사용성의 문제를 넘어서 신규 팀원의 온보딩 속도가 저하되고 과거 맥락을 설명하는 커뮤니케이션 비용이 증가하여 결국 조직 전반의 문제를 유발할 수 있습니다.

제품의 언어 만들기

이런 문제를 해결하기 위해 디자인 시스템이 존재하는데요. 잘 만든 디자인 시스템은 제품의 일관성을 확보하고 완성도를 높이면서, 작업 효율과 생산성을 높이고, 작업자들이 사소한 인터페이스 개선보다 중요한 비즈니스 성장에 집중하도록 만들 수 있습니다.

처음엔 단순한 과제로 생각했지만, 샵라이브에는 일관성 있는 제품의 언어가 필요하다 생각했습니다. 팀 전체의 공감을 얻기 위한 자료를 만들어 발표를 진행한 뒤 팀의 공감대를 형성했고, Alive라는 디자인 시스템의 매니저로서 프론트엔트 엔지니어 2명과 함께 Alive 팀을 구성했습니다.

Alive Deck

샵라이브 어드민에서 테이블을 제외한 컴포넌트가 Alive만으로 구성되도록 한다는 목표를 가지고, 2주 단위의 스프린트를 계획하여 매 스프린트 시작마다 목표를 설정하고 마지막 금요일에 회고로 마무리하기로 했습니다.

엔지니어 두 분은 디자인 시스템을 위한 환경 구성을 진행하고, 저는 파운데이션 토큰과 단독 컴포넌트를 설계하는 작업으로 첫 번째 스프린트를 시작했습니다.

Alive의 원칙

Alive는 두 가지 원칙을 갖고 있습니다.

사용자를 위한 일관성

단순히 일관적인 사용자 경험뿐만 아니라 더 많은 사용자를 위한 접근성, 브랜드 이미지를 위한 심미적 완성도를 포함합니다. 그러나 동일한 컴포넌트가 유려함을 위해 서로 다른 시각적 형태를 갖거나, 동일한 기능이 다른 행동 패턴을 만들어 사용자에게 혼란을 주는 설계는 지양합니다.

작업자를 위한 효율성

유지보수를 위한 효율성뿐만 아니라 샵라이브 온보딩을 용이하게 하는 가이드라인, 커뮤니케이션을 최소화하는 언어로서의 기능, 단일 진실 공급원(SSoT)으로서의 기능을 포함합니다. 코드나 가이드로 규정되지 않고 사람의 기억과 설명에 의존해야 하는 복잡한 규칙은 지양해야 합니다.

파운데이션 토큰

파운데이션 토큰은 브랜드 무드와 시각적 접근성을 고려한 아이콘, 서체, 색상, 둥글기, 그림자, 여백 등의 스타일을 의미합니다. 그동안 hex()와 같은 원시적인 값을 그대로 사용하던 샵라이브 어드민에 스타일 토큰을 정의하여 제품 전반의 시각적 일관성을 확보했습니다.

이전에는 디자이너마다 미묘하게 다른 색상 값이나 여백을 사용했지만, color-neutral-500, shadow-xs 같이 정의된 토큰을 사용하여 커뮤니케이션 비용을 줄이고 구현 속도를 높였습니다.

Foundation Color token

또한 샵라이브의 신규 서비스 브랜딩에 맞추어 제품 내에 gradient를 사용하는 빈도가 높아졌는데요, 흐릿한 회색빛 없이 선명한 gradient를 위해 기존 rgb() 색공간에서 oklch()로 전환하여 디자이너가 의도한 색상을 보다 정확하게 표현할 수 있는 색상 위계를 구성하였습니다.

rgb()

oklch()

oklch() 색공간의 특성상 Lightness를 조절한 결과값이 모든 색상에서 균일하게 적용되어 접근성 측면에서도 전보다 더 개선된 팔레트를 만들 수 있었습니다.

아이콘 활용 프로세스

샵라이브 어드민에서 엔지니어가 아이콘을 활용하려면, 네 단계의 준비 과정이 필요합니다.

Figma 디자인을 확인한다.
디자인에서 신규 아이콘을 구분해 저장한다.
저장한 아이콘 파일을 업로드한다.
신규 아이콘 컴포넌트를 생성한다.

그리고 각 사용처에서 필요한 아이콘을 다음과 같이 작성하여 호출하고 있었습니다.

import IconHome from '@/assets/icons/home.svg'import IconLive from '@/assets/icons/live.svg'import IconAI from '@/assets/icons/ai.svg'import IconLibrary from '@/assets/icons/library.svg'import IconSettings from '@/assets/icons/settings.svg'import IconUser from '@/assets/icons/user.svg'import IconLogout from '@/assets/icons/logout.svg'...

위처럼, 샵라이브 어드민의 내비게이션은 아이콘 호출을 위해 총 25줄의 코드를 작성해야 했는데요. 이제 코드 한 줄만으로 서비스의 모든 아이콘을 호출할 수 있습니다.

import { Icon } from '@shoplive/alive'
Navigation icons

새로운 아이콘을 추가할 경우, 엔지니어가 새롭게 추가된 아이콘을 일일이 확인하지 않아도 Figma 플러그인을 통해 디자이너가 클릭 한 번으로 PR을 올릴 수 있습니다.

컴포넌트의 역할과 책임을 분리하기

컴포넌트는 제품의 인터페이스를 이루는 구성 요소를 말합니다. 컴포넌트는 각자의 역할을 가지고 독립적으로 동작하며 제 기능을 수행해야 합니다.

샵라이브 서비스 중 AI Clip에는 영상의 자막 구간에 따라 영상 길이를 조절해주는 기능이 있습니다. 자막에 해당하는 구간을 앞뒤로 추가하기 위한 트리거로서 버튼이 필요하고, hover 상태일 때 표시하는 툴팁을 통해 자막 내용을 인지할 수 있어야 합니다.

AI Clip Buttons

기존에는 이 요구사항을 툴팁버튼<TooltipButton>이라는 커스텀 컴포넌트를 만들어 사용하고 있었습니다. 이 툴팁버튼은 <Tooltip><Button>이라는 컴포넌트의 역할과 책임이 섞이고 AI Clip이라는 도메인 맥락까지 포함되어 다른 환경에서 재사용이 어려운 상황이었습니다.

  <TooltipButton    key={startHoverBlocker ? Date.now() : undefined}    tooltipProps={{      title: addingStartWordText,      placement: determineTooltipPlacement(addingStartWordText),      trigger: 'hover',      showArrow: false,      align: {        offset: [0, 4],      },      isTooltipCentered: true,      open: isStartWordButtonDisabled ? false : undefined,    }}    buttonProps={{      leftIcon: 'addCircleLine',      ...

도메인 맥락과 요구사항의 조합으로 인해 파편화가 생긴 컴포넌트를 기능과 목적에 따라 구조화하고 툴팁과 버튼이 기능해야 하는 서로의 역할과 책임을 분리하여, 컴포넌트 구현을 위한 구문도 단축하고 샵라이브 어드민 어디서나 <Tooltip><Button>을 재사용할 수 있게 되었습니다.

AI Clip Buttons
<Tooltip   size="small" text={addingWord?.text ?? ''}   direction="s"   disabled={hasNoAddingWord}>  <Button style={style} variant="secondary" size="medium" leading="outline_plus" disabled={hasNoAddingWord} onClick={addWord}>    {t('page.ai_clip.add.words_start')}  </Button></Tooltip>  

이처럼 각 컴포넌트의 역할을 명확하게 인지할 수 있도록, 샵라이브의 모든 구성원들이 볼 수 있는 가이드라인을 만들어가고 있습니다.

Alive guidelines

일관적인 행동 패턴 설계하기

샵라이브 어드민에는 방송 목록, 숏폼 목록, 상품 목록, 라이브러리 목록 등 데이터베이스의 목록을 조회하는 테이블이 많이 존재합니다.

사용자는 원하는 데이터에 보다 빨리 접근할 수 있도록 필터링을 활용할 수 있는데요, 각 테이블마다 동작이 전부 다르게 설계되어 사용자는 각 테이블마다 다른 필터링을 경험해야 했습니다.

Filterings

필터링 경험이 모든 테이블에서 동일하게 동작하도록 필터링하는 각 정보의 속성에 따라 UX를 통일하여 사용자 경험의 일관성과 유지보수의 효율성을 확보하였습니다.

Filterings
Filterings

화면에 표시할 수 있는 데이터가 없는 상황에서도 각 플로우마다 모두 다른 형태를 갖고 있었습니다.

컴포넌트 형태를 통일하여 사용자가 시각적 정보를 통해 현재 상황을 빠르게 인지할 수 있도록 돕고, 다음 행동이 제한된 상황에서 사용자의 행동을 유도하는 장치를 간편하게 제공할 수 있도록 Blankslate 컴포넌트와 하위 action 속성을 제공하여 행동을 유도합니다.

Blankslate
<Blankslate  leading={ <Icon/> }  heading="Heading"  description="Description"  action={{ children: 'Primary Action' }}  secondaryAction={{ children: 'Secondary Action' }}/>

이를 통해 단순히 데이터가 없습니다라는 메시지만 보여주는 것이 아니라, 사용자가 다음에 무슨 행동을 해야하는지 명확하게 안내할 수 있게 되었습니다.

성과 측정

Alive로 가장 먼저 체감한 변화는 팀의 작업 속도와 효율입니다. 컴포넌트와 행동 패턴이 정리되면서, 동일한 문제를 반복해서 고민하거나 설명해야 하는 상황이 눈에 띄게 줄어들었습니다. Alive를 활용한 프로젝트와 도입 전 프로젝트의 Jira 태스크를 비교하여 작업에 대한 정량적 성과를 측정했는데요.

UI 작업 스토리포인트

디자인 QA 태스크 수

반복적으로 사용되는 인터페이스를 Alive로 대체하면서 신규 기능 개발 시 UI 작업에 소요되는 시간이 평균 24% 감소했습니다. 작업자가 어떻게 구현할지를 고민하는 시간보다 무엇을 만들지에 더 집중할 수 있는 환경이 되었습니다.

또한 디자인 시스템 QA 단계에서 컴포넌트의 시각적 규칙과 행동 패턴의 품질을 보장하기 때문에, 개발 과정에서 생성되는 디자인 QA 태스크가 과거 대비 63% 감소했습니다. 서비스 개발 과정마다 padding, margin과 같은 사소한 수치를 점검하는 과정이 사라진 만큼, 더 중요한 작업들을 처리할 수 있게 됐습니다.

디자인 시스템은 수단

Alive가 가장 중요하게 생각한 것은, 디자인 시스템은 목적이 아니라 수단이라는 점입니다.

팀이 달성하고자 하는 것은 결국 비즈니스의 성공이고, 이런 비즈니스의 성공을 서포트하기 위해 Alive는 항상 서비스의 목적이 아닌 수단이 되는 인터널 프로덕트로서 성장해야 합니다. 완벽한 시스템을 만드는 것보다, 팀이 효율적으로 활용할 수 있는 시스템을 만드는 것이 더 중요합니다.

Alive now

Alive는 계속 진행 중입니다. 남은 로드맵을 바탕으로 모든 서비스에 Alive를 적용하여 서비스를 개선하고 있습니다. 시스템은 하루아침에 완성되지 않습니다. 하지만 아이콘 하나, 버튼 하나의 일관성이 모여 제품 전체의 신뢰를 만들어냅니다.

샵라이브의 각 도메인 서비스가 더 많은 비즈니스 목적을 달성하고 더 많은 매출을 창출할 수 있도록 제품 측면에서 구조적인 문제를 해결하며 효율성을 만들고, 나아가 비즈니스까지 서포트하고자 합니다.

Alive는 시스템 운영뿐만 아니라 Alive 외부 공개를 통한 리크루팅 활성화, 샵라이브 플레이어의 모듈화와 시스템화, Svelte와 같은 다른 프레임워크에 대한 지원 등 다양한 목표가 남아있습니다.