라우터(Router)에 대해

라우팅(Routing)

당연하게도 라우터는 라우팅을 하는 녀석입니다. 라우팅(Routing)이란 뭘까요?

위키나 사전등에서 대략

어떤 네트워크 안에서 통신 데이터를 보낼 경로를 선택하는 과정이다

정도로 설명하고 있습니다. 뭐 의미가 저렇긴하지만 그 중에 집중하고 싶은 부분은 경로를 선택하는 과정 입니다. 거기서 보다 잘라내고 핵심만 추리면

선택하는 과정

라고 줄일 수 있습니다. 선택하는 과정이라고 한글로 쓰니 좀 이상하네요. 영어로 하자면 과정은 process가 되니까선택이 일어나는 일련의 처리과정이라고 이해할 수 있겠습니다.

 

선택(Condition?)

프로그래밍에서 선택이란 사실 select가 아닙니다. 아무것도 없이 골라잡을 게 주어지지는 않습니다.

프로그래밍에서 선택이란 정확하게 말하자면 어떤 상태를 선택하는 것이고, 이 중 주인공은 선택이 아니라 상태입니다. 따라서 프로그래밍에서의 선택이란 condition 이라고 할 수 있습니다.

이는 마치 잠을 잘까 밥을 먹을까의 선택을 하는 것이 아니라, 배고프면 밥을 먹고, 졸리면 잠을 잔다는 것이 프로그래밍이란 의미입니다.

그렇다면 프로그래밍에서의 선택이 상태고 이를 라우팅과 결합해보면 상태에 따라 일어나는 일련의 처리과정이라고 이해할 수 있습니다.

 

조건문(Conditional Statement)

판단문이라는 잘못된 이름으로도 알려진 if, switch 등의 익숙한 문들이 왜 조건문이라 불리는지 이제 알 수 있습니다. 조건이란 주어진 상태라는 뜻입니다.

주어진 상태에 따라 다른 처리를 선택하기 때문에 조건에 따라 달리 선택되는 문이라는 의미로 조건문입니다.

이거 뭔가 위에 얘기하고 있던 프로그래밍의 라우팅과 무지하게 비슷하지 않나요?

 

조건문의 제거

프로그래밍의 가장 큰 문제는 복잡성입니다. 컴터는 아무리 복잡한 로직과 조건에 따른 분기도 문제없이 처리합니다만, 이 알고리즘 자체를 인간이 이해하는데는 한계가 명확합니다. 보통 2단 중첩 조건문이 한계로 3단 중첩 조건문은 이미 버그라고 확정지어도 무관할 정도로 안정성이 떨어지게 됩니다.

하지만 알고리즘에서 조건문은 결코 제거되지 않습니다. 반대로 조건문을 제거하지 않으면 복잡성은 제거되지 않습니다.

이 모순을 어떻게 해결할까를 수많은 개발자들이 고민해왔습니다. 디자인패턴이나 전통적인 알고리즘 분야에서도 열심히 노력하고 있습니다만 수학적 연산을 통해 일부 제거할 수 있을 뿐 근본적인 해결책을 얻지는 못했습니다.

그나마 한가지 발견한게 있는데 바로 조건에 따른 문을 분산시키는 기술입니다. 간단히 js코드로 살펴보죠.

switch( a ){
case 'print':  //statement1; break;
case 'action'//statement2; break;
case 'run'//statement3; break;
case 'stop'//statement4; break;
}

위에 switch문이 있습니다. 이를 어떻게 하면 제거할 수 있을까요?

당연히 제거할 수 없습니다. 하지만 다음과 같이 미리 조건에 해당되는 모든 데이터를 구비해두면 코드를 변화시킬 수 있습니다.

var actor = {
print : function(){ //statement1; },
action : function(){ //statement2; },
run : function(){ //statement3; },
stop : function(){ //statement4; }
};

위의 actor는 switch문에 있던 모든 조건에 대응하는 키에 함수를 할당하여 조건별 처리되던 문을 각각의 함수 내부로 옮겼습니다. 이렇게 되면 switch문은 제거되고 아래와 같이 변합니다.

var runner = actor[a];
runner();

switch문을 없애는데 성공했습니다! 이 방법이 유일하게 조건문을 제거하는데 찾아낸 방법입니다. 이 방법은 디자인패턴이 되면 전략패턴이나 상태패턴1으로 나타나고 방법론으로는 데이터드리븐(Data Driven)2으로 나타납니다.

게다가 이렇게 되면 큰 차이점이 생기는데 기존의 switch문에서는 조건이 늘어나면 매번 코드를 건드려야하지만 경우의 수만큼 데이터화한 경우는 새로운 경우에 대한 데이터를 추가함으로서 처리됩니다. 즉 아래와 같은 차이가 생깁니다.

//switch
switch(a){
...
case 'handle': ....; break;
}
 
//data
actor.handle = function(){...};

따라서 조건문을 조건별 처리기를 각각 제작하여 데이터화하는 것은 미래의 확장이나 수정이 일어나면 대처할 수 있는 범위나 수준이 완전히 달라집니다.3

 

라우터

사실 조건문을 데이터드리븐형태로 제거할 때 이미 라우터가 등장했습니다. 매우 심플하지만 아래 코드가 바로 라우터입니다.

var runner = actor[a];

상태에 따라 일어나는 일련의 처리과정을 훌륭하게 커버하고 있습니다. 이때 상태는 a 이고 일련의 처리과정에 해당되는 녀석은 runner입니다.

프로그래밍에서 라우터가 등장하는 이유는 복잡성을 제거하고 데이터드리븐으로 변경되면서 기존의 조건문을 일관된 처리객체와의 매핑으로 바꾸는 과정에서 만들어지는 산출물인 셈입니다.

 

라우터와 조건문의 차이

데이터 드리븐으로 구축해도 라우팅하는 과정은 다시 조건문으로 회귀할수도 있습니다. 즉 아래와 같죠.

var runner;
switch( a ){
case 'print': runner = actor.print; break;
case 'action': runner = actor.action; break;
...
}
runner();

그렇다면 라우터와 조건문은 차이가 없는건가요?

.

.

넵 없습니다. 문법 상으로는 차이가 없습니다. 차이가 있는 부분은 매핑규칙(Mapping Rule)이 존재하는가 입니다.

매핑규칙(Mapping Rule)

매핑규칙은 조건문의 조건식에 들어갈 내용을 정형화하여 간단한 규칙으로 만든 것입니다. 규칙이 될 수 있는 것은 함수, 값 등 제약이 없습니다만 제약이 많을 수록 복잡성이 줄어들어 관리하기 간단해지고, 복잡해질 수록 다시 조건문과 동일한 복잡성에 수렴합니다.

위의 라우터의 매핑규칙을 보죠.

var runner = actor[a];

이는 a라는 값이 뭐가 되었든 actor에 정의만 되어있으면 된다는 엄청나게 간단한 규칙입니다. 이 때의 문제는 a에 해당되는 키가 actor에 없으면 안되다는 것이지만, 안정성은 둘째치고 규칙은 엄청나게 간단하고 확장도 무한입니다.4

그에 비해 두 번째의 조건문에 가깝던 규칙을 보죠.

var runner;
switch( a ){
case 'print': runner = actor.print; break;
case 'action': runner = actor.action; break;
...
}

이것은 라우터이기도 하지만 거의 조건문에 가깝고, 조건의 확장도 코드의 수정없이는 불가능합니다.

매핑규칙과 조건식의 근본적인 차이점은 조건의 확장성에 달려있습니다. 조건식 즉 식이 되면 확장성이 거의 없어지게 됩니다. 하지만 규칙이 되면 규칙을 따르는 이상 전부 허용하게 됩니다.

어떻게 보면

  • 조건식은 블랙리스트로
  • 매핑룰은 화이트리스트로

이해할 수 있습니다. 이는 전부 상대적이면서 개념적이기 때문에 어떤게 규칙인지 식인지 명확히 나눌 수 있는 성격의 것이 아닙니다.

반대로 판단할 수 있는 것은

그 식보다는 이 식이 보다 규칙에 가깝다

라고는 할 수 있겠죠.

 

트리거, 테이블, 타겟, 규칙

라우팅에는 기본적인 네 가지 요소가 필요합니다. 물론 추가적으로 더욱 많은 요소야 추가될 수 있습니다만 이 네 가지는 반드시 있어야 합니다.

여태 설명한 것은 규칙(Rule)입니다. 그리고 당연히 코드 상의 a는 라우팅 타겟(Target)입니다. 즉 규칙은 타겟을 기반으로 판단하는 것입니다.

규칙이 타겟을 판단한 뒤는 매핑할 대상이 필요합니다. 이게 바로 라우팅 테이블(Table)로 코드 상에서는 actor에 해당됩니다.

라우팅 테이블의 경우 많은 웹애플리케이션 프레임웍에서는 xml등으로 관리합니다. Spring을 비롯한 많은 프레임웍에서 라우팅 테이블을 기술할 때 보통 그 테이블 상의 정보로 연결되는 규칙을 동시에 정의합니다.

즉 라우팅 테이블 안에 규칙을 포함하고 타겟을 넘겨주는 게 일반적인 구조입니다.

마지막으로 라우팅 트리거(Trigger)는 이러한 라우터의 작동이 언제 일어날 지를 정의합니다. 많은 웹프레임웍에서는 서버에 request가 올 때 작동됩니다만 js용 프레임웍에서는 hash가 바뀔 때를 감시하고 있다가 작동하는 경우도 있습니다.

 

라우팅 트리거라는 개념을 갖고 있다면, 모든 것을 트리거 대상으로 인식할 수 있습니다.

쿠키의 변화, 디비값의 변화, 세션의 변화, 날씨의 변화, 센서의 변화, 위치의 변화.. 무엇이든 라우팅의 트리거가 될 수 있습니다.

또한 트리거의 대상이 꼭 라우팅 타겟일 필요도 없습니다. 라우팅 발동 자체는 순방문자가 늘어날 때 실행되었지만, 그 때의 타겟은 디비에 쌓인 글이 몇 개라면.. 으로 할 수도 있는 거죠.

 

결론

네트웍 장비로부터 생겨난 라우팅의 개념은 프로그래밍 구조 전반에 영향을 끼치고 있습니다. 프로그래밍시 라우팅의 개념을 이해하고 기존의 한정적이고 복잡한 구조를 매핑테이블과 라우팅 시스템으로 이전함으로서 유연성과 확장성을 확보해갈 수 있습니다.

…안되면 걍 전략패턴이나 상태패턴 좀 많이 쓰는 것 정도라도..=.=

  1. 두 패턴 다 실행 시점에서 실제 처리할 객체를 지정할 수 있습니다. 
  2. 데이터드리븐의 정의는 아직도 의견이 분분합니다만 ^^ 
  3. 코드를 건드리면 원래 js파일을 수정배포하게 되지만 데이터를 추가하는 경우는 그저 새로운 js파일을 추가로 로딩하면 될 일입니다! 
  4. 실행시점의 안정성은 결국 try로 확보할 수 밖에 없습니다 



출처 - http://blog.bsidesoft.com/?p=123#Routing




라우팅을 꼭 웹서버에서 해야 할까?


요즘 여기저기 듣는게 많아서 이것저것 보다가 생각난 것을 주절주절 적어본다. 어깨너머로만 보고 혹은 대충 써보고 적은 것들도 많아서 내용의 정확성은 보장하지 않는다 오키


최근 node.js + express + ejs + bootstrap을 이용해서 간단히 웹서버를 만들어 띄우는 것을 보면서 꽤 유용한 기술이구나...싶은 느낌을 받았다.

그런데 얼핏보면 깔끔해 보이는 이 구조도 사실상 php의 재탕에 불과하며..여전히 서버코드와 클라이언트 코드가 섞여서 유연성이 떨어지는 방향으로 발전하기 딱 좋게 생겼다.

게다가 서버나 클라이언트나 자바스크립트고 애초에 추구하는바도 서버측과 클라이언트측 코드 재사용이니 기본 구조만 본다면 jsp를 써서 서버나 클라이언트나 자바로 하겠다는것과 크게 달라보이질 않는다.

물론 UI 동적 구성을 jsp로는 할 수 없으니 node.js 묶음이 더 유연하긴 하겠지만... 서버-데이터구축 -> 서버-페이지 렌더링 -> 클라-동적UI 모두를 javascript로 처리하다보면 더 뒤죽박죽이 될것 아닌가 싶기도 하다.


그렇다면 좀 깔끔한 방법이 없을까?

이건 쉽게 시작할 수는 있어 보이지만 쉽게 변화시키기에는 적합해 보이지 않는다.


그러면서 든 생각이... 애초에 서버와 클라이언트가 이렇게 뒤죽박죽 된 것이 웹 개발이 성행하면서 부터 아닐까?..그러니까 JEE.. 뭐 나야 이바닥 초기맴버는 아니니 잘 모르겠다...

어쨌든 데이터 생성이 UI 렌더링에 영향을 받는게 이뻐보이진 않는다. 물론 서버에서 데이터를 줘야 페이지 렌더링을 하겠지만... 엮여도 너무 엮인 느낌이다.

게다가 how-to만 따라하며 던져지는 일만 하던 개발자라면... jsp 페이지(혹은 다른 view template) 안에서 수행되는 java 코드와 그 외 코드는 사실 몇만광년 떨어진 서버와 클라이언트라는 다른 공간에서 수행된다는 사실을 까먹게 될 것 같은 느낌도 든다.


사실 나도 M-V-C 구조가 구체적으로 머릿속에 잘 받아들여지지 않았고...(저 V는 서버에서 만드는 view와 크라이언트가 만드는 view를 섞어놓는 만행을 저질렀다.) service와 dao의 역할분담에 대한 명확한 판단은 아직도 잘 서지 않으며, 스프링에서도 당연히 서버코드에 속하는 Controller 영역이 고전적인 server-client 프로그래밍(네떡 게임, 터미널 모드, svn<->svn client, ..)에서는 당연히 client 영역이였다는 부분도 망각하고 있었다.


컨트롤러(http request와 java 코드의 경계에 있는)에서 주로 처리하는 일은 권한 체크, 파라메터 추출, 결과용 데이터 만들기, response body 만들기(주로 html 렌더링), 필요하면 또다른 웹서버 혹은 메일 발송등의 추가적인 통신 처리 등인데...


권한 체크야 어쩔 수 없다 쳐도, 요즘 권한체크는 컨트롤러에 도달하기 전에 인터셉터 형태로 처리되니 사실 컨트롤러가 할건 아니고,


파라메터 추출도 요즘 JEE 프레임워크들은 알아서 data model에 매핑해주니 딱히 컨트롤러가 할 일은 없고,


결과용 데이터 만들기는... 뭐 컨트롤러가 여전히 해야 할것 같고.. 그런데 db(혹은 다른 storage)를 뒤져서 데이터를 뽑는것 뿐만 아니라 이메일을 발송한다던가, 다른 웹서버에 요청을 전달한다던가 혹은 데이터를 가져온다던가, 핵연료봉을 들어 올린다던가, 혹은 이러한 작업들을 큐에 쌓던가...결국은 결과 데이터를 만들기 위해 수행하는 일련의 작업들이라고 보면 되지 않을까? 펙토리 메소드로 결과용 데이터를 만든다고 치면 이 모든건 펙토리 메소드에서 처리되도 이상할 것이 없는 작업들처럼 보이는데??


html 렌더링(혹은 xml, json 문자열 만들기)도 요즘은 컨트롤러가 data model만 던지면 연관된 view template에 엮어서 html로 만들던가 알아서 xml, json 등으로 변환해준다. 


라우팅...그러니까 "이 처리가 성공하면 어느 페이지로 갈 것이다"에 대한 결정을 서버측에서 정해야 할까?

전에는 사용자의 이동을 제한하기 위해서... 그러니까 권한이 없는 페이지에 대해서는 동선을 제공하지 않기 위해서 서버측에서 처리해야 한다고 생각했었다.

그런데... 서버에서 보호해야 하는 것은 페이지 url이 아니라 거기에 담긴 데이터 아닐까?

다른말로 어떻게 해서든 악의적인 사용자가 그 url을 알게 되었을 때 그 url로 접근하면 데이터를 그냥 제공하는게 제대로 된 보안일까?

원천적으로 url을 보여주지 않는다는데 의의가 있을 수는 있지만... 어차피 오픈된 웹인 마당에 url 좀 숨겼다고 진정 보안에 도움이 될까?


결론은? 기존에 컨트롤러라고 생각했던 것은 결국 data model builder 혹은 factory method에 지나지 않게 되며 어떤 형태로든 결과는 data model 하나 던져주면 할일 다 하는거다.


어디서 많이 보던것 아닌가?

RESTful 모델이 그렇게 동작한다.

물론 hypertext 기반이어야 하고 정해진 method 규약을 따라야 하며, http response status를 통해 결과처리를 하는 등등 몇가지 추가사항들이 있지만... 어쨌든 url을 던지면 data가 던져진다... RESTful 틱하다.


요즘 ajax는 당빠가 된 client측의 javascript들이 워낙 좋아져서 페이지 이동 없이 리스트에서 상세보기로, 수정하기로 자유자제로 움직일 수 있다.


내 귀에 제일 유명한 jQuery로 대표되는 javascript 라이브러리? 프레임워크? 들은 서버에서 xml이든 json이든 던져주는 url 하나만 만들어주면 요거로 표도 만들고 그래프도 그리고 소팅도 하고 필터링도 하고 모양도 바꾸고 알아서 잘 한다.


물론 view를 손안대고 코 풀려면 Bootstrap이 요즘 내귀에는 대세이다.


일단 해상도에따라 레이아웃 대충 바꿔주고 메뉴 재구성해주는것만해도 땡큐다.


근데 하나가 비었다... 라우팅... 굳이 컨트롤러에서 할필요 없을것 같아 빼놓았는데 Bootstrap도 jQuery도 이걸 처리하기에는 부족하다.... 그래서 Backbone.js가 있다.


서버측은 Springframework의 RESTful 관련 기능을 최대한 활용해서 데이터 던져주는데만 집중하고,

클라측은 Backbone.js와 Bootstrap을 이용해서 와꾸를 짜고 이쁜게 필요하면 jQuery 투입.

어차피 서버가 던져주는 json/xml 데이터는 jQuery가 쓰기에도 Backbone.js가 쓰기에도 OK.

dwr 혹은 (버려진) Flex의 RemoteObject 같이 엽기적인 뒷구멍 솔루션을 쓰지 않아도 깔끔하게 동작한다.


요런 구성을 설명해주는 슬라이드가 있어서 이 긴 글을 적었다...이 새벽에... 아 졸려...

링크만 남기기 허전해서 주절주절 늘어놨는데... 내가 다시 이 글을 볼 일이 있을지 모르겠다...

어쩌다 다시 봤을 때... "뭔 헛소리?"하지 않을까 싶기도 하고..


아무튼 결론은 아래 링크를 보시라!!


http://www.slideshare.net/morman/integration-of-backbonejs-with-spring-31


integrationofbackbone.pptx



Backbone.js를 포함한 client side MVC에 대해서는 아래 링크가 도움이 될 듯.

http://codefactory.kr/2011/12/22/getting-started-with-backbonejs-1-what-is-backbone/


하나 만들어 띄워보고 싶다....언젠가....근데 아마 안될꺼야...



출처 - http://blog.daum.net/rollin/8097011










'Development > JavaScript' 카테고리의 다른 글

javascript - document.body.scrollTop  (0) 2013.11.02
Backbone.js  (0) 2013.10.13
javascript - RequireJS  (0) 2013.10.02
javascript - 크롬에서 동적으로 로드된 js 파일 디버깅 방법  (0) 2013.07.28
javascript - forms 객체  (0) 2013.05.13
Posted by linuxism
,