Airbnb의 더 빠른 웹/앱서비스 개선을 위한 방법
예전에 Airbnb 블로그에 올라온 Server-Driven UI 라는 글을 읽게 되었는데, 꽤 많은 고민이 들어가 있고 흥미로워서 간단하게 소개해볼까 합니다. 원문이 자세하게 설명하고 있으므로 관심있으시면 한번 읽어 보시는 걸 추천드립니다. Server-Driven UI (SDUI) 는 말 그대로 화면에 보여지는 UI 렌더링을 클라이언트가 아닌 서버위주로 진행한다는 의미입니다.
이러한 것은 예전부터 니즈는 많았습니다. 특히나 Web은 그 특성 상 배포 결과가 바로 반영될 수 있기 때문에 앱 서비스에서 이러한 요구사항이 많았죠. 빠르게 UI를 변경시키고 싶은데, 그렇게 하려면 새로 버전 업데이트를 해야 하고 앱 스토어나 마켓의 심사 때 걸리는 시간 등 때문에 그런 걸 보완하기 위해서 서버에서 내려주는 데이터에 따라서 UI를 변경시키는 경우가 꽤 있었습니다.
이러한 니즈 때문에 React Native의 CodePush 와 같은 기능을 사용하거나, 하이브리드 플랫폼 기반으로 개발하는 경우도 있었습니다. 하지만 일반적으로 이런 방법들은 불안정하기도 하고 기능도 제한적이라서 Enterprise급에서 많이 선택되지는 않는 편이었죠. Airbnb에서는 앱 뿐만 아니라 Web에서도 통일된 UI 시스템인 Ghost Platform을 만들고 이에 관한 설명을 하고 있습니다.
기존에는 렌더링이 대부분 서버에서 응답한 data를 클라이언트에서 그에 맞게 그려주는 형태였는데, 여러 클라이언트마다 파편화되는 문제도 있으며, flexible 하지 않다는 문제가 있습니다. 가장 큰 문제는 모바일인데, 앱은 UI 변경을 위해서는 새로 릴리즈 해야 하며 업데이트가 되기 전까지 사용자는 그 내용을 볼 수가 없습니다.
SDUI에서는 데이터와 UI 값을 함께 내려주게 됩니다. 또한 Airbnb의 Ghost Platfrom (GP) 에서는 Web/iOS/Android 가 동일한 backend response로 처리되게 됩니다. 또한 모두 동일한 GraphQL schema를 사용하게 됩니다. 이렇게 모든 플랫폼이 동일한 응답을 이용하여 처리가능한 universal schema 를 만들기 위해서 공을 많이 들였다고 합니다.
참고로 GP의 이름이 Ghost인 이유는 Guest + HOST 입니다. 참 Airbnb스러운 작명센스네요. ㅎㅎ
GP는 두 가지의 주된 요소가 있습니다. Section과 Screen 입니다. 아래와 같은 형태입니다.
Section은 가장 원시적인 구성 요소이며, UI component 를 표현하는 데이터로 어떤 데이터가 표현이 될지도 함께 가지고 있습니다. 이러한 데이터들은 서버에서 응답할 때 부터 미리 처리가 다 되어 있다고 합니다. 즉, 번역이 필요하다면 번역된 값으로, i18n 처리도 다 되며 포맷도 다 맞추어서 내려준다고 합니다. 클라이언트는 단지 이 값을 UI에 렌더링 할 뿐입니다.
GP의 응답은 여러개의 Screen 을 포함하고 있으며 각각은 어떻게 화면과 레이아웃이 어떻게 보여질지를 명시하게 됩니다. 추가로 다른 메타데이터들과 로깅 등에 대한 정보도 담고 있다고 합니다. 이 값들을 이용하여 Section을 어떻게 렌더링할지, 그리고 모달을 어떻게 띄울지나 popover는 어떻게 보여질지 등에 대해 알 수 있습니다.
모든 section 값들이 SectionContainer로 객체로 리턴되며 아래 예시에 있는 것과 같은 SectionComponentType의 값에 따라 다르게 렌더링이 되도록 할 수도 있습니다. 예를 들어 enum 에 TITLE이나 PLUS_TITLE 같은 값이 있는데 타입 값에 따라서 다르게 렌더링이 됩니다.
아래와 같이 type 에 따라 다르게 렌더링 된다고 하네요.
이러한 section component 들은 각 플랫폼 별 native language (Typescript, Swift, Kotlin) 를 통해 구현되었다고 합니다. 이렇게 하면 특정 component 에 대해서 플랫폼별로 구현만 해놓으면 해당 component에 대한 구현/수정만 진행하면 되므로 테스트도 쉬워지고, backward compatibilty 등과 같은 것들도 더 쉬워지기 때문에 개발 생산성이 높아질 수 있을 것 같습니다. 물론 모든 컴포넌트를 다 구현을 해 주어야 하기도 하고 새로 컴포넌트가 추가되면 당연히 새로 구현을 해야 하기는 합니다.
안드로이드를 예로 들면 아래와 같은 Kotlin 코드 예시를 통해 section component를 네이티브 환경에 맞게 렌더링 하게 됩니다.
여기서 중요한 것은 Section의 data model 이 하나의 unique한 렌더링을 한다는 것입니다. 어떠한 context 없이도 렌더링이 되기 때문에 특정 기능에 종속되는 비즈니스 로직이 필요 없다고 합니다. 이러한 구조를 만드는 것은 많은 고민이 필요하기도 하고, 이러한 면에서 GP 자체가 다양하게 사용될 수 있는 것들을 염두에 두고 설계된 것 같다는 생각이 듭니다.
경험상 이러한 방향성은 좋기는 하지만 서비스를 운영하다 보면 커스터마이징 등이 필요한 케이스가 있게 되는데, 그럴 때 커스터마이징이 조금 더 불편할 수는 있을 것 같습니다. 하지만, 전체적인 구조의 장점을 생각하면 이는 큰 단점이 아니기 때문에 이렇게 설계하였을 것입니다.
ScreenContainer에 값이 들어있으며 화면, 레이아웃을 정의하며, section이 어떻게 들어갈지도 정의하게 됩니다. modal, popup, popover, full screen 등에 관한 정보도 담고 있다고 하며 아래와 같은 GraphQL 스키마를 가집니다.
여기서 레이아웃의 배치와 디테일한 정보 (desity, rotation, 그 외에 다양한 factor들) 은 ILayout 값에 의해서 결정이 된다고 하며, 아래와 같이 SectionDetail 값을 가지고 있는데 여기에 section data의 값들에 맞추어서 렌더링이 됩니다.
GP는 단순히 화면에 보이는 값만 내려주는 게 아닙니다. Event handling 도 제어 가능합니다. 즉, 사용자와 인터렉션 하는 UI의 action까지도 서버 응답 값을 통해서 dynamic하게 변경할 수 있다는 것입니다. 예를 들어서, 어떤 버튼을 눌렀을 때의 액션이나 카드 스와이핑과 같은 액션에 대해서 지정할 수 있습니다. 이는 아래 예시처럼 IAction이라는 schema로 정의한다고 합니다.
해당 schema로 받은 서버응답 값을 사용해서 action을 정의하게 됩니다. 아래는 안드로이드에서 어떻게 사용되는지에 관한 예시입니다.
위의 예시에서는 subtitle의 text를 클릭했을 때 지정된 IAction이 수행되는 형태의 코드입니다.
GP의 전체적인 과정을 다시 살펴보면, 아래 그림처럼 서버의 응답값을 받아서 section component를 만들고 여기에 user interaction을 추가하게 됩니다.
그런 다음에 위에서 설명한 것 처럼 전체적인 레이아웃을 정의하여 화면을 렌더링하게 됩니다.
GP는 아직 1년 정도밖에 되지 않은 시스템이라고 합니다. 하지만 이미 Airbnb 서비스의 여러 부분에서 사용되고 있다고 합니다. 앞으로 nested section에 관한 기능들을 추가 할 예정이며 디자인 툴 (Figma나 위지윅 에디터 등) 을 활용해 section이나 배치 등을 수정할 수 있는 no-code 형태로 확장을 할 계획을 가지고 있다고 합니다.
Airbnb는 오래 전부터 오픈소스에 굉장히 적극적이고 활발이 참여하고 있었으며 오픈소스 커뮤니티에 수 많은 기여를 하고 있었는데, 이번에 사용하고 있는 GP도 어느정도 안정화 되면 오픈소스로 공개하지 않을까요? 그렇지 않더라도 다른 곳에서도 비슷한 오픈소스 라이브러리도 여러가지 내놓지 않을까 싶네요.
사실 이러한 Server-driven UI는 예전부터 많은 회사들이 부분적으로 사용하기는 했습니다. A/B 테스팅과 같은 다양한 실험/테스트, 유저 별 최적화, 빠른 개선이라는 목적 자체도 거의 같았구요. 하지만 어떤 개발자든 생각 가능할 만한 비교적 간단한 수준이었고 복잡하고 거대한 구조를 전체적으로 플랫폼화 한 경우는 거의 없었습니다. (물론 원문에 써 있는 내용처럼 Airbnb도 아직은 부분적으로 사용한다고 합니다만)
회사별로 디자인 언어를 통일하는 경우도 많았는데, 거기에서 한발 더 나아가서 이렇게 플랫폼별로 동일하게, 그리고 동적으로 action을 포함한 UI가 변경되도록 하는 것은 많은 고민이 필요한 일입니다. Generic platform을 만들면, 거기 들어가는 많은 개발력도 문제지만 다양한 커스터마이징 니즈 때문에 흐지부지 되는 경우가 많기 때문입니다. 그냥 계획을 하고 간단한 수준으로 구현하는 것은 어려운게 아니지만, 다양한 시나리오를 고려하여 스키마를 고안하고 전체적인 구조를 만든 것을 보면 꽤 많은 고민을 해서 만든 시스템이라는 것이 느껴집니다.
앞으로 이러한 Server-driven UI가 대세가 될까요? 그건 아닐 것입니다. SDUI를 하려면 고려할 것도 많고 단점도 있기 때문입니다. 일반적으로 많은 서비스가 사용자 자체를 확보하는데 어려움을 겪는 편이며, 이러한 것들까지 고려할 만한 여유는 없는 경우가 많죠. 하지만 빠른 개선을 통해 MVP를 찾아 나가며 사용자를 늘리거나, 플랫폼별로 통일된 UI가 중요하거나 실험, 개선, 배포등이 매우 빠른 iteration 주기를 갖는 서비스라면 고려해 볼 만 할것 같습니다.
IT업종에서는 서비스 개선 속도가 가장 우선시 되는 요즘 추세를 봤을 때 앞으로는 이러한 형태로 설계되는 서비스들이 꽤 많이 늘어나지 않을까 하는 생각이 듭니다.