상태는 어디에 있는가?

92025년 08월 24일4

맷은 채팅창의 깜빡임 버그를 해결하기 위해 며칠 밤낮으로 매달렸다. 그는 결국 이벤트의 연쇄 반응을 정리하고 순서를 제어하는 복잡한 로직을 추가하여 문제를 해결했다. 코드는 전보다 훨씬 더 보기 흉해졌지만, 어쨌든 버그는 잡았다.

하지만 안도의 한숨을 내쉰 것도 잠시, 새로운 요구사항이 그의 앞에 떨어졌다.

“채팅창에서 사용자 이름을 클릭하면, 그 사람의 간단한 프로필 정보를 보여주는 작은 팝업(Pop-up)을 띄워주세요.”

간단해 보이는 기능이었다. 맷은 늘 하던 대로 백본(Backbone.js)의 뷰를 활용했다. ChatUserView에 클릭 이벤트를 추가하고, 클릭이 발생하면 팝업을 보여주는 코드를 작성했다.

여기서 문제가 발생했다. ‘팝업이 열려있는지, 닫혀있는지’에 대한 정보, 즉 이 UI의 상태(State)를 어디에 저장해야 할까?

첫 번째 선택지는 UserModelisProfilePopupOpen: true 같은 속성을 추가하는 것이었다. 하지만 이건 말이 안 됐다. 사용자의 프로필 정보라는 본질적인 데이터 모델에, 단순히 UI의 표시 여부를 저장하는 것은 모델의 순수성을 해치는 일이었다.

결국 맷은 두 번째 선택지를 택했다. ChatUserView 객체 자체에 새로운 속성을 추가하는 것이었다.

// ChatUserView 내부 코드 (개념)
var ChatUserView = Backbone.View.extend({
  
  initialize: function() {
    // 뷰가 처음 만들어질 때, 팝업은 닫혀 있는 상태.
    this.isPopupOpen = false; 
  },

  events: {
    'click .username': 'togglePopup'
  },

  togglePopup: function() {
    this.isPopupOpen = !this.isPopupOpen; // 뷰의 상태를 직접 변경
    this.render(); // 상태가 바뀌었으니 다시 그린다
  },

  render: function() {
    // ... 기존 렌더링 코드 ...
    if (this.isPopupOpen) {
      // 팝업을 보여주는 HTML을 추가
    }
  }
});

이제 상태는 두 곳에 나뉘어 존재하게 되었다. 애플리케이션의 핵심 데이터(사용자 이름, 온라인 여부)는 Model에, 그리고 UI의 일시적인 상태(팝업 표시 여부)는 View에 저장되었다. ‘진실의 원천(Single Source of Truth)’이라는 백본의 이상이 깨지기 시작한 순간이었다.

이 작은 균열은 곧 거대한 균열로 이어졌다.

며칠 뒤, 또 다른 버그 리포트가 접수되었다.
[버그] 채팅창: 프로필 팝업을 열어놓은 상태에서 다른 채팅방으로 이동하면, 이전에 열어뒀던 팝업이 사라지지 않고 화면에 그대로 남아있는 문제.

원인은 명확했다. 다른 채팅방으로 이동할 때, ChatRoomModel의 데이터는 바뀌었지만, ChatUserViewisPopupOpen 상태는 아무도 건드려주지 않았기 때문이다. 뷰가 자신만의 독립적인 상태를 가지기 시작하면서, 전체 시스템의 통제에서 벗어난 것이다.

이 문제를 해결하기 위해, 이제 ChatRoomView(상위 뷰)는 채팅방이 바뀔 때마다 모든 자식 뷰인 ChatUserView를 일일이 찾아다니며 “얘들아, 혹시 팝업 열려 있으면 다 닫아라!” 라고 직접 명령을 내려야만 했다.

this.subviews.forEach(view => view.closePopup());

이 코드를 작성하던 맷은 등골이 서늘해지는 것을 느꼈다. 이건 jQuery 시절의 악몽과 다를 바 없었다. 상위 객체가 하위 객체의 내부 구현을 속속들이 알아야 하고, 직접 상태를 변경하도록 명령하는 방식. 그들이 벗어나려고 발버둥 쳤던 바로 그 패턴으로 회귀하고 있었다.

그의 뒤에 서서 이 모든 과정을 지켜보던 조던 워크가 입을 열었다. 그의 목소리는 그 어느 때보다 진지했다.

“우리의 근본적인 질문이 틀렸습니다, 맷.”

“네?”

“우리는 계속 ‘상태를 어디에 둬야 할까?’ 라고 묻고 있어요. 모델에 둘까, 뷰에 둘까. 하지만 진짜 질문은 이것이어야 합니다. ‘애플리케이션의 모든 상태를 단 한 곳에만 둘 수는 없을까?’”

조던의 눈빛은 흔들림이 없었다.

“사용자 데이터, 채팅방 정보, 심지어 어떤 팝업이 열려있는지 같은 아주 사소한 UI 상태까지 전부. 모든 것을 단 하나의 거대한 데이터 덩어리로 관리하는 겁니다. 그러면 뷰는 아무런 상태도 가질 필요가 없어요. 그저 그 거대한 데이터를 보고 자신을 그리는 역할만 충실히 하면 되는 거죠. 생각도, 기억도 없는 껍데기처럼요.”

모든 상태의 중앙 집중화.
그것은 너무나 거대하고, 급진적인 아이디어였다. 하지만 맷은 그 혼란스러운 아이디어 속에서, 자신들이 겪고 있는 문제의 본질을 관통하는 날카로운 통찰력을 느낄 수 있었다. 상태가 흩어져 있기에 예측이 불가능하다면, 하나로 모으면 된다. 지극히 단순하지만, 아무도 시도하지 않았던 발상이었다.