실시간 알림 구조 다시보기

Jnns·2026년 1월 30일
post-thumbnail

이전 프로젝트에서 실시간 알림을 구현하며 전역 상태로 Socket과 Toast를 관리했던 이유와 이후 리팩토링을 고민하게 된 계기를 정리해보려 한다.


초기 구현 방식

실시간 이벤트와 알림이 포함된 기능을 구현하면서 가장 중요하게 생각했던 기준은
“어디서든 동일한 실시간 상태를 공유해야 한다”는 점이었다.

이를 만족하기 위해 다음과 같은 요구사항을 고려했다.

1️⃣ 이벤트 시작/종료 여부

2️⃣ 실시간 알림

3️⃣ 페이지 이동과 무관하게 유지되어야 하는 상태

이런 조건을 충족하려면 특정 페이지나 컴포넌트에 종속되지 않는 상태 관리 방식이 필요했다.
그래서 소켓 연결과 UI 관련 상태를 전역 상태로 관리하는 방식을 선택했다.

한 번 연결된 소켓을 여러 컴포넌트에서 공유하고
실시간 이벤트에 따라 UI를 즉시 반영하는 구조가 필요했기 때문이다.

이에 따라 다음과 같은 구조를 설계했다.

  • Socket 인스턴스를 store에 저장

  • 실시간 이벤트를 store에서 직접 처리

  • 컴포넌트는 전역 상태를 구독해 UI만 렌더링

구조적으로는 다음과 같은 역할 분리를 의도했다.

  • store → 실시간 이벤트 수신, 상태 변경

  • 컴포넌트 → 상태에 따른 UI 표현

이 방식은 구현 초기에는 꽤 직관적이었다.

어느 페이지에서든 동일한 이벤트 상태를 공유할 수 있었고
페이지 이동과 무관하게 실시간 토스트 알림도 전역으로 제어하는 것도 자연스러웠다.


이후 느낀 문제점

1️⃣ 전역 상태의 책임이 점점 커짐

이벤트 종류가 늘어날수록 store가 계속 비대해질 가능성이 보였다.
모든 실시간 이벤트가 한 store에 몰리면서 결과적으로 단일 store가 과도한 책임을 떠안게 되는 구조가 될 위험이 있었다.

2️⃣ 소켓 연결 관리의 복잡성

store마다 io()를 호출하는 구조이다 보니 의도와 달리 소켓 연결이 여러 개 생성될 가능성이 있다는 점을 인지하게 됐다.

3️⃣ UI 상태와 이벤트 로직이 강하게 결합됨

토스트 UI 자체가 전역 상태에 포함되어 있어 다른 종류의 실시간 알림(공지, 시스템 메시지 등)이 추가될 경우 구조를 다시 고민해야 하는 상황이 될 수 있었다.

즉, 이벤트 로직과 UI 표현이 얽혀 있는 상태였다.


리팩토링 방향

현재 구조에서는 이벤트 종류가 늘어나면 유지보수가 어렵워질 것이라 판단했고,
리팩토링의 목표를 다음과 같이 정리했다.

  • 소켓 연결은 단 하나의 인스턴스로 관리

  • 이벤트 수신과 UI 상태를 느슨하게 분리

  • 전역 상태는 ‘필요한 최소한의 상태’만 유지

1️⃣ Socket Manager 분리

소켓의 생성 / 연결 / 해제를 전담하는 모듈을 별도로 분리하고 store에서는 소켓 인스턴스를 직접 생성하지 않도록 구조를 변경하려 한다.

이를 통해 소켓 연결 책임을 한 곳에 모으고 실제 인스턴스가 하나만 유지된다는 보장을 할 수 있도록 한다.

2️⃣ 이벤트 단위로 책임 분리

  • 서버의 도메인 이벤트 수신 → handler 함수
  • UI에 필요한 상태 변경 → store

이처럼 역할을 분리하면
이벤트가 늘어나도 구조가 쉽게 무너지지 않고 특정 이벤트 로직만 교체하거나 확장하기 수월해질 것이라 판단했다.

3️⃣ Toast는 UI 전용 상태로 명확히 분리

"실시간 알림"이라는 개념과 "토스트 UI"를 분리하려 한다.
이렇게 하면 추후 모달, 배너, 시스템 알림 등 다른 형태의 UI로 확장이 자연스러워진다.


마무리

이번 경험을 통해 전역 상태는 분명 편리하지만 그만큼 책임도 빠르게 커진다는 점을 실감했다.

또 “지금 잘 동작하는 구조”와 “확장 가능한 구조로 잘 동작하는 것”은 전혀 다른 문제이고 그래서 구조와 책임을 먼저 고민하는 것이 중요하다는 것을 다시 체감했다.

이번 리팩토링은 단순히 코드를 정리하는 작업이 아니라 상태 관리와 실시간 이벤트를 어떻게 바라볼 것인가에 대한 고민이 될 것이다.

앞으로 비슷한 기능을 구현할 때는 정말 이 상태가 전역으로 관리되어야 하는지 한 번 더 고민하는 습관을 들이려 한다.

0개의 댓글