티스토리 뷰

공용 컴포넌트 모듈화를 적극 도입한 이유

저는 "사용자에게는 일관적인 사용자 경험을, 개발자에게는 생산성 있는 경험을 제공하는 것"이 제가 가장 중요하게 생각하는 부분인데요.

이전 프로젝트에서는 초반에 모듈화 틀을 잘 잡아놓지 못해 서로 중복되는 스타일 컴포넌트를 작성하거나, 심지어 비슷하면서도 조금씩 다른 스타일을 가지기도 했습니다.

 

이는 사용자에게 혼란을 주며(동일한 기능을 하는데 스타일이 다르다면 사용자는 다른 기능을 한다고 인식할 수 있습니다), 개발자는 중복되는 스타일 코드, 기능 코드를 매번 작성해야 합니다.

 

이런 불편함을 해소하기에는 공용 컴포넌트 모듈화가 필요했습니다.

 

모듈화에 큰 어려움이 없었던 결정적 이유

Figma - 와이어프레임

모듈화에 큰 어려움이 없었던 이유는 초반 설계를 꼼꼼하게 했었기 때문인데요.

Figma로 와이어 프레임을 설계하고 후반 작업으로는, 2번 이상 사용되는 컴포넌트는 체크를 하여 공용 컴포넌트로 만들 컴포넌트를 리스트업 했습니다.

 

물론 프로젝트 도중 수정 사항이 생겨 공용 컴포넌트를 추가하는 일도 있었습니다. 하지만 이미 정말 자주 사용되는 Button, Input과 같은 컴포넌트들은 이미 설계가 되어, 프로젝트 진행에 있어서는 전혀 지장이 없었습니다 :)

 

모듈화 방식

가장 대표적인 예인 Button 컴포넌트를 예시로 들겠습니다.

같은 버튼이라고 할지라도 가령 예를 들어, 지금 제가 작성하고 있는 티스토리 글쓰기 화면에서도 아래와 같이 길이, 색상, 폰트 색상 등이 다를 수는 있습니다.

이를 어떻게 어떤 조합으로 묶어 사용하면 편리할지를 고민해야 했습니다.

우리가 옷을 입을 때 상의 목록 중에 하나를 고르고, 하의 목록에서 하나를 고르고, 신발 목록에서 하나를 골라 코디를 조합하듯이 저희 팀에서는 이러한 방법으로 CSS 조합을 고를 수 있도록 했는데요.

 

📜 src/Components/Button/Button.styled.js 

import styled, { css } from 'styled-components'

const variantCSS = {
	default: css`
		background-color: ${({ theme }) => theme.COLOR.common.gray[400]};
		font-family: ${({ theme }) => theme.FONT_WEIGHT.bold};

		&:hover {
			background-color: ${({ theme }) => theme.COLOR.common.gray[300]};
			transition: all 0.2s ease-in-out;
		}

		&:disabled {
			background-color: ${({ theme }) => theme.COLOR.common.gray[200]};
		}
	`,
	'default-reverse': css`
		border: 1px solid ${({ theme }) => theme.COLOR.common.gray[400]};
		font-family: ${({ theme }) => theme.FONT_WEIGHT.bold};
		background-color: ${({ theme }) => theme.COLOR.common.white};

		&:hover {
			background-color: ${({ theme }) => theme.COLOR.common.gray[100]};
			transition: all 0.2s ease-in-out;
		}
	`,
	'no-border': css`
		font-family: ${({ theme }) => theme.FONT_WEIGHT.bold};
		background-color: ${({ theme }) => theme.COLOR.common.white};
		border: none;

		&:hover {
			background-color: ${({ theme }) => theme.COLOR.common.gray[100]};
			transition: all 0.2s ease-in-out;
		}
	`,
}

const shapeCSS = {
	default: css`
		border-radius: 2rem;
	`,
	soft: css`
		border-radius: 0.8rem;
	`,
	square: css`
		border-radius: 0rem;
	`,
}

const sizeCSS = {
	default: css`
		width: 16rem;
		height: 4.8rem;
	`,

	full: css`
		width: 100%;
		height: 4.8rem;
	`,
	fit: css`
		width: fit-content;
		height: fit-content;
		padding: 0.3rem 1.5rem;
	`,
}

const fontSizeCSS = {
	default: css`
		font-size: ${({ theme }) => theme.FONT_SIZE.medium};
	`,
	small: css`
		font-size: ${({ theme }) => theme.FONT_SIZE.tiny};
	`,
	small: css`
		font-size: ${({ theme }) => theme.FONT_SIZE.small};
	`,
	large: css`
		font-size: ${({ theme }) => theme.FONT_SIZE.large};
	`,
}

위 코드와 같이 Shape에서 선택지 몇 개, Size에서 선택지 몇 개 이런식으로 각각 몇 가지를 지정했습니다.

이 지정 기준은 Figma 와이어 프레임을 토대로 이뤄졌습니다. 자주 사용되는 옵션을 선택하는 거죠 !

 

이제 선택 조합들을 정해주었으니, 사용할 때 조합을 선택해서 해당 스타일을 사용하게 될텐데요. 이는 아래와 같이 적용해주었습니다.

export const Button = styled.button`
    ${({ variant }) => variantCSS[variant]}
    ${({ shape }) => shapeCSS[shape]}
    ${({ size }) => sizeCSS[size]}
    ${({ fontSize }) => fontSizeCSS[fontSize]}
    cursor: ${({ disabled }) => (disabled ? 'default' : 'pointer')};
`

즉, Button 컴포넌트를 사용할 때 props로 넘겨 받아 적용하는 방식입니다.

 

위에 보이는 Button은 스타일 컴포넌트를 선언해준 것 뿐입니다. 이제는 Button이라는 컴포넌트를 만들 차례인데요.

우리가 컴포넌트에 props로 넘겨 받은 걸 사용할 때 구조 분해해서 사용하듯이 해주면 됩니다.

 

📜 src/Components/Button/Button.js 

import * as S from './Button.style'

function Button(props) {
	const {
		variant = 'default',
		shape = 'default',
		size = 'default',
		fontSize = 'default',
		fullWidth = false,
		children,
		...rest
	} = props

	return (
		<S.Button
			variant={variant}
			shape={shape}
			size={size}
			fontSize={fontSize}
			fullWidth={fullWidth}
			disabled={!!rest.disabled}
			{...rest}
		>
			{children}
		</S.Button>
	)
}
export default Button

위 코드에서 주목해서 봐야할 점들은 2가지인데요.

 

1. default 속성을 주었다

Figma에서 와이어 프레임을 보게 되면 제일 자주 사용되는 버튼 스타일이 있을 것입니다. 해당 스타일은 특별히 props로 어떤 값을 넘겨주지 않아도 지정될 수 있도록 default를 설정해준 것입니다.

자주 사용하는 스타일이니 더욱 편하게 사용할 수 있겠죠?

 

2. ...rest

.`..rest`에는 우리가 특별히 가져온 props 이외의 prop들이 포함되게 되는데요. 가장 대표적으로 `onClick`이 포함될 수 있겠습니다. 사용할 때 그냥 button 태그를 사용하듯이 `onClick` 속성으로 이벤트 함수를 넘겨주게 되어도 곧잘 동작할 것입니다 :)

 

모듈화를 통해 얻을 수 있었던 생산성

우선 매번 디자인을 확인해 가며 color나 font size 같은 부분을 prop 값을 통해 키워드만 전달해주면 스타일이 적용된다는 점에서 중복된 코드를 굉장히 많이 줄일 수 있었습니다.

 

프로젝트에서 공용 컴포넌트를 통해 사용되고 있던 컴포넌트들은 디자인 수정이 생겼더라도 모듈화된 파일에서 수정을 해주면 일괄적으로 수정되는 것 덕분에 생산성 면에서 도움이 많이 되었습니다.

 

아쉬웠던 점도 있습니다

저희는 프로젝트 극초기에 웬만한 공용 컴포넌트를 모두 잡고 시작했습니다.

 

문제점1.

해당 작업을 할 때 팀원들과 "이 정도(색상, 크기)면 되겠죠?" 라는 말을 매번 하면서 진행했습니다.

그래서 어느정도 작업을 진행했다고 하면 빈 파일에 들어가 컴포넌트를 호출해 직접 시각적으로 확인을 하며 추가 수정을 이어갔습니다.

 

문제점2.

다른 팀원이 만든 공용 컴포넌트를 사용할 때 원하는 디자인 요소를 위해서는 속성 코드들을 어느정도는 파악해야 했습니다.

 

이는 문서화 부족에 따른 문제였다고 생각합니다. 컴포넌트 별, 속성별로 시각적으로 문서화하여 진행했더라면 위와 같은 문제를 해소할 수 있었을 것 같기도 합니다.

 

그래서 다음 프로젝트에서는 `Storybook`을 적극 도입하여 문서화를 해보려고 하고 있습니다 :) 

 


여기까지 팀원들과 초기부터 공용 컴포넌트 모듈화에 집중하여 설계했던 이유와 과정들을 소개해보았습니다 :)

앞으로도 저는 공용 컴포넌트 모듈화를 필수로 진행할 것 같고, 더욱 생산성 있고 편한 사용법을 위한 모듈화 방식에 대해 고민하고 적용해 나갈 것입니다 :)

728x90
LIST
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함