수개월간의 긴밀한 협업 끝에, 마침내 그날이 왔다. Next.js 13이 세상에 공개되었다. 그리고 그 중심에는 React 팀의 비전이 고스란히 녹아있는 ‘App Router’가 있었다. 폴더 기반 라우팅, 기본이 되는 서버 컴포넌트, 'use client'
지시어까지. React 19의 핵심 사상이 처음으로 대중 앞에 그 모습을 드러낸 순간이었다.
초기 반응은 폭발적이었다.
트위터와 기술 블로그는 ‘혁신’이라는 단어로 들끓었다. 데이터베이스에 직접 접근하는 컴포넌트 코드 스니펫이 공유되며 개발자들은 열광했다.
“API 레이어가 사라졌다! 이게 개발의 미래다!”
“컴포넌트 단위로 로딩 상태를 관리하다니, Suspense의 진정한 힘이 이제야 드러나는군.”
하지만 그 뜨거운 열기는 금세 거대한 혼란의 소용돌이로 바뀌었다.
React Core Team의 멤버들은 실시간으로 쏟아지는 커뮤니티의 반응을 예의주시하고 있었다. 그들의 화면에는 찬사만큼이나 날 선 비판과 근본적인 질문들이 가득했다.
“잠깐, 이게 정말 React 맞아? 내가 알던 React랑은 너무 다른데.”
한 유명 개발자의 트윗은 수많은 개발자들의 공감을 얻었다. 그들에게 React는 클라이언트 라이브러리였다. useState
와 useEffect
로 상태와 상호작용을 관리하는 것이 그들의 멘탈 모델이었다. 그런데 이제는 서버와 클라이언트를 넘나들고, async/await
가 컴포넌트 함수에 자연스럽게 등장했다. 너무나 낯선 모습이었다.
“컴포넌트 안에서 fetch
를 쓰라고? 지난 5년간 useEffect
안에서만 데이터를 가져오라고 배웠는데, 이제 와서 규칙을 바꾸는 건가?”
“'use client'
는 대체 뭐야? 모든 걸 클라이언트 컴포넌트로 만들면 예전이랑 똑같은 거 아닌가? 언제 서버를 쓰고, 언제 클라이언트를 써야 하는지 기준이 너무 모호해.”
혼란은 곧 불만으로 이어졌다. 가파른 학습 곡선에 지친 개발자들의 목소리가 터져 나왔다.
“이건 너무 복잡해. 예전의 단순했던 React가 그립다.”
React 팀의 회의실에는 무거운 침묵이 흘렀다. 그들은 이 정도의 반발을 예상하지 못했던 것은 아니었다. 패러다임의 전환에는 언제나 저항이 따르는 법이다. 하지만 쏟아지는 비판의 양과 깊이는 생각 이상이었다.
“우리가 실패한 걸까?”
한 엔지니어가 자조적으로 중얼거렸다.
“아니.”
침묵을 깬 것은 로렌 탄이었다. 그녀는 침착했지만 단호한 목소리로 말했다.
“기술이 실패한 게 아니야. 우리의 ‘소통’이 부족했던 거야. 우리는 개발자들에게 ‘무엇’이 바뀌었는지는 보여줬지만, ‘왜’ 바뀌어야만 했는지는 충분히 설명하지 못했어.”
그녀의 말은 정곡을 찔렀다. React 팀은 번들 사이즈, 네트워크 폭포수, 하이드레이션 병목이라는 문제의식을 수년간 공유하며 해답을 찾아왔다. 하지만 대다수의 개발자에게는 그 고뇌의 과정이 생략된 채, ‘서버 컴포넌트’라는 낯선 결과물만 툭 던져진 셈이었다.
그들은 자신들의 해결책이 얼마나 우아한지에 취해, 정작 그 해결책이 필요한 이유를 설명하는 데 소홀했던 것이다.
커뮤니티의 혼란은 실패의 증거가 아니었다. 그것은 앞으로 그들이 무엇을 해야 할지를 알려주는 가장 값진 피드백이었다. 코드뿐만 아니라, React 19의 철학과 멘탈 모델을 전달하기 위한 또 다른 차원의 노력이 필요했다. 소통의 중요성을 뼈저리게 깨닫는 순간이었다.