근래에는 회사에서 디자인 시스템을 도입하였다는 소식을 쉽게 찾아볼 수 있습니다. 링크
저 또한 디자인 시스템을 도입하고 정착시키는 과정을 겪었습니다.
개발자 입장에서 디자인 시스템을 도입한 경험을 돌아보고, 또 앞으로 어떻게 발전시킬 수 있을지 돌아보도록 하겠습니다.
디자인 시스템에 관한 설명은 10분 만에 읽는 디자인 시스템 A to Z을 참고해 주세요.
제가 사용해보면서 겪은 디자인 시스템은 이러했습니다.
디자이너들은 제품의 아이덴티티, 디자인, 컴포넌트, 디자인 가이드 등을 고려하여 디자인 시스템을 구축하고 개발자에게 UI, UX 가이드라인을 제공합니다.
개발자는 전달받은 내용을 토대로 어떻게 만들지를 고민하게 됩니다. 주로 컴포넌트를 만들어서 사용하게 되는데, 가이드라인에 따라서 컴포넌트를 제작하고 재사용할 수 있도록 만듭니다. 이 과정에서 개발자는 디자인 시스템은 디자이너들이 제공하는 UI, UX 가이드라인에 따라 만든 단순 'UI kit'라고 생각하게 되기 쉽습니다.
폰트, 아이콘, 레이아웃, 규격 등은 디자이너분들께서 정의하였으니, 개발자가 신경 써야 할 부분은 이것을 어떻게 사용할지에 대해 고민을 할 뿐입니다.
폰트 크기 및 색상, 반응형의 크기는 변수를 사용하여 사용하였습니다.
export const palette = {
red_500: "red",
gray_500: "#ddd",
...
}
export const ft21 = css`
font-size: 21px;
line-height: 1.5;
`
...
폰트 크기와 색상을 사용할 때에는 변수 이외의 값을 사용하지 않는다는 규칙을 정하도록 합니다.
//? 빨간색 글씨의 21px 글자
//good
const style = styled.div`
color: ${palette.red_500};
${ft21};
`
//bad
const style= {color:"red", font-size:21px;} // 색상 불일치, line-height 불일치
앞의 예제처럼 개발자들끼리 디자인 시스템을 사용하기 위해서는 규칙을 만들게 되고, 이에 따라 가이드라인이 필요하게 되었습니다.
이 때는 적은 인원이기에 이러한 규칙들을 서로 알기만 하고 문서화시키지 않았었는데, 새로운 개발자가 왔을 때 이러한 규칙들을 직접 전달해야만 했습니다. 후속 개발자를 위해 가이드라인의 필요성이 느껴졌습니다.
대부분의 디자인 가이드를 위해 인풋, 버튼, 실렉터, 등의 간단한 컴포넌트를 만들게 됩니다.
컴포넌트를 만들 때에는 리액트 애플리케이션 구조에서 아토믹(atomic) 디자인을 따라 atom이라 생각되는 컴포넌트를 만듭니다.
디자인만 반영된 컴포넌트는 기존의 html 태그를 스타일만 더하여 제작합니다. 이렇게 하여 사용하는 개발자가 추가적으로 알아야 할 것이 없어 사용하는데 어려움이 없습니다.
드롭다운 및 모달 등의 기능이 필요한 컴포넌트는 hooks를 사용하여 기능들을 쉽게 불러와 사용할 수 있도록 하였습니다.
const {openModal, closeModal, ModalWrapper} = useModal();
...
<Button onClick={openModal}>모달열기</Button>
<ModalWrapper>
<ModalContents />
</ModalWrapper>
여기까지 사용한다면 디자인 시스템 아니 'UI kit'를 만들어 사용하는 데에는 큰 어려움이 없습니다. 하지만 서비스는 다양한 요구를 하기 마련이죠.
예를 들어 간단한 버튼이 있는데, 이 버튼에 아이콘도 추가되어야 하고, 색도 바뀌어야 하고, hover 방식도 3가지가 되고, 아이콘 위치도 바뀔 수 있고, 버튼이 2등분으로 나눠질 때도 있고...
이렇게 조건이 하나 생길 때마다 개발자들은 이에 대응하기 위해 property를 하나씩 추가하게 되고, 코드는 보기 힘들어지고, 저런 조건들은 결국 개발자들이 평소에 숙지하고 있어야 할 숙제가 되고 맙니다.
그러한 조건들을 만족하기 위해 어떻게 하면 효율적으로 작성하고 재사용할 수 있을까를 고민해보았었습니다.
디자인 가이드만 추가된 버튼 컴포넌트를 만들었습니다.
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
const Button: React.FC<ButtonProps> = ({ children, ...props }) => {
return (
<button className="button-style" {...props}>
{children}
</button>
)
}
앞서 예제처럼 다양한 옵션들을 추가하면 다음처럼 변형이 됩니다.
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
color: ColorType
size: SizeType
icon?: React.ReactElement
iconPlace?:IconPlaceType
hover?: ButtonHoverType
half?: boolean
}
const Button: React.FC<ButtonProps> = ({ children, color,...props }) => {
if(icon)...
if(hover)...
if(half)...
return (
<button className="button-style" color={color} {...props}>
{children}
</button>
)
}
조건이 생길수록 숙지해야 할 옵션들이 많아지고, 코드도 복잡해져서 유지보수 측면에서 점점 난이도가 올라가게 됩니다.
그렇다면 컴포넌트를 나누는 방법은 어떤가요.
<ButtonWithIcon>
<HalfButton>
<BlueButton>
<YellowButton>
이러한 방식으로 코드를 분리를 할 수 있게 되겠지만 모양이 바뀌면 그만큼의 파일을 수정해야 하고, 결국 숙지해야 하는 건 같습니다. props로 구분하냐 컴포넌트로 구분하냐의 차이일 뿐입니다.
결론적으로, 저는 다양한 옵션들을 지원하기 위해서 공통 컴포넌트에 옵션을 추가하지 않고, 각각 따로 만들어 주었습니다.
//? 아이콘이 들어가는 인풋
<div className="search-input-wrapper">
<Input/>
<InputIcon className="search-input-icon"/>
</div>
inline style 대신 wrapper를 추가하는 것을 선호합니다.
매번 아이콘 넣어주는 거 번거롭지 않나요? 네. 번거롭습니다. 그래서 이것을 분자(Molecules)로 만들어 사용하게 됩니다.
<form>
<SearchInput/> // 분자
<ul className="result">
<li>result</li>
</ul>
</form>
사실 분자로 만들지도 않았습니다. 재사용의 필요성이 없다면 분자로 만들지 않고, 필요성이 생겼을 때에만 분자로 만들어주었습니다. 실제로 여러 명이 비슷한 기능을 만들었고, 후에 하나의 컴포넌트로 통일하는 작업을 하기도 했습니다. 매번 만드는 것은 번거롭지만, 반대로 예외 상황에서는 자유로울 수 있었습니다. 가령 아이콘 옆에 구분 바를 만든다고 하면 옵션을 하나 더 추가해야겠지만 따로 만들면 해당 부분만 수정하면 됐습니다.
우선 원자(atom)만을 사용하여 작업을 하고, 해당 옵션이 계속해서 필요로 할 경우에는 hooks나 공통 컴포넌트로 만들어 재사용하도록 하였습니다. 그 작업을 미리 하지는 않았습니다. 뭐든 필요에 의해서만 작업을 하기로 하고 있습니다.
// 타이머 기능
const {hour,minutes,seconds} = useTimer();
// 페이지 이탈 방지 기능
<>
<PreventRouting/>
<Content/>
</>
사실 작업하기 전에 해당 옵션의 재사용 정도는 디자이너님들이 잘 알고 있어 미리 물어보는 게 좋습니다.
원자에 옵션을 추가되거나, 분자가 만들까 만들어지게 되면 사용자에게 공유를 해야 합니다.
처음에는 구두로 전달했었습니다. 하지만, 이러한 컴포넌트들이 많아질수록 서로 놓치는 부분이 생기고, 커뮤니케이션 미스로 인하여 결과적으로 반영이 안 된 부분도 빈번했습니다.
전체 개발자에게 디자인 시스템에 대한 내용을 전달을 위한 문서가 필요해졌습니다.
이에 따라 스토리북을 도입하기로 합니다.
스토리북은 다음 그림처럼 컴포넌트 단위 개발을 하는데 도움을 주는 UI 개발 도구입니다.
스토리북을 사용하여 다음과 같은 장점을 얻을 수 있습니다.(주관적)
디자이너와 제작한 컴포넌트 공유 // 디자이너분들은 처음에만 봤던 것 같다.
'docgen' addon을 이용하여 컴포넌트의 property 정리 // 타입 스크립트를 사용하면 거의 안 봐요.
컴포넌트의 옵션들과 기능들을 직접 사용해보며 확인할 수 있다. // 거의 안 쓰더라
신규 개발자에게 가이드를 제공한다.(⭐️⭐️⭐️)
이렇게 장점들을 가지고 있습니다
앞에서 말한 것처럼 저희 팀은 옵션을 잘 추가하지 않고, 분자를 많이 만들지도 않았습니다. 그에 따라 시간이 지나면서 개발자들이 'UI kit'를 사용하는데 익숙해졌고 스토리북을 보지 않고도 개발이 가능했습니다.(서버가 한 달 정도 꺼져있어도 찾는 사람이 없었다...)
신규 개발자가 팀에 합류하였고, 스토리북과 함께 예제를 몇 개 만들어 보면 금세 익숙해져서 스토리북의 역할이 끝났다.
스토리북을 제작하는 데는 어느 정도의 노력이 필요했나요?
초반에 이해하고 설정을 하는 것에 시간이 걸린다.
그 후에 스토리를 만드는 데에는 어렵지 않다.
옵션이나 분자가 추가된다면 내용을 업데이트해야 한다.
신규 입사자와 개발자 간의 공유를 위하여 문서화는 필요하였다.
스토리북이 도입되고 그러한 문제를 해결하였지만, 사실 시간이 해결해 준 문제였다.
하지만 이건 컴포넌트의 변경이 적고, 인원이 적은 팀에서 해결된 문제이다.
인원이 많고, 컴포넌트의 작업이 많을수록 스토리북은 힘을 발휘할 것이라고 예상합니다.
좋았던 것들
디자이너와의 함께 사용하는 만큼 사용하는 언어에서도 통일을 컴포넌트의 구성도 통일하였을 때 소통과 개발이 편리하였던 경험이 있습니다.
스토리북에 다양한 예제를 제공할수록 이해하는데 도움이 되었습니다.
결과적으로, '디자인 시스템'을 도입하여 전체적인 서비스의 통일성이 생겼습니다.
반복적인 작업은 컴포넌트를 재사용하면서 개발 속도를 낮출 수 있었고, 서비스의 확장성도 좋아졌습니다.
이를 위해서 디자이너와 소통을 많이 하였고,
발전을 거듭하며 사용하는 모두가 만족하는 디자인 시스템이 될 수 있었습니다.
디자인 시스템에 관한 회고 글을 쓰면서 다른 글들을 찾아보면서 새롭게 깨달은 것이 있습니다. 내가 경험한 디자인 시스템은 'UK kit'에 불과했다는 것입니다. 참고. 디자인 시스템, 제대로 알고 제대로 만들어야 한다, 10분 만에 읽는 디자인 시스템 A to Z
저는 디자인 시스템의 '유형적인 요소'만을 고려하였고, '무형적인 요소'를 고려해보지 못했습니다.
새로운 팀에 들어오면서 팀의 방향성, 일하는 방법, 사고방식들을 배우며 디자인 시스템에 대한 공부를 하고 있습니다.
디자인 시스템을 발전시키는 역할로써 개발자들이 디자인 시스템을 더 잘 이해하고 쉽게 사용할 수 있도록 노력하고자 합니다.
이런 것도 있군요!
모르고 있던 거 알아갑니다. 감사합니다