드디어 REST!
이제 REST(Representational State Transfer) 아키텍처 스타일을 다룰 때가 되었다. REST 스타일은 여러 스타일들을 조합하여 정의한 하이브리드 스타일이기 때문에, 이러한 조합의 근거(rationale)를 이해해야만 REST를 제대로 이해할 수 있다. 따라서 이 글에서는 REST로의 진화과정을 추적하면서, 각각의 진화가 필요한 이유, 즉 설계원칙과 그로 인하여 추가된 제약과 그 효과들을 설명하겠다.
인터넷 스케일의 아키텍처에서 시스템의 부패(decay)와 퇴보(regression)를 막는 것은 굉장히 어려운 일이다. 독립적 진화가능성(independent evolvability)은 이러한 문제를 해결하는데 필수적인 속성이라고 할 수 있다.
Client-Server 스타일은 관심사의 분리(separation of concerns) 원칙을 추구한다. 관심사가 분리되면 서로 간의 의존성이 줄어들게 되고, 독립적 진화 가능성의 기초를 탄탄하게 만들 수 있다. 이러한 이유로 웹의 요구사항에 처음 적용된 아키텍처 스타일이 바로 Client-Server 스타일이다.
클라이언트는 관심사가 고객이므로, 유저 인터페이스와 관련된 기능들을 담당한다. 클라이언트 컴포넌트가 유저 인터페이스의 기능만을 담당하므로 여러 플랫폼으로 이식(portability)하기 쉬워진다. 서버는 관심사가 데이터이므로, 데이터의 저장과 관련된 기능들을 담당한다. 서버는 유저 인터페이스에 대해 고려하지 않으므로 구현이 단순해지고, 그 결과 확장성(scalability)이 향상된다.
인터넷 규모의 아키텍처에서는 다양한 지점에서 문제가 발생할 수 있다. 따라서 시스템은 부분적인 장애(partial failures) 상황에서도 여전히 서버를 안정적으로 유지하는 것이 무엇보다도 중요하다. 시스템의 상태를 즉각적으로 이해하고 안정적으로 서비스가 유지되도록 만들기 위해서는 가시성(visibility), 신뢰성(reliability), 확장성(scalability) 등의 속성이 유지되어야 한다.
Stateless 스타일은 요청(request message)의 처리에 필요한 모든 정보가 요청 메시지에 포함되어야 함을 요구한다. 따라서 요청을 만드는 시점에 모든 정보가 있어야 하므로 클라이언트에서 애플리케이션의 상태까지 관리해야 한다. 따라서 서버는 상태를 가질 필요가 없으며, 서버가 일시적인 장애(partial failures)에서 복구될 때에도 애플리케이션의 상태를 복구할 필요가 없으므로 복구 과정이 단순해지며, 서버의 복구 이후에는 이전과 완전히 동일한 동작할 수 있게 된다. 따라서 신뢰성(reliability)이 향상되고 서버의 증설에서도 상태의 복제나 분배 등이 불필요하므로 확장성(scalability) 또한 향상된다. 더하여 모니터링 시스템은 하나의 요청 정보만으로도 충분히 상황을 파악할 수 있게 되어 전체 시스템의 가시성은 크게 향상된다.
이러한 이유로 REST 스타일을 완성하기 위해 두 번째로 채택된 스타일이 Stateless이다.
Stateless 스타일은 요청에 모든 정보를 담아야 한다는 제약이므로, 네트워크 성능을 저하시키는 스타일이라고 할 수 있다. 따라서 네트워크의 효율(network efficiency)을 높여서 이러한 네트워크 성능저하를 어느 정도 상쇄시킬 방안이 필요하다.
이때 등장해야 하는 스타일이 Cache이다. Cache가 적용된 시스템에서는 요청에 대한 응답을 캐시에 저장한 후, 미래의 요청에 대한 응답으로 캐시된 응답을 사용한다. 따라서 Cache는 컴포넌트 사이의 통신(interaction)을 부분적으로 혹은 완전히 제거할 수 있기에 네트워크 효율성(network efficiency), 확장성(scalability), 고객 체감 성능(user-perceived performance)을 개선시킬 수 있다.
이러한 이유로 세 번째로 도입된 스타일이 Cache이다.
REST와 다른 스타일의 가장 큰 차이가 바로 Uniform Interface 스타일의 유무이다. Uniform Interface 스타일은 범용성의 원칙(the engineering priciple of generality)을 추구하는데, 시스템의 모든 컴포넌트에 동일한 인터페이스를 적용해야 한다는 제약이 Uniform Interface의 핵심이며, 따라서 모든 통신(interaction)은 하나의 규약으로 이루어지게 된다.
단일 통신 규약으로 인하여, 전체 시스템은 단순해지고(simplicity) 가시성(visibility)은 높아진다.
시스템의 각각의 구성요소는 규약을 만족시키기 위한 구현 방식의 자유를 가지므로독립적 진화가능성(independent evolvability)을 얻게 된다. 예를 들어, Server와 Proxy가 완전히 다른 구현을 택했다고 하더라도 전체 시스템의 동작에는 전혀 영향을 주지 않는다.
이러한 Uniform Interface 스타일을 완성하기 위해서는 4개의 추가적인 제약을 따라야 한다.
리소스의 식별(Identification of resources)
표현으로 리소스 조작(Manipulation of resources through representations)
자기 서술적 메시지(Self-descriptive messages)
애플리케이션 상태 엔진인 하이퍼미디어(Hypermedia as the engine of application state)
이 4개의 추가적인 제약 모두는 데이터에 대한 제약이다. 그렇다면 REST는 왜 데이터에 이렇게 많은 공을 들였을까? 그 이유는 REST 스타일에서 데이터는 단순히 정보가 아니라 하나의 요소(element), 즉 시스템의 부품으로 기능하기 때문이다.
대부분의 아키텍처는 데이터를 캡슐화하고 그 결과를 노출할 뿐이지만, REST는 데이터를 하나의 부품으로 취급한다. 따라서 REST에서의 데이터는 단순히 소비되는 콘텐츠가 아닌 부품으로 승격되었다고 볼 수 있다. 이러한 이유로 데이터 부품은 그 자체로 정보의 역할을 수행하지만 동시에 애플리케이션의 역할 또한 수행한다. 이러한 애플리케이션으로써의 역할은 데이터 부품에 포함된 링크, 자바스크립트, 자바애플릿 등을 통해 이루어지게 된다.
REST 스타일은 정보 교환 시스템을 위한 아키텍처 스타일이며, REST는 교환 대상인 정보를 리소스로 추상화한다. 따라서 리소스의 식별 정보(위치 혹은 이름)는 굉장히 중요한 요소이며 지속성을 가져야만 그 가치를 극대화시킬 수 있다. 이렇게 중요한 리소스 식별자(resource identifier)는 정보 공유자(author)가 리소스의 본질에 가장 적합한 식별자를 부여하는 반면에, 기존의 하이퍼텍스트 시스템들은 정보가 변하면 식별자 또한 함께 변해야 하는 노드 번호 혹은 문서 번호 등을 사용했기 때문에, 링크의 수명 또한 길지 못한 특징이 있었다.
리소스로 대표되는 정보는 리소스의 표현(resource representation)이라고 불리는데, 표준 규격을 통해 정보를 노출(abstract)하기 때문에 과도한 상세함(파일 경로와 같은 변하기 쉬운 정보)을 억지로 노출할 필요가 없다. 더하여 REST의 모든 구성요소(즉 시스템의 부품)들은 Uniform Interface의 제약을 따르기 때문에, 이러한 리소스의 표현을 이해할 수 있다. 따라서 리소스의 표현은 REST에서 유비쿼터스 언어의 역할을 담당한다고 볼 수 있다.
이러한 리소스의 표현은 구성요소들 사이에 교환되어야만 하며, 이때 교환을 위해 오가는 메시지는 제어 정보(control data)와 리소스의 표현(resource representation)으로 구성된다. 그런데 REST는 stateless 스타일을 도입했기 때문에, 이러한 메시지는 자기 서술적(self-descriptive)하여야만 하며, 서버에 애플리케이션의 상태를 저장하지 않기 때문에 상태 정보는 온전히 클라이언트에서 관리되어야만 한다. 이러한 이유로 HATEOAS(Hypermedia As The Engine Of Application State)라고 불리는, "애플리케이션의 상태를 대변하는 하이퍼미디어"의 특징이 필요하다.
REST 스타일은 범용성의 원칙(principle of generality)을 따르기 위해 Uniform Interface 스타일을 도입하였으며, 모든 시스템의 구성요소가 엄격하게 이 원칙 하에서도 동작하도록 만들기 위해 4개의 추가적인 제약을 마련하였으며, 이 점이 바로 REST와 다른 스타일들의 가장 큰 차이임을 이해하게 되었다.
이제 우리는 왜 로이 필딩이 REST(REpresentational State Transfer)라는 이름을 고안하게 되었는지 충분히 이해하게 되었다.
인터넷 스케일의 환경에서는 수많은 변수들이 복합적으로 작용한다. 웹 사이트와 시스템의 구성요소는 우후죽순으로 생겨나기도 하고, 전혀 예상치 못한 과부하가 발생하거나, 잘못된 데이터가 전달되기도 하고 심지어 악의적인 데이터가 입력되기도 한다. 이러한 문제를 효과적으로 해결하기 위해서는 시스템이 단순성(simplicity) 을 유지하면서도 높은 가시성(visibility)을 제공하여, 모니터링을 용이하게 해야 한다. 또한, 필요한 보안(security) 절차를 쉽게 추가할 수 있는 기능 확장성(extensibility)과 성능 확장성(scalability)을 확보할 수 있어야 한다.
이러한 필요한 변화를 쉽고 유연하게 만들어내기 위해서는 시스템의 전체적인 복잡도를 낮추고, 시스템 사이의 의존성(dependency)을 최소화해야 한다. Lyaered System 스타일은 각 레이어가 인접한(immediate) 레이어만 볼 수 있다는 제약을 추가함으로써 이러한 목표를 달성한다. 결과적으로, 모든 구성요소는 오직 하나의 레이어에 대한 지식만을 가지게 되어 각 시스템의 독립성(substrate independence)이 강화된다.
레이어들 사이에는 중재자(intermediaries)가 도입될 수 있으며, self-descriptive 메시지는 중재자가 메시지를 어떻게 처리해야 할지 쉽게 이해하는데 결정적인 도움을 준다. 따라서 중재자는 메시지의 맥락에 맞게 캐시(cache) 처리를 하거나, 로드 밸런싱을 수행하거나, 시스템을 보호하기 위한 방화벽의 역할을 하여 공통의 관심사를 처리하는 장소로 기능할 수 있다.
드디어 REST 스타일의 마지막 요소인 Code on Demand 스타일이다.
클라이언트의 기능은 코드를 다운로드 받음으로써 확장될 수 있으며, 이로 인하여 클라이언트는 단순성을 유지할 수 있게 된다. 다만 다운로드된 코드가 어떠한 행위를 할지 예측할 수 없기 때문에 가시성(visibility)이 낮아진다. 이러한 이유로 인해 Code on Demand는 선택적(optional) 제약이다. 선택적이라는 말은, 이 제약이 제공하는 이점이 분명한 경우에만 도입해야 한다는 의미를 내포하고 있다.
이 장에서는 분산 하이퍼미디어 시스템(distributed hypermedia system)을 위한 REST(Representational State Transfer) 아키텍처 스타일을 살펴봤다.
지금까지의 여정을 정리하자면, Client-Server 스타일을 통해 Separation of Concerns를 달성하여 부분적 진화가능성을 향상시키고, Stateless로 서버의 상태관리 부담을 제거했을 뿐만 아니라 구성요소들의 상호작용을 명쾌하게 만들었다. Stateless로 인한 네트워크 부담은 Cache 스타일을 통해 네트워크 효율을 향상시키는 접근법을 택했다. Uniform Interface 스타일을 통해 모든 컴포넌트가 동일한 언어를 사용하도록 강제함으로써, 시스템의 누구라도 이해할 수 있는 자기 서술적(self descriptive) 메시지에 기반하는 스타일로 진화시켰다. Layered System 스타일은 시스템의 부분적 진화에 누구나 참여할 수 있는 창발성을 부여하였다. 끝으로 전체 시스템의 가시성을 일부 저해하더라도 코드를 이동시킬 수 있는 특수성이라는, Code On Demand 스타일을 도입하였다.
즉, REST는 Uniformed Layered Client-Stateless Server with Code on Demand라는 하이브리드 스타일로 탄생하게 되었다.
이 글을 쓰는 과정은 로이 필딩이 이미 정제해서 전달해 준 메시지가 있음에도 불구하고, 무엇을 전하고 숨길 것인가(abstraction)에 대한 갈등의 연속이었다. 그만큼 방대한 내용을 다루는 논문이었기에 그 내면에 숨은 가치(rationale behind the paper)를 모두 전달하는 것은, 최소한 나에겐 쉽지 않은 도전이었던 것 같다.
이것으로 로이 필딩의 REST 논문 읽기를 끝내려 한다. 로이 필딩이 그랬던 것처럼, 나 역시 이 글의 마지막을 크리스토퍼 알렉산더의 통찰로 마무리하고자 한다.
Each one of us has, somewhere in his heart, the dream to make a living world, a universe. Those of us who have been trained as architects have this desire perhaps at the very center of our lives: that one day, somewhere, somehow, we shall build one building which is wonderful, beautiful, breathtaking, a place where people can walk and dream for centuries.
-- Christopher Alexander