라우팅과 라우터
[Archive] 이 글은 2021년에 다른 플랫폼에서 작성한 글을 이전하며 재구성한 것입니다.
내용 중 일부는 현재 기준과 맞지 않을 수 있습니다.
라우터와 라우팅
라우터(router)는 말 그대로 라우팅(routing)을 수행하는 역할을 한다.
일반적으로 라우팅은 ‘어떤 네트워크 안에서 통신 데이터를 보낼 경로를 선택하는 과정’으로 정의할 수 있다.
중요한 부분은 ‘경로를 선택하는 과정’이다.
이 글에서는 라우팅을 네트워크나 특정 프레임워크의 기능이 아니라, 프로그래밍에서의 분기와 매핑 문제로 바라본다.
라우팅이란 무엇인가
프로그래밍에서 선택은 무언가를 임의로 고르는 행위가 아니다.
상태(state) 가 주어지고, 그 상태에 따라 정해진 처리가 수행된다.
라우팅의 본질은 상태와 처리 로직을 연결하는 방식에 있다.
조건문으로 보는 라우팅
가장 익숙한 라우팅 방식은 조건문이다.
1
2
3
4
5
6
7
8
9
10
11
switch (action) {
case "print":
print();
break;
case "run":
run();
break;
case "stop":
stop();
break;
}
이 방식은 직관적이고 이해하기 쉽다.
하지만 조건이 늘어날수록 다음과 같은 문제가 생긴다.
- 분기 수 증가에 따른 가독성 저하
- 새로운 조건 추가 시 코드 수정 범위 증가
- 분기 로직과 실행 로직이 강하게 결합됨
조건문 자체는 사라질 수 없지만, 조건문에 모든 책임을 지우는 구조는 빠르게 복잡해진다.
조건문에서 매핑으로
조건 분기를 코드가 아닌 데이터 구조로 옮기면 조금 다른 모습으로 바뀐다.
1
2
3
4
5
6
7
8
const actions = {
print: () => {},
run: () => {},
stop: () => {},
};
const runner = actions[action];
runner && runner();
중요한 변화는 다음과 같다.
- 분기 로직이 코드에서 데이터로 이동
- 조건의 확장은 객체의 확장으로 해결
- 실행 흐름이 훨씬 단순해짐
복잡성을 제거하고 데이터드리븐으로 변경하면서 조건을 매핑 규칙으로 치환한다.
데이터 드리븐(data driven)
사용자가 이벤트를 발생시켰을때 즉 마우스/키보드로 데이터를 전송 했을때에만 작동하는 것.
이벤트가 발생할 때 까지 자원(대기시간 및 메모리)의 소비를 최소화한다.
- 라우터의 최소 구성 요소
이 구조를 라우팅 관점에서 바라보면, 라우터는 다음 요소들로 구성된다.
- Target: 현재 상태 (예: action)
- Table: 상태와 처리 로직의 매핑 테이블 (예: actions)
- Rule: 매핑 규칙 (예: key 접근 규칙)
- Trigger: 라우팅이 실행되는 시점
1
const runner = actions[action];
이 한 줄이 상태를 기준으로 처리 대상을 결정하는 가장 단순한 라우터라고 볼 수 있다.
SPA에서의 라우팅
SPA(Single Page Application) 환경에서 페이지 이동이 곧 문서 이동을 의미하지 않는다.
초기 로딩 이후에는 상태 변화에 따라 화면의 일부만 갱신된다.
이 과정에서 라우팅은 어떤 상태에 어떤 화면을 보여줄 것인가를 결정하는 역할을 한다.
라우팅은 복잡한 기술이 아니다.
결국 상태에 따라 무엇을 실행할지 결정하는 문제.
- History 기반 라우팅
Browser History Mode는 HTML5 History API를 기반으로 URL을 관리하는 방식.
history.pushState를 통해 URL을 변경하되, 페이지를 새로 로드하지 않고 상태만 갱신한다.
1
2
3
4
5
window.history.pushState(
{ data: "some data" },
"Some history entry title",
"/some-path"
);
브라우저의 뒤로 가기 / 앞으로 가기 동작은 popstate 이벤트를 통해 감지할 수 있다.
1
2
3
window.onpopstate = () => {
appDiv.innerHTML = routes[window.location.pathname];
};
URL이 /some-path 형태로 깔끔하지만, 브라우저가 해당 경로로 직접 접근할 경우 서버가 이를 처리할 수 있어야 한다.
따라서 Browser History Mode를 사용할 때는 모든 경로 요청을 SPA의 진입 지점으로 돌려주는 서버 설정이 필요하다.
- Hash 기반 라우팅
Hash History Mode는 URL의 해시(/#)를 사용해 상태를 표현하는 방식이다.
해시 값은 window.location.hash를 통해 확인할 수 있으며, 해시가 변경될 때마다 hashchange 이벤트가 발생한다.
1
2
3
window.addEventListener("hashchange", () => {
appDiv.innerHTML = routes[window.location.hash.replace("#", "")];
});
이 방식은 브라우저가 서버에 새로운 경로를 요청하지 않기 때문에 별도의 서버 설정 없이도 동작한다.
정적 페이지나 서버 제어가 어려운 환경에서는 Hash History Mode만으로도 충분한 라우팅을 구현할 수 있다.