Published
- 6 min read
변경에 유연한 컴포넌트를 만들자 #1
왜 변경에 시간이 걸리는가?
원인은 다음과 같다.
- 컴포넌트 인터페이스에 결합된 도메인 의존성
- 확장 불가능한 인터페이스
- 컴포넌트 내부에서 쓰는 자식 컴포넌트의 추상화 단계가 이븐하지 않음
인테페이스, 인터페이스, 인터페이스 인터페이스는 중요하다.
컴포넌트 인터페이스에 결합되어있는 도메인 의존성
예를 들어 XXXItem 이라는 컴포넌트 만들었다 치자. 그러면 XXX라는 도메인 안에서밖에 사용 불가함. 근데? XXXItem, OOOItem ?? 이런거 엄청 많이 쓰잖아. 비슷한 기능과 동작인데 항상 새로 만들어야 함.
해결과정
모든 맥락에서 다 쓸 수 있게 활짝 Open하자.
도메인 맥락을 제거하고 Style의존성에 대한 고민
정말 여러 군데에서 사용할 수 있고 변경될 수 있는 여지가 무한대가 됨. 근데 기능은 “OOItem 표출”이지만 Style이 조금 다르다면?? 기능이 동일하니 이 컴포넌트 재사용해서 생산성 up하는게 자연스러운 흐름이다. 근데?
Text가 아니라 Icon이 추가된다면? 그 위치가 앞이 됐다가 뒤가 됐다가 막 바뀌어. 이럼??
Props를 추가해서 대응하는 것은 안좋은 선택이었다.
Props가 추가되면 될 수록, 요구사항이 변경될 때마다(무한대) 복잡해짐. 유지보수성 down.
그래서 컴포넌트를 세분화하고 공통으로 사용하는 부분을 분리했음.
좋은 방법인데, 나의 구현이 사용자 친화적이지가 않았음. 사용하는쪽에서 결정할 수 있게 주도권을 외부에 넘겨야 하는데 그냥 꽉막힌걸 여러개 만들어내는 꼴이 되어버림.
확장 가능한 구조
가능하면 표준 인터페이스를 써라
interface Props extends LiHTMLAttributes<HTMLLIElement> {
button?: ReactNode
}
그저 표준 인터페이스를 extend하는 것만으로도 엄청나게 많은 도움이 된다. 특히, 내 생각을 절제하고 (사용자 친화적인)표준 인터페이스를 강제하게 된다. 안따르면 컴파일이 안되거든.
이 Props는 li attributes를 그대로 쓸 수 있다. 그리고, 데이터 구조와 관련된 Prop없이 그대로 children
을 가져다 써야 한다.
인터페이스 생각하기 어려우면 일단 표준 인터페이스를 Extend하자. 그 뒤에 생각.
네이밍은 중요하다.
오픈소스 디자인 시스템 라이브러리에서 흔히 사용되는 일반적인 네이밍을 그대로 가져다 쓰는게 오히려 낫다.
남들이 다 Switch라 그러고 onChange라는 핸들러를 쓰는데 너 혼자 Toggle & onToggle이라 그러지 말란 말이다.
자식 컴포넌트들의 추상화 단계의 일관성
function SomethingComponent({}: SomethingcomponentProps) {
// 어쩌구 저쩌구
return (
<ParentSomething>
<AAAFeature className='추상화1단계' />
<BBBFeature className='추상화1단계' />
<div className='어기서 갑자기 구현세부사항 등장'>
<CCCFeature className='추상화2단계' />
<image href='근데 여긴 또 추상화가 아니다??' />
<div className='근데 여긴 또 추상화가 아니다??' />
</div>
</ParentSomething>
)
}
왜 이렇게 되었냐, 이해는 감. CCCFeature는 나중에 요청이 들어왔겠지. 근데 이게 올바르냐? X
2주 지나서 다시, 혹은 다른 사람이 이 코드 보면 눈이 피로해짐. 맥락을 놓쳐버리고 왔다갔다를 많이 해야 됨. 한번에 이해가 안됨.
즉, 변경에 시간이 걸린다. DDDFeature 추가할 때 어케 넣을지 혼동이 온다. 1단계에 넣었다가 CCCFeature가 망가지면 어떻게 함. 결국 CCCFeature를 다 읽고 난 뒤에 어디 넣을지 결정해야 한다. 최악의 상황에는 CCCFeature도 수정해야 한다.