거인의 그림자

12025년 08월 16일3

2016년, 캘리포니아 멘로 파크.
세상의 혁신을 이끈다는 페이스북의 캠퍼스는 그 명성만큼이나 자유로운 에너지로 가득했다. 내리쬐는 햇살 아래, 직원들은 캠퍼스를 자전거로 누비거나 야외 테이블에 앉아 노트북을 두드렸다. 이곳은 단순한 회사가 아니었다. 세상을 연결하겠다는 거대한 야망이 살아 숨 쉬는, 하나의 작은 실리콘밸리였다.

그 풍경 속을, 한 젊은 개발자가 걷고 있었다.
댄 아브라모프(Dan Abramov).
그의 이름 앞에는 이미 ‘Redux의 창시자’라는 화려한 수식어가 붙어 다녔다. 복잡하기 짝이 없던 프론트엔드 상태 관리에 ‘예측 가능한’이라는 질서를 부여한 남자. 그의 라이브러리는 페이스북 담장을 넘어, 전 세계 리액트(React) 개발자들의 코드에 성스러운 경전처럼 스며들었다.

댄은 자신의 창조물이 이룬 성공에 조용한 자부심을 느꼈다. 그러나 최근, 그의 마음속에는 설명하기 힘든 미세한 균열이 감지되고 있었다.
버그가 아니었다. 성능 저하도 아니었다.
세상에서 가장 진보한 코드가 모인다는 이곳의 코드베이스를 들여다볼수록, 그는 거대하고 단단한 벽에 가로막힌 듯한 답답함을 느꼈다. 그 벽은 너무나 견고해서 누구도 의심하지 않았지만, 그의 눈에는 어딘가 비효율적인 그림자가 어른거렸다.

자리로 돌아온 댄은 습관처럼 코드 에디터를 열었다. 화면에 떠오른 파일은 수백만 명이 매일같이 사용하는 페이스북의 한 기능, UserProfile.js였다.

코드는 단 한 줄의 오차도 없이 완벽하게 작동했다.
하지만 아름답지는 않았다.

class UserProfile extends React.Component { ... }

모든 것이 이 한 줄에서 시작되었다. 클래스(Class).
리액트의 세계를 지탱하는 가장 기본적이고도 강력한 설계도. 그것은 마치 잘 지어진 성채와 같았다. 외부의 공격으로부터 데이터를 안전하게 지키고, 정해진 규칙에 따라 성문을 열고 닫으며 자신의 임무를 훌륭하게 수행했다.

댄의 손가락이 스크롤 휠 위에서 천천히 움직였다.
눈이 쫓는 코드의 흐름은 논리적으로는 타당했지만, 어딘가 부자연스러웠다.

사용자 정보를 화면에 처음 보여주기 위해, componentDidMount라는 메서드 안에서 여러 개의 네트워크 요청이 뒤섞여 있었다. 프로필 정보를 가져오는 코드, 친구 목록을 가져오는 코드, 실시간 상태를 구독하는 코드가 한데 엉켜 각자의 일을 시작했다.

그런데 사용자의 이름이 바뀌면, componentDidUpdate라는 또 다른 메서드에서 이름과 관련된 부분만 다시 실행해야 했다. 실시간 상태 구독을 시작했다면, 사용자가 페이지를 떠날 때 componentWillUnmount라는 전혀 다른 공간에서 구독을 해지하는 코드를 잊지 말아야 했다.

‘프로필 정보’라는 하나의 관심사가 ‘Mount’, ‘Update’, ‘Unmount’라는 세 개의 다른 시간과 공간에 흩어져 있었다. 마치 한 요리를 완성해야 하는데, 재료들이 주방의 각기 다른 서랍에 제멋대로 흩어져 있는 것과 같았다.

“작동은 하지.”
댄은 나지막이 읊조렸다.
“하지만 이게 최선일까?”

이것은 단지 UserProfile.js 파일 하나만의 문제가 아니었다. 리액트로 만들어진 수많은 거대 애플리케이션이 공통으로 앓고 있는 성장통이었다. 컴포넌트가 복잡해질수록, 코드는 거미줄처럼 얽혀 그 누구도 전체 그림을 쉽게 파악할 수 없게 되었다.

이 거대한 성채, 클래스라는 이름의 거인은 리액트를 세상의 중심으로 만들었지만, 동시에 그 자신의 무게에 짓눌리고 있었다.

댄의 시선이 다시 모니터의 첫 줄에 머물렀다.
그의 머릿속에 조용한 질문 하나가 떠올랐다.

‘우리가 세운 이 거대한 성벽에, 정말 다른 문은 없는 걸까?’

그 작은 질문이, 곧 리액트의 심장을 뒤흔들 거대한 혁명의 시작이 될 것임을 그 순간, 아무도 알지 못했다.