설계?
유지보수 잘 하려면 코드를 이쁘게 짜 놓아야 한다. 하지만 코드를 이쁘게 짜겠다는 선언만으로는 그렇게 할 수 없다. 건물을 지으려면 땅에 줄부터 그어놔야 하듯이 코드가 올라갈 기반도 뭔가 틀이 잘 잡혀야 코드를 깔끔하게 올릴 수 있는데 이번 시리즈에서는 설계를 위한 다양한 시도 끝에 내가 얼추 픽스하려고 하는 것들을 남겨보려고 한다.
Nextjs의 레이아웃
나는 레이아웃의 설계가 상당히 중요하다고 생각한다. 컴포넌트가 어디에 배치되고 어디에 표시될지 명확하게 설계가 되어야 앞으로 올릴 컴포넌트들을 블록 쌓듯이 착착착 올릴 수 있기 때문이다.
그런 점에서 Next.js에서 제공하는 레이아웃은 기능별, 페이지별 분리가 너무나도 편하게 설계가 되어있어 사용하기 편하다. 레이아웃에 대한 Next.js의 공식문서를 한번 살펴보자.
레이아웃은 라우트 세그먼트(app의 디렉토리)에 하나씩 존재할 수 있고, 라우트 세그먼트의 계층적 구조에 의해 레이아웃도 계층화가 된다. 즉, 구조에 따라 중첩된 레이아웃(nested layout)을 구성할 수 있다.
위 그림은 루트 레이아웃 아래 레이아웃이 중첩된 모습을 그려본 것이다. 나는 이 구조가 좋다고 생각하지 않는다. 루트 레이아웃에 특정 구조를 넣어버렸기 때문인데, 물론 필요에 따라서는 유용할 수 있겠지만, 추후에 루트 레이아웃이 없어야하는 등의 특정 요구사항이 들어왔을 때는 확장성의 부재로 다소 많은 유지보수 비용을 투자해야할 수도 있다.
집합적 사고로 레이아웃 구성하기
그럼 레이아웃을 어떻게 구성해야 유지보수에 유리하게 만들 수 있을까?
유지보수의 핵심은 "생각할 꺼리를 줄이는 것" 이라고 생각한다. 생각할 꺼리를 줄이려면 기능이 잘 분리되어야 한다. 만약 A 기능을 수정했는데 B 기능이 영향을 받게되면 A 기능을 수정할 때 많은 생각을 해야할 것이다. 우리는 이러한 현상을 방지하기 위해 코드를 기능별로 응집하고 모듈화한다.
레이아웃도 동일하다. 유지보수를 편하게 하려면 생각할 꺼리를 줄여야 한다. 다만 레이아웃을 기능 단위로 묶는다고 생각하면 약간 어색하다. 레이아웃을 응집한다거나 모듈화한다는 말도 왠지 와닿지 않는다. 나는 이 어색함이 레이아웃의 태생적 특별함에서 기인한다고 생각한다.
레이아웃은 존재 그 자체만으로 프로젝트에 영향을 미친다. 함수나 클래스는 특정 시점에 호출을 제어할 수 있지만 레이아웃은 그냥 그대로 거기에 존재한다. 게다가 변화도 크게 없기에 설계의 필요성을 크게 느끼지 못하는 경우도 많다. 그러다 레이아웃을 근본적으로 뜯어고쳐아 하는 요구사항이 생기면 지옥도가 펼쳐진다.
이러한 현상을 방지하려면 레이아웃도 어느정도의 설계가 필요하다. 어떻게 하면 설계를 잘 할 수 있을까? 나는 그 해답을 집합적 사고에서 찾았다.
Next.js는 레이아웃에 계층이 존재한다. 루트 레이아웃은 프로젝트의 전역에 영향을 미치는 최상단 레이아웃이며, 그 아래로 라우트 세그먼트 별로 레이아웃이 존재할 수 있다. 이 상황을 밴 다이어그램으로 그려보면 아래와 같지 않을까?
루트 레이아웃: 전체집합
루트 레이아웃은 전체 집합이며 언제나 존재한다. 따라서 모든 하위 집합에 영향을 미칠 수 있다. 그러므로 나는 "루트 레이아웃이 어떠한 UI 구조도 가질 수 없게 해야한다"고 생각한다. 루트 레이아웃의 UI는 전역적인 영향을 미치므로, 수정할때도 전역적인 사고를 해야할 것이다. 대신 프로젝트 전역에 영향을 미쳐야만 하는 프로바이더, 폰트, 글로벌 CSS와 같은 설정 파일은 루트 레이아웃에 포함해야 할 것이다.
루트 레이아웃에 UI 스타일이 없다면 라우트 세그먼트의 스타일 유지보수 시 루트 레이아웃을 아예 고려사항에서 배제할 수 있게 된다. 물론 라우트 세그먼트 별로 레이아웃 구조를 가지게 된다는 번거로움이 생길 수 있겠지만 이 마저도 집합적 사고를 통해 해결할 수 있다고 생각한다. 아래를 이어서 보자.
레이아웃 관계설정 : 겹치지 않는 집합 (A ∩ B = ∅)
한 프로젝트에 각자 다른 레이아웃 A와 B가 각각 존재한다고 생각해보자. 아래 그림처럼 생각해볼 수 있을 것이다.
즉 디렉토리 구조는 아래처럼 될 것이다.
레이아웃이 병렬적으로 관리되기 때문에 추후 다른 레이아웃을 가진 라우트 세그먼트를 추가하기에도 쉬울뿐더러, A와 B가 각각의 UI 전용 레이아웃 역할이 있으므로 A를 유지보수할 때는 B를 아예 생각하지 않아도 될 것이다.
레이아웃 관계설정 : 부분집합 (B ⊆ A)
A 레이아웃이 B 레이아웃을 포함해야하는 경우도 생길 수 있다.
이러한 경우, (b) 디렉토리를 (a) 디렉토리 내부에 넣는 경우를 생각해볼 수 있다. 이 방법은 Next.js에서도 권장하는 방법이다.
이로써 B 레이아웃은 A 레이아웃의 부분집합이 되고, 유지보수할때도 논리적으로 A와 B의 상관관계를 인지할 수 있다.
결론
이렇듯 집합적 사고를 통해 레이아웃을 배치하면 나중에 유지보수를 할 때 집합의 범주에 들어가지 않는 부분은 아예 생각에서 제외해버릴 수 있다는 장점이 있다. 다만 디렉토리 트리 구조가 복잡해질 수 있고, 코드의 중복도 생길 수 있음을 감안해야 한다. 또한 루트 레이아웃에 들어간 UI가 100% 바뀌지 않는다고 확신할 수 있다면 루트 레이아웃을 적극적으로 사용하는것이 올바를 것이다. 다만, 변화는 언제든 있기 마련이다. 언제든지 상황이 변할 수 있다고 믿는 경우에는 위와 같이 사고하여 레이아웃을 설계해보는 것도 좋은 방식이라 생각한다.
'개발 일지' 카테고리의 다른 글
프로젝트 설계 이모저모 - 프론트엔드 리포지토리 패턴 구현 (0) | 2024.02.29 |
---|---|
Nextjs 프로젝트 설계 이모저모 - 과도기적 디렉토리 설계 (2) | 2024.02.08 |
프론트엔드 설계 아이데이션 (0) | 2024.01.12 |
iOS/Android flutter 웹뷰 렌더링 엔진 이슈 해결 (1) | 2024.01.08 |
에러 처리) assert 함수 활용 (0) | 2024.01.08 |