XHP와 컴포넌트 기반 개발 방식은 페이스북의 서버 사이드 코드를 송두리째 바꿔놓았다. <ui:post>
, <ui:comment-box>
, <ui:photo-grid>
와 같은 재사용 가능한 UI 부품들이 라이브러리에 차곡차곡 쌓여갔다. 개발자들은 이제 복잡한 HTML 구조를 고민하는 대신, 마치 레고 블록을 조립하듯 이 부품들을 가져다 쓰기만 하면 됐다. 생산성은 극적으로 향상되었고, 코드의 안정성은 비교할 수 없을 만큼 높아졌다.
“정말 놀라워요.”
신입 개발자 한 명이 감탄하며 말했다. “마치 잘 설계된 API를 쓰는 기분이에요. <ui:post>
에게 게시물 데이터만 넘겨주면, 알아서 완벽한 HTML을 만들어주니까요.”
그러나 이 성공의 이면에는 누구도 선뜻 입 밖에 내지 못하는, 거대한 숙제가 남아있었다. XHP는 어디까지나 PHP, 즉 서버의 영역에서만 작동하는 마법이었다.
페이지가 최초로 로딩된 이후, 사용자의 브라우저 안에서 일어나는 모든 동적인 상호작용은 여전히 원시적인 자바스크립트와 jQuery의 차지였다.
맷은 ‘좋아요’ 버튼을 클릭했을 때, 서버와 통신하지 않고 즉시 버튼의 텍스트를 ‘좋아요 취소’로 바꾸는 기능을 구현하고 있었다. 서버 사이드 코드는 더없이 우아했다.
// PHP (XHP)
<ui:like-button postID={$post->id} />
문제는 클라이언트 사이드, 즉 자바스크립트 파일에서 발생했다.
// JavaScript (jQuery)
// 'ui-like-button' 클래스를 가진 모든 버튼에 클릭 이벤트를 등록한다.
$('.ui-like-button').on('click', function () {
var button = $(this);
var postID = button.attr('data-post-id'); // 'data-post-id' 속성 값을 읽는다.
if (button.hasClass('liked')) {
// ... 좋아요 취소 로직 ...
button.text('좋아요');
button.removeClass('liked');
} else {
// ... 좋아요 로직 ...
button.text('좋아요 취소');
button.addClass('liked');
}
});
이 코드는 작동했다. 하지만 치명적인 문제를 안고 있었다. 자바스크립트 코드는 <ui:like-button>
컴포넌트의 내부 구현을 너무나 잘 알고 있어야만 했다. ‘이 컴포넌트는 ui-like-button
이라는 클래스 이름을 가질 것이고, data-post-id
라는 속성에 게시물 ID를 담고 있을 것이다’ 라는 사실을 전제로 작성된 것이다.
만약 서버 사이드에서 누군가 <ui:like-button>
컴포넌트의 내부 구조를 조금이라도 바꾼다면? 예를 들어 클래스 이름을 ui-new-like-button
으로 변경하거나, data-post-id
속성 이름을 data-identifier
로 바꾼다면, 이 자바스크립트 코드는 즉시 먹통이 되어버린다.
서버에서는 완벽하게 캡슐화되어 있던 컴포넌트가, 클라이언트 사이드에서는 그 내부가 속절없이 파헤쳐지고 의존성이 생기는 모순적인 상황이었다.
이 문제는 곧 현실이 되었다.
디자인팀의 요청으로 ‘좋아요’ 버튼의 구조가 미세하게 변경되자, 서버 담당 개발자는 <ui:like-button>
컴포넌트의 PHP 코드만 수정했다. 당연히 아무에게도 알리지 않았다. 컴포넌트의 장점은 내부를 몰라도 쓸 수 있다는 것이었으니까.
그러나 그 코드가 배포된 직후, ‘좋아요’ 기능 전체가 마비되었다. 클라이언트 사이드의 jQuery 코드가 더 이상 변경된 HTML 구조를 찾지 못했기 때문이다.
회의실에서 톰이 이마를 짚으며 말했다.
“이건 미친 짓이야. 서버와 클라이언트가 같은 컴포넌트를 두고 서로 다른 언어로, 서로 다른 방식으로 이야기하고 있어. 하나를 고치면 반드시 다른 쪽도 함께 고쳐야만 해.”
그 자리에 있던 조던 워크는 조용히 생각에 잠겨 있었다. 그는 이 문제의 본질을 꿰뚫어 보고 있었다.
서버(PHP)와 클라이언트(JavaScript)의 분리. 이것이 문제였다. 기술의 분리가 관심사의 분리가 되어야 하는데, 오히려 개발의 분열을 낳고 있었다.
‘하나의 컴포넌트는 하나의 언어로, 하나의 방식으로만 정의되어야 한다.’
그의 머릿속에 새로운 질문이 싹텄다.
‘XHP가 이뤄낸 이 컴포넌트의 철학, 이 아름다운 개념을… 그대로 자바스크립트의 세계로 가져올 수는 없을까? 서버와 클라이언트가 같은 설계도를 공유하게 만들 수는 없을까?’
그것은 단순히 남겨진 숙제를 푸는 수준이 아니었다. 웹 개발의 근본적인 패러다임을 바꾸려는, 거대한 도전의 서막이었다.