-
컴포넌트 설계의 진짜 의미React 2024. 4. 23. 17:59
우리는 귀에 딱지가 앉도록 듣는 말이 있습니다.
‘컴포넌트를 잘 설계해야 한다.’
컴포넌트 설계…?
설계의 뜻이 뭘까요?
음..
컴포넌트를 ‘만든다’로 쉽게 생각해도 될 것 같아요.
컴포넌트 설계를 ‘잘’ 설계한다 = 컴포넌트를 ‘잘’ 만든다.
‘잘’ <— 이게 핵심이네요.
그럼 컴포넌트를 잘 만든다는건 어떤 의미일까요?
컴포넌트를 잘 나누는 것일까요?
그렇다면 컴포넌트를 나누는 이유는 뭘까요?
재사용 가능하게 나눠야한다는 뜻일까요?
컴포넌트의 뜻부터 같이 알아보죠.
좀 더 개발적인 의미로 들어가볼까요?
리액트 공식문서를 살펴보니, UI를 구성하는 요소라고 하네요.
우리가 흔히 말하는 컴포넌트를 재사용한다는 의미가,
결국 UI를 재사용하기 위해 컴포넌트를 잘 만들어야한다고 말하는걸까요?
혹은 기능을 재사용하기 위함일까요?
아니면 둘 다?
제 생각에는 UI + 기능을 재사용하는 것이 진정한 컴포넌트의 재사용이라고 생각합니다.
그럼 재사용이 가능하다는 의미의 범위가 어디까지 일까요?
단순히 다른 곳에서 한 번 더 쓰이면 재사용인지
모든 곳에서 쓰일 수 있어야만 재사용인지..?
제 경험 공유하며 같이 고민해보도록 하죠!
어느 날, 같은 팀 디자이너 분이 저를 애타게 찾더군요.
벌써부터 느낌이 안좋습니다.
제품의 요구사항이 바뀐 것인데요,
디자이너 팀원들의 요구사항은 아래와 같았어요.
제품의 디자인이 바뀐 이유는
1. 유저에게 온보딩 단계를 더 가시적으로 보여줄 필요가 있다.
2. 유저가 입력한 '토너먼트 종료일'와 '선물 전달일'의 순서를 더 명확하게 하기 위한 디자인이 필요하다.
3. 카카오톡 공유에 한정된 부분을 일반 공유하기로 대체한다.
4. 어차피 일반 공유하기에 링크 복사 기능이 있으니, 링크 복사 버튼을 삭제하고, 입장하기 버튼을 추가한다.
오! 제품이 좀 더 디벨롭되는군요! 개발자인 저도 기분이 좋습니다 ㅎㅎ
그건 그렇고, 음… 디자인이 싹 다 바뀌었네요?
스프린트가 얼마 남지 않았던 이슈로,
조금 더 효율적으로 일하기 위해 재사용 할만한 요소들을 찾아보겠습니다.
타이틀 UI요소(빨간박스), 선물 전달일 및 토너먼트 진행 시간(초록박스) 정도가 되겠네요.
초록박스는 기능은 그대로 남겨둔 채로, UI만 수정하면 될 것 같아요.
그렇다면 저 파란박스 내 버튼들은 어떻게 해야할까요?
스프린트 기한이 며칠 남지 않았는데, 새롭게 구현할 생각하니 막막합니다...
다른 팀원들의 뷰에서 가져다 쓸만한 것은 없는지 살펴보겠습니다.
오!! 여기 토너먼트 최종 결과물 뷰에서 파란박스 내 버튼들을 재사용하면 금방 구현할 수 있겠군요!
버튼의 텍스트와 기능은 다르고, UI만 같네요.
이제 코드를 살펴보러 가봅시다.
음.. 지금 구조에선 '다시하기' 텍스트 하나만 바뀌어도 재사용이 불가능 할 것 같네요.
그러나 시간이 부족했던 스프린트 특성과, 제 실력 이슈로!!
일단 복붙하고, 네이밍과 기능만 바꿔서 진행해 봅니다. (아주 비효율적이죠?)
이제부터 차근차근 공통으로 쓰일 수 있게 작업해봅시다.
기능은 다르고 UI는 완전히 같아요.
(토너먼트 결과 버튼은 '결과 제출하기' '다시하기' / 온보딩 결과 버튼은 '공유하기' '입장하기'이기 때문)
그러나
현재 네이밍(빨간박스)으론 토너먼트 결과 footer와 온보딩 결과 footer에서만 버튼이 쓰일 수 있겠죠?
더 넓은 사용성을 위해 일단
도메인을 제거해야할 것 같아요.
CommonButton이라는 이름을 주고, children을 활용해봅시다!
음... 이렇게 하니까 문제가 있네요. 위 CommonButton을 가져다 쓰는 쪽에서 children이 같은 값이 들어가버려요.
그래서 버튼의 text가 '공유하기' '공유하기' 처럼 똑같이 들어가는 문제가 있네요.
새롭게 props를 설정해봅시다.
onClick은 버튼 태그의 기본 props를 상속받았기에 지워주고,
left와 right라는 네이밍을 통해 왼쪽 버튼의 텍스트와 클릭 시 핸들러, 오른쪽 버튼의 텍스트와 클릭 시 핸들러를 정의해주었어요!
- 좀 더 직관적인 네이밍 이용을 의도했습니다.
이제 공통으로 빼줬으니, 한 번 가서 사용을 해볼까요?
음... 이렇게 바꿔봤는데 어떤가요?
원래 코드보다는 재사용이 가능할 것 같아요.
이제 온보딩 최종 단계footer와 토너먼트 결과 뷰 footer에서 같이 가져다 쓸 수 있게 되었어요!
'비교적' 변경에 유연한 UI를 가지게 되었습니다.
그러나,,,,
이제 이런 요구사항이 있다고 가정해보죠.
'온보딩 최종단계 footer의 왼쪽 버튼의 색깔을 다르게 정의해주세요'
'토너먼트 결과 뷰 footer의 오른쪽 버튼에 화살표를 추가해주세요.'
기존의 방법대로라면,
이렇게 props를 추가해서 구현을 할 수 있을겁니다.
그러나, 컴포넌트의 가치가 떨어지는 것 같은 불안한 느낌이 들죠...
기껏 재사용성을 고려하여 만들어놨는데,
추가적인 요구사항에는 대응하지 못하는 컴포넌트가 되어버린 것만 같아요.
애초에 설계를 잘하지 못한걸까요?
우리는 어디까지 고민하며 컴포넌트를 설계해야 할까요?
이를 해결하기 위해 대표적인 원칙과 개발자 선배들이 먼저 고민하신 부분을 소개해드리겠습니다.
SRP : Single Responsibility Principle
평소 SOLID 원칙에 대해서 많이 들어보셨을 것 같아요.
그 중에서도 SRP는 가장 중요한 단일 책임 원칙인데요.
이를 잘 지키기 위해,
컴포넌트는 다음과 같은 기준으로 보아야 합니다.
1. Headless 기반의 추상화하기
- Headless 란?
- 사용자 인터페이스(UI)를 가지지 않은 컴포넌트
2. 한가지 역할만 하기
- 또는 한 가지 역할만 하는 컴포넌트의 조합으로 구성하기
3. 도메인 분리하기
- 도메인을 포함하는 컴포넌트와 그렇지 않은 컴포넌트 분리하기
위와같은 원칙을 지키며 다시 변경에 유연하게 바꿔보죠.
이해를 돕기 위해 기존 버튼이 아니라 모달창을 가지고 왔습니다.
다음과 같은 모달창이 있다고 가정해보죠.
컴포넌트 합성을 이용을 해볼게요.
- 컴포넌트 합성이 무엇인지는 아래 레퍼런스 참고 부탁드려요!!
서브 컴포넌트 먼저 정의해보겠습니다.
다음으로 메인 컴포넌트를 정의하겠습니다.
메인과 서브 컴포넌트를 묶어서 export 해줍니다
그럼 이제 사용법을 같이 살펴보죠.
이제 우리는 보다 변경에 유연한 컴포넌트를 얻게 되었습니다.
모달 안의 텍스트가 바뀔 때는 Modal.Title을,
모달 닫기 버튼의 아이콘이 바뀔 때는 content를,
모달 확인 버튼의 텍스트가 바뀔 때에도 content를,
각 모달 서브 컴포넌트들의 위치가 바뀔 때에도 보다 유연하게 대처할 수 있게 되었습니다.
**결론을 정리해보겠습니다.
컴포넌트를 잘 설계한다 = 컴포넌트를 잘 만든다 = 컴포넌트를 잘 나눈다 = 재사용하기 용이하다?
그럼 우리는 어디까지 재사용을 고려하며 개발해야 하는가?
아직 일어나지 않은 추가적인 요구사항을 대응할 정도로 컴포넌트 설계를 고려해야 하는가?
- 토스 한재엽님께서는 다음과 같이 고민해야한다고 말씀하십니다.
1. 컴포넌트로 분리하면 실제로 복잡도를 낮추는가?
2. 컴포넌트로 분리하면 재사용 가능한 컴포넌트인가?
- 당근마켓 원지혁님께서는 다음과 같이 고민해야한다고 말씀하십니다.
1. 비슷한 관심사라면 가까운 곳에
2. 데이터를 ID 기반으로 정리하기
3. 의존한다면 그대로 드러내기
4. 모델 기준으로 컴포넌트 분리하기
결국 우리는 이런 선배 개발자 분들이 먼저 닦아놓으신 고민의 흔적과 생각을 근거로,
나만의 기준을 세워 컴포넌트를 바라보아야 하는 것은 아닐까요?
이 아티클을 접하시고, 컴포넌트 분리의 원칙을 그대로 받아들이는 것이 아니라,
새로운 요구사항에 우리가 어떻게 대응하고 있는지,
기존 우리의 코드에 스스로 문제정의를 하며
끊임없이 개선하는 노력을 기울이는 개발자가 되시기를 기원하며
아티클 마치겠습니다.
- 장정안
참고 레퍼런스 꼭꼭 보시는 걸 추천드립니다!
정말 많은 인사이트가 담겨있어요!!!
참고 레퍼런스:
https://www.youtube.com/watch?v=fR8tsJ2r7Eg
https://fe-developers.kakaoent.com/2022/220731-composition-component/
https://www.youtube.com/watch?v=HYgKBvLr49c
https://fe-developers.kakaoent.com/2023/230330-frontend-solid/
https://fe-developers.kakaoent.com/2024/240116-common-component/
'React' 카테고리의 다른 글
변경에 유연한 컴포넌트 설계 (1) 2024.06.17 이미지 최적화 후 Lighthouse로 성능 검사하기 (0) 2024.05.10 모던 리액트 Deep dive - 렌더링은 어떻게 일어나는가? & 메모이제이션 (0) 2024.03.19 useContext (ContextAPI) 란? (0) 2024.03.12 언젠가는 쓸 useLayoutEffect... (useEffect vs useLayoutEffect) (0) 2024.03.03