UI 요소의 정보를 담은 자바스크립트 객체를 반환한다는 아이디어는 거대한 돌파구였다. 조던 워크는 며칠 밤낮으로 키보드를 두드리며 이 개념을 구체화하기 시작했다. 그는 이 모든 것의 중심에 놓일 하나의 공식을 화이트보드에 큼지막하게 적었다.
UI = render(data)
이것은 그의 새로운 라이브러리가 지향할 단 하나의 목표이자, 모든 복잡성을 해결할 열쇠였다. 그는 이 공식을 실제로 동작하게 만들 시스템을 설계하기 시작했다. 시스템은 크게 두 부분으로 나뉘었다.
render
함수 (개발자가 작성하는 부분)
개발자는 더 이상 jQuery로 DOM을 조작하거나 백본의 뷰를 상속받지 않는다. 대신, 데이터를 인자로 받아 UI 설명서 객체를 반환하는 단순한 자바스크립트 함수들을 작성한다. 이 함수들이 바로 render
의 실체, 즉 ‘컴포넌트’다.
조던은 간단한 ‘사용자 프로필’ 컴포넌트를 예시로 작성해 보았다.
// 프로토타입 코드
// Profile 컴포넌트 함수
function Profile(userData) {
// 컴포넌트는 다른 컴포넌트를 호출하여 조립할 수 있다.
var profilePic = ProfilePicture({ src: userData.avatarUrl });
var userName = UserName({ name: userData.name });
// 최종적으로 UI '설명서'를 반환한다.
return createDescription('div', { className: 'profile' }, [
profilePic,
userName
]);
}
이 코드는 지극히 선언적이다. ‘프로필은 프로필 사진과 사용자 이름으로 구성된다’고 선언할 뿐, 이것을 화면에 ‘어떻게’ 그려야 하는지에 대해서는 한마디도 하지 않는다.
- 라이브러리 (조던이 만들어야 하는 부분)
진정한 마법은 보이지 않는 곳에서 일어난다. 조던이 만들 라이브러리는 개발자가 작성한 render
함수를 받아, 실제로 화면에 UI를 그려주는 복잡한 작업을 모두 책임져야 했다.
그 과정은 다음과 같이 설계되었다.
- 개발자가 최상위
render
함수(예:Profile
)와 초기 데이터(initialUserData
)를 라이브러리에 전달하며 실행을 요청한다. - 라이브러리는
Profile(initialUserData)
를 호출한다. Profile
함수는 내부적으로ProfilePicture
와UserName
함수를 호출하고, 그 결과물들을 조합하여 최종적인 ‘UI 설명서 객체 트리’를 만들어 반환한다.- 라이브러리는 이 설명서 트리를 해석하여, 처음으로 실제 DOM 요소(
<div>
,<img>
등)들을 생성하고 화면에 그려준다.
여기까지는 최초의 렌더링 과정이다. 진짜 도전은 데이터가 변경되었을 때 시작된다.
- 사용자의 이름이 바뀌어 새로운 데이터
newUserData
가 생성되었다. - 개발자는 라이브러리에 ‘데이터가 바뀌었으니 업데이트해줘’라고 알리기만 하면 된다. (
library.update(newUserData)
) - 라이브러리는 다시
Profile(newUserData)
를 호출하여, 새로운 ‘UI 설명서 객체 트리’를 얻는다. - 바로 이 순간. 라이브러리는 이 새로운 설명서 트리를 화면에 무작정 덮어쓰지 않는다. 대신, 이전에 저장해 두었던 옛날 설명서 트리와 비교하는 작업을 시작한다.
- 두 트리를 비교하여, 정확히
UserName
컴포넌트의 결과물만 바뀌었다는 사실을 찾아낸다. - 라이브러리는 오직 그 바뀐 부분에 해당하는 실제 DOM 요소 하나만을 찾아가 내용을 수정한다.
톰과 몇몇 동료들이 조던의 화이트보드 앞에 모여 그의 설명을 들었다. 톰이 가장 핵심적인 질문을 던졌다.
“결국, 개발자는 더 이상 DOM에 대해 전혀 신경 쓰지 않아도 된다는 거군요. 오직 데이터와, 그 데이터를 UI로 변환하는 render
함수에만 집중하면 되는 거고요.”
“정확합니다.” 조던이 대답했다. “개발자는 매번 이상적인 최종 결과물만 선언하면 됩니다. 그 결과물을 현실 세계에 최소한의 비용으로 반영하는 더럽고 힘든 일은, 전부 라이브러리가 맡는 거죠.”
회의실에 있던 모두는 이 아이디어가 가진 엄청난 잠재력을 직감했다. 이것이 성공한다면, 프론트엔드 개발의 패러다임이 완전히 뒤바뀔 터였다. 복잡한 이벤트 리스너도, 꼬리에 꼬리를 무는 업데이트도, 상태의 불일치도 모두 사라질 것이다.
오직 UI = render(data)
라는 명징한 공식만이 남는다. 이제 남은 것은, 이 거대한 약속을 실제로 구현해내는 험난한 과정뿐이었다.