목요일, 7월 18

최근 웹 개발환경 이해 - 진보된 웹 환경 공부 #2 Restlet Framework



개요

지난 글 진보된 웹 환경 공부 #1 에서는 REST라는 설계 철학이 등장한 이유와 함께 그와 같은 설계와 함께 사용해야 하는 URI, JSON 등에 대한 개괄적인 설명을 다뤘습니다. 이번 글에서는 REST를 구현한 RESTful 서비스를 Restlet이라는 Framework를 사용하여 간단히 구현해보겠습니다.

그 전에 REST는 설계에 철학이 담겨있습니다.
제가 철학이라고 말하는 것은, 뭔가 거대 담론을 지칭하는 것은 아니고 단지 "이와 같은 설계를 통해 세상이 이렇게 되었으면 좋겠다." 라는 설계자의 바람이 느껴지는 것을 말합니다.

그렇다면 기존에는 어떤 설계를 사용했는지 그리고 이와 같은 설계의 한계점은 무엇인지 살펴보고 REST를 통해 어떻게 보다 더 좋은 방향으로 프로그래밍을 할 수 있는지 알아보는게 우선이라고 생각해서 이 부분을 추가했습니다.

해서 이 글은 이와 같은 순서로 작성됐으며, 이런 생각을 하시면서 읽으면 되실 것 같습니다.
1. 기존에 범용적으로 사용되던 Web Framework 개괄 설명
2. 1에서 다룬 Framework의 설계
3. 2의 문제점과 한계
4. REST의 개괄 설명은 생략 #1을 참고하세요
5. REST가 지향하는 설계철학
6. Code review
7. 결론 및 내용 요약

[ "기존에 사용되던 Framework의 한계점은 무엇이고 REST는 어떤 장점이 있으며, 어떻게 사용해야 하는가?" ]

Structs Framework

Structs는 2000년도 이전에 크레이그 맥클라나한(Craig McClanahan)에 의해 탄생했으며 MVC 패턴을 구현하기 위해 Java Servlet API를 사용했습니다. Structs외 이 당시 대부분의 Web-Framework는 거의 MVC 패턴을 사용했습니다.

Structs Framework가 사용하는 MVC 패턴의 문제

structs MVC model 2

 Structs에서는 MVC 패턴을 사용하는데 이는 Model-View 간의 결합도를 낮추기 위해서입니다. 객체지향에서 결합도를 낮추는 일은 매우 중요합니다.

 MVC model 2 는 비록 model 과 View 사이에 Bean을 두었지만 단순히 데이터를 주고 받는 매개자 역할을 했기 때문에 Model이나 View의 변화에서 자유롭지 못했습니다.

 그 외에 Server에서 최종적으로 반환하는 것이 View로 UI를 구성하기 위한 부가적인 데이터가 추가되어 있고, 이를 해석하는 과정에 비용이 많이 들었으므로 이 시기에 웹 서비스 간에 유려한 연동은 소원한 일이었습니다.

 만약 상기의 Structs구조에서 Javabean을 View에 binding시키고 View를 보내주는 것이 아닌, 서술가능한 형태의 DataStructure 형태로 Bean을 제공했다면 어땠을까요? 개발자들은 보다 View와 Model간에 연결성이 떨어져 병렬개발(?)이 가능했을 것이고, 외부에서 해당 서비스를 이용하기는 쉬웠을 것입니다. 요것이 현재 REST기반 아키텍쳐의 장점이죠.


Structs Framework의 Http session 문제

 또한 기존 웹 Framework들은 사용자의 로그인 정보등을 유지하기 위해서 세션과 쿠기 등의 부수요소를 사용했는데, 이와 같은 값들은 로그인과 같은 특정 과정을 거친 후에 생성되므로 웹 서비스 간에 연결하고자 할 때에 한 번 이상의 트랜잭션이 추가로 필요로 하게 되었습니다.


Restlet Framework

 다시 말하자면 기존에 사용하던 설계 상의 문제점은, 웹 서비스들 간에 연동도 어렵고, 웹 서비스를 다른 개발자들에게 공개하기도 어려운 상황 속이었습니다. 그러던 중에 REST를 통한 open-api 의 공개와 성공은 많은 개발자들에게 수 많은 웹 서비스들을 API처럼 사용할 수 있는 가능성을 열었고, 결과적으로 개발자와 서비스 모두에게 큰 도움이 되었습니다.


Restlet Framework가 지향하는 설계와 기능


 Restlet Framework는 #1 에서 살펴본 내용처럼 Restlet은 공개한 REST API 들을 URI로 접근할 수 있도록 도와줍니다. 또한 많은 REST API들을 사용할 수 있도록 URI을 각각의 메소드 등에 연결하기 편하게 도와주는 Routing이란 기능을 제공합니다.

 그리고 기존의 설계와는 다르게 Model의 데이터들을 View에 기입한 뒤에 View를 반환하는 것이 필수 구조가 아니고, View와 Model간에 Data를 설명해주는 서술자를 둠으로서 View와 Data간에 결합도는 최소화 할 수 있게 됐습니다.

 이것은 흔히 Front-End, Middle-End, Back-End 라고 부르는 구조처럼, 각 단계마다의 결합도와 의존성을 최소화하고 대신 정해진 규약과 인터페이스에 의한 분업 체계로 바뀌었음을 의미합니다. 이렇게 빠뀐 구조 덕분에 Front-End 에서 python, java, javascript 아무거나 내키는대로 사용할 수 있게 된 것입니다. Front-End Freedom!


Restlet Framework Sample service code review

Restlet Tutorial
Restlet의 기본적인 튜토리얼은 위의 주소를 참고하세요.

Restlet의 1단계는 서버를 만드는 작업입니다.
Restlet에서 서버는 하나의 Component 단위이며,

Component는 VirtualHost-Application의 구조로 이루어집니다.


그러므로 자연스럽게 2단계는 Virtual-Host 설정이고 3단계는 Application 설정입니다. 물론 정해진 순서는 없고 코드를 짜기에 따라서 어플리케이션에서 직접 Component를 올리고 Virtual-Host와 Application을 설정할 수도 있지만, 이번에는, Restlet Framework에 기본적으로 탑재하고 있는 서버 컴포넌트를 올리고 이 위에 어플리케이션을 올리는 작업을 해보도록 하겠습니다.

//HeloWorld
public class HelloWorldRESTMain {
public static void main(String[] args) throws Exception {
   // Create a new Component.
   Component component = new Component();
   // Add a new HTTP server listening on port 8182.
   component.getServers().add(Protocol.HTTP, 8182);
   // Attach the sample application.
    // component.getDefaultHost().attach(new HelloWorldRESTApplication());
   // Start the component.
   component.start();
}
}


컴포넌트를 만들고 8182번 포트를 사용하는 HTTP서버를 올리고, HelloWorldRESTApplication 을 attach 해줍니다.

//HelloWorldRESTApplication
public class HelloWorldRESTApplication extends Application {
    @Override
    public synchronized Restlet createInboundRoot()
    {
        Router router = new Router();
        router.attach("/helloworld",HelloWorldRESTResource.class );
        return router;
    }
}

HelloWorldRESTApplication에서는 helloworld URI에 Resource를 attach하는 역할을 합니다. 여기에 /helloworld 라는 URI는 이제부턴 HelloWorldRESTResource 클래스가 되는 거죠.
Resource는 어떤 역할을 할까요?


Resource는 실질적인 동작을 수행하는 곳 입니다. Router는 URI를 각 Resource로 연결해주는 식별자 역할만을 수행합니다.

REST Framework는 HTTP의 Get, Post, Put, Delete 를 지원하며 Restlet에서는 해당 Resource에 어노테이션을 확인하고 함수를 호출합니다. Get이라면 @Get 어노테이션에 따르는 함수를 호출하죠. 우리는 HelloWorld를 통해 Client에게 JSON을 반환해줄 것입니다.

// HellowWorldRESTResource
public class HelloWorldRESTResource extends ServerResource {
@Get
    public Representation HelloWorld(Representation entity)
    {
JsonRepresentation response = null;
        try
        {
        LinkedHashMap<String, Object> list = new LinkedHashMap<String, Object>();
            list.put("WELCOME_REST", "Hello World");
            response = new JsonRepresentation(list);
         
        } catch(Exception ex)
        {
       
        }
return response;
    }
     
}

JSON을 반환하기 위해 JsonRepresentation 클래스를 사용했습니다.
이제 브라우저로 http://localhost:8182/helloworld 에 접속하게 되면,

{"WELCOME_REST":"Hello World"} 

위와 같은 JSON을 반환받게 됩니다.



마치며

 REST는 매우 강력한 서버 모델이자 동시에 협업 모델이기도 합니다. MVC모델이 그토록 오랜 시간 GUI구현 패턴을 주도해온 이유는 View와 Model의 분리가 디자이너와 개발자에게 좋은 협업 환경을 만들어 주었기 때문입니다.

일보 더 나아가 REST는 개발에 있어 GUI와 서버 구성에 완벽한 독립성을 부여했습니다. GUI 개발자와 서버 개발자는 같은 프로그래밍 언어를 사용할 이유가 전혀 없게 되었다고 봐도 무방합니다. JSON이라는 훌륭한 매개자가 있으니까요. 또한 이를 통해 서비스 간에도 자유로운 협업이 가능해지게 되었습니다. RPC 같은 것과는 비교도 안되죠.

 다음 3부에서는 JSON을 통한 GUI 구성에 있어 MVVM모델을 사용하고 있는 knockout.js라이브러리를 통해 개발자와 퍼블리셔라고 불리는 Html 코더 간에 독립성을 확보하는 예제를 작업해 볼 것입니다.



화요일, 7월 16

최근 웹 개발환경 이해 - 진보된 웹 환경 공부 #1 REST




개요


 Framework는 개발자들에게 보다 편하고 쉽게 좋은 코드를 만들 수 있게 해주는 역할을 합니다. 그렇다면, 무엇이 좋은 코드이고 무엇이 좋은 코드일까요? 이것은 누구도 쉽게 대답하기 어려운 질문입니다.

 최근 프로그래밍 기법이나 언어는 지속적으로 OOP를 지향하며 발전되어 왔습니다. OOP하면 우리는 지겹도록 들어온 말이 재사용성이나 캡슐화 같은 이야기인데 잘 와닿지는 않을 것입니다. 왜냐면 그건 결과이기 때문이죠. 우리가 OOP언어를 사용하기 때문에 재사용성이 높아지고 하는 것이 아니라, OOP 적으로 설계하고 코드를 짤 수 있어야 그 결과물로 수업시간에 배운 OOP의 장점들을 얻어낼 수 있게 되는 것입니다.

 이번 최근 웹 개발환경의 이해에서는 REST와 함께 Knockout.js 라이브러리를 통해 요즘 OOP 기법에서 특히 중요하게 생각하는 "결합도 낮추기"를 선배님들이 어떻게 고민하였고 해결 방안을 제시했는지에 대해서 공부하고자 합니다.

 { "결합도 낮추기 (Decoupling) " = 코드간 의존성을 없애는 것을 뜻하며, 최근에 애자일 혹은 Lean 방식의 개발방법론이 대세를 이루며, 가장 핵심 기능을 우선 구현하여 단계적으로 향상시켜나가는 방식에 가장 중요한 OOP 요소입니다. " }



REST 란?


 먼저 살펴볼 것은 REST 입니다.
 REST는 Representational State Transfer 의 약자로 우리나라 말로는 "상태 재현적 전송" 으로 표현할 수 있겠습니다. "상태 재현적 전송"이란 REST의 설계 원칙 중에 하나로 (그리고 WWW의 설계 원칙에도 동일한 ) Stateless = 비연결성을 뜻합니다.

 원칙적으로 HTTP는 비연결성을 지향합니다만, 현존하는 거의 모든 웹사이트들은 세션이나 쿠키등을 통해 상태 정보를 저장하고 이를 통해 일종의 연결성을 임의로 만들어서 운용하고 있습니다. REST는 로이필딩이 2000년도 박사 논문으로 발표했고, HTTP의 주요 저자라고 합니다. 그러니 HTTP가 오용되는 현실을 보고 이를 바로잡기 위해서 REST를 발표했다고 생각해도 무리는 아닌 것 같습니다. ( 2000년 발표된 설계 기법이 퍼지는데 걸린 시간을 생각해보면 IT라고 해도 변화가 그렇게 빠른건 아닌 것 같습니다. )

 어쨌든, WWW 는 말 그대로 Web과 같은 네트워크 시스템을 만들고자 한 것이 목표였고 REST는 이와 같은 목표를 이루기 위한 방법론이라고 할 수 있겠습니다.

 REST의 장점을 대표하는 케이스를 하나 찝어보자면,
 웹 서비스들이 폭발적으로 성장하게 된 계기를 마련해준 Open-API 가 바로 REST의 대표적인 케이스입니다. 이쯤에서 REST 서비스를 웹 개발이나 서비스에 전혀 조예가 없는 초심자 분들에게도 쉽게 설명해드리고자 합니다.


예를 들어, 프로그래밍을 짤 때를 생각해보시길 바랍니다.
우리가 만드는 함수는 어떤 짜여진 규격이 있습니다.
다음의 pseudo 코드를 한번 보시죠.

[반환값] function1 ( Arg1, Arg2 ) {
        ... work work work ...
        return result;
}

어떠세요? 위의 코드는 거의 모든 분이 이해하실 수 있을 겁니다.
그럼 이제 질문을 하나 드리겠습니다.

REST는 아래와 같은 질문을 통해 이해해야 합니다.
< 위와 같은 코드를 Remote에서 호출하려면 어떻게 해야 할까요? >
- 1. 어떤 머신도 쉽게 접근할 수 있는 식별 가능한 주소.
- 2. 서로 다른 머신끼리 통신할 수 있는 공통의 인터페이스.
- 3. 함수를 호출하고자 하는 머신을 식별할 수 있는 stateless한 인터페이스.
- 4. 해당 함수에 인자를 줄 수 있는 공통의 인터페이스.

 다시 한번 강조드리는 것은, REST는 WWW, WEB처럼 거미줄로 엮인 네트워크 시스템을 고민하면서 나온 설계 철학이라는 것 입니다. REST의 저자인 로이 필딩은 이와 같은 문제들을 풀 수 있는 환경 = RESTful 을 구축하면 여러가지 장점이 있다고 생각한 것 입니다. ^^

 그리고 각 필요한 요소들이 시간이 지나면서 구축이 되기 시작한 것이죠 ~~


1번의 답 URI
URL은 많이 들어보셨을텐데 URI는 뭔가 하시는 분 혹시 계신가요?
URL은 Uniform Resource Location의 약자로, 말 그대로 Resource의 Location에 대한 Uniform 입니다. 예를들면 http://{host}/image.jpg 와 같은 형식이 URL입니다. 하지만 이것으론 충분하지 않게 됐습니다.

왜냐구요? 위를 보세요, 우리는 이제 함수를 호출할 수 있는 어떤 주소값도 필요하게 되었습니다. 이를 URL처럼 http://{host}/fucntion1 으로 접근하면 어때? 오, 그거 좀 괜찮은데? 그래서 나온게 URI입니다. URI는 Uniform Resource Identifier의 약자로 식별자로서 리소스를 구분하겠다는 뜻입니다. 앞의 예처럼 http://{host}/function1이라고 하면 이것은 함수와 연결되는 리소스의 식별자라고 생각하면 되겠죠.

대신 자신만 사용하는 것이 아니기 때문이 이름은 신중이 지을 필요가 있습니다~


2번의 답 JSON
JSON은 아직 표준이 아닌 것으로 알고 있어서 의견이 다를 수 있습니다만, 어쨌든 JSON도 서로 다른 머신끼리 통신할 수 있는 공통의 인터페이스를 목표하는 것은 맞습니다.

JSON이 뭔지 간단히 집고 넘어가자면, 위에서 예를 든 함수에서 반환값이 ArrayList와 같은 형식이라고 생각해봅시다. 이것을 Remote에서 호출한 컴퓨터에게 어떻게 전달하면 좋을까요? 이런 의문에서 만들어진 코드입니다.

JSON은 JavaScript Object Notation의 약자로, 말 그대로 Javascript에서 Object를 표기하는 방법입니다. 이는 Hashmap과 같이 key-value 짝 형식으로 되어 있는데, 예를 들자면
{
    "이름": "테스트",
    "나이": 25,
    "성별": "여",
    "기혼": true,
    "주소": "서울특별시 양천구 목동",
    "특기": ["농구", "도술"],
    "가족관계": {"#": 2, "아버지": "홍판서", "어머니": "춘섬"},
    "회사": "경기 안양시 만안구 안양7동"
 }
이런 형식입니다. Object들에 대한 Descriptor를 함께 가지고 있다고 생각하면 될 것 같습니다. 그렇기에 Client에서는 JSON을 통해 Return값을 받고 이를 적절히~ 파싱해서 화면에 보여주면 되는 것이죠.

3번의 답 Stateless.
Stateless는 단순히 비연결지향만을 뜻하는 것은 아닙니다.
비연결을 지향하기 위해 서버/클라이언트 간에 혹은 타 머신간에 서로를 인식하기 위한 값을 커뮤니케이션 시에 함께 보냄을 뜻하는 것 입니다. 이것은 마치 TCP와 UDP의 통신 방식의 차이와 유사합니다.


4번의 답 HTTP Protocol
앞선 단계를 따라 Remote의 함수를 URI를 통해 호출하고 결과를 HTTP JSON으로 받는 것까지를 설계적으로 구현했다면, Argument를 주는 것을 어떻게 할 것인가? 이것은 HTTP Protocol을 사용합니다. HTTP 스펙에 따르면 HTTP 프로토콜은 4가지 메소드를 지원하는데 Get, Post, Put, Delete 가 그것입니다.

굳이 이런 Argument를 방식을 사용하는 이유는 HTTP 프로토콜보다 범용적으로 사용되는 것이 없기 때문이기도 하겠고, 애초에 설계 방향이 같기도 하기 때문인 것 같습니다. 어쨌든 Argument로 값을 넣어주고자 한다면, Post로 JSON을 보내면 되고, 단순히 값을 넣고자 한다면 Put을 사용하면 되겠죠.





마치며...


 이번 글에서는 REST에 대해서 간략히 다뤄봤습니다.

 REST라는 설계, 구현 방법을 배우고 습득하는 것도 중요하지만 그만큼 REST라는 것을 만들기 위해 했던 선배들의 고민과 문제의식 그리고 해결방안을 생각하기 까지의 과정을 생각하는 것도 중요하다고 생각합니다.

 다음 글에서는 REST를 실질적으로 구현할 수 있는 Framework를 보면서 REST 서비스를 구현하기 위해 필요한 요소들이 무엇인지에 대해 살펴보도록 하겠는데, 아마 분량이 너무 많을 것이므로 서버 측면과 클라이언트 측면으로 나누어 설명하고 그 후에 서버와 클라이언트를 통합해 기존의 방식과 설계/디자인패턴의 변화에 대해 다루겠습니다.

 3편이 남았네요.