섹션 도입부 UI 분리로 캐릭터 연출 강화
목차
섹션 도입부를 캐릭터 말풍선(speak-bubble)으로 분리하고 빈 패널에 대한 가드를 추가했다. 단순해 보이는 리팩토링이지만, 읽기 경험과 코드 유지보수성 모두에 영향을 주는 작업이었다.
섹션 도입부, 왜 분리했나
열람 패널에서 각 섹션이 시작될 때 캐릭터가 인사를 하거나 설명을 덧붙이는 도입부가 있다. 원래는 섹션 본문과 함께 인라인으로 렌더링되고 있었는데, 스타일도 뒤섞여 있고 로직도 복잡했다.
이번에 speak-bubble이라는 별도의 UI로 분리한 이유는 몇 가지다:
- 재사용성: 캐릭터 말풍선이 섹션마다, 여러 맥락에서 나타날 수 있는데, 분리하면 한 군데서만 유지보수하면 된다
- 스타일 명확성: 말풍선만의 CSS를 별도로 관리하면서 주변 패널 스타일과 간섭이 줄어든다
- 읽기 경험: 도입부가 별도의 박스나 시각적 강조로 분리되면서, 사용자 입장에서 "여기서 캐릭터가 뭔가 말한다"는 신호가 더 명확해진다
실무에서 이런 UI 리팩토링은 보통 기술 부채가 쌓일 때 하게 된다. 초반에는 "섹션 도입부 + 본문"을 한 덩어리로 처리하는 게 빠르지만, 기능이 늘어나면서 (캐릭터 이모션 추가, 말풍선 스타일 변경, 모바일 대응 등) 점점 복잡해진다. 분리는 그런 복잡도를 관리하는 전략이다.
빈 패널에 대한 가드 추가
가드라고 부르는 게 있다 — 렌더링 직전에 특정 조건을 체크해서 문제 상황을 미리 걸러내는 것이다. 이 작업에서는 패널 콘텐츠가 비어 있을 때를 처리했다.
예를 들어:
- 네트워크 로딩 중에 임시로 섹션이 비어 있을 수 있다
- 서버 에러로 데이터가 없을 수 있다
- 사용자가 실수로 빈 섹션을 열었을 수 있다
이전에는 이런 상황에서 레이아웃이 깨지거나 오류가 콘솔에 났을 수 있다. 빈 상태에 대한 명확한 검증을 reading-panel.tsx에 추가함으로써:
| 상황 | 이전 | 이후 |
|---|---|---|
| 데이터 없음 | 레이아웃 깨짐 / 에러 | 상태에 맞는 메시지 또는 스켈레톤 표시 |
| 로딩 중 | 불완전한 UI 렌더링 | 로딩 상태 명시적 처리 |
| 오류 상황 | 사일런트 실패 | 에러 바운더리나 폴백 표시 |
이건 UX 개선이자 동시에 버그 예방 조치다. 팀 리딩 입장에서 보면, "리팩토링할 때 엣지 케이스도 함께 처리한다"는 문화가 중요하다. 단순히 코드를 깔끔하게 하는 것도 좋지만, 그 과정에서 놓친 부분들을 발견해서 고치는 게 더 가치 있다.
변경 파일의 역할
두 파일이 어떻게 역할을 나눴는지 보면 이 리팩토링의 의도가 더 명확해진다:
src/app/globals.css
- speak-bubble의 스타일 정의 (박스, 배경색, 그림자, 폰트 등)
- 전역 CSS이기 때문에 앱 전체에서 일관된 외형 유지
- 다크 모드, 반응형 등 기본 스타일도 함께 관리
src/app/r/[uid]/reading-panel.tsx
- 섹션 도입부 렌더링 로직 (speak-bubble 컴포넌트 조건부 표시)
- 빈 패널에 대한 검증 로직
- 패널 상태 관리 (로딩, 에러, 성공)
이렇게 관심사가 분리되면, 디자이너가 speak-bubble 스타일만 변경하려면 globals.css만 보면 되고, 엔지니어가 도입부 표시 조건을 바꾸려면 reading-panel.tsx만 수정하면 된다. 코드 리뷰도 더 간단해진다.
일반론 — 언제 분리할까
이 작업을 통해 느낀 건, UI 분리의 타이밍이 중요하다는 것이다. 너무 빨리 분리하면 과도 엔지니어링이 될 수 있고, 너무 늦으면 기술 부채가 된다. 대체로 다음 신호들이 보이면 분리를 고려하는 게 좋다:
- 같은 패턴이 여러 곳에서 반복되고 있다
- 스타일 변경이 예상되는데 로직도 함께 엮여 있다
- 새로운 기능을 추가하려니 현재 구조를 이해하는 데 시간이 든다
- 테스트하기 어려운 상황이 생긴다
이 경우 섹션 도입부가 여러 곳에서 다르게 쓰일 예정이었고, 스타일 개선(아이콘 추가, 색상 조정 등)이 자주 요청되고 있었다. 그래서 분리가 합리적인 선택이었다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.