병무청 병역일터의 채용공고를 간편하게 검색할 수 있는 sangiyo.kr은 최신 공고를 보여주지만 백엔드가 없다. 그렇다고 프론트엔드에서 직접 병무청 API를 호출하는 것도 아니다. sanigyo.kr은 다음과 같이 굴러간다.
- 병역일터 API를 긁어서 채용공고 데이터 JSON을 만든다.
- 채용공고 데이터 JSON을 JS 번들에 통째로 삽입해서 프론트엔드에 넘긴다.
- 프론트엔드에서 JSON을 직접 선형 탐색하면서 조회를 수행한다.
요컨대 DB를 프론트에 통째로 넘기는 것이라고 할 수 있다.
그리고 이렇게 하려면, 기존 서비스를 다음과 같이 악용해야 한다.
- 로직단: 채용공고를 API로 가져와서 DB에 저장하는 AWS Lambda의 대체재로 GitHub Actions를 악용한다.
- 프론트단: DB를 통째로 받아와서 직접 검색을 수행하도록 브라우저를 악용한다.
로직단의 구조
로직단에서는 파이썬 스크립트로 병역일터 API를 긁어서 JSON으로 만들고, 프론트엔드 JS 번들에 넣는다. 해당 스크립트가 하는 일은 대략 이렇다.
- 병역일터 공공 API를 호출해 공고 목록을 받는다.
- 병역일터 공공 API는 불완전해서, 요구 자격증, 복리후생 등은 보내주지 않는다. 병무청 병역일터 홈페이지를 직접 스크랩해 누락된 정보를 채운다.
- 이 정보를 바탕으로 채용공고 목록을 JSON으로 만든다.
- 프론트엔드를 React로 빌드하고, JS Bundle에 위 JSON을 끼워넣는다.
- 정적 웹사이트 호스팅 도구인 Azure Static Web App으로 sangiyo.kr에 HTML, CSS, (4에서 만든) JS를 배포한다.
Github Actions의 cron을 AWS Lambda 대용으로 악용하면 위 작업을 1시간에 1회씩 실행할 수 있다.
on:
schedule:
- cron: "0 * * * *" # 매시 정각
프론트단의 구조
프론트는 React로 만들어 Azure Static Web Apps에 올린다. 빌드 시점에 JSON을 받아 번들에 그대로 넣는 게 핵심이다. sangiyo.kr에 접속하면 2MB짜리 JSON을 다운받게 되는데 그게 바로 채용공고 DB다. 브라우저는 페이지를 열 때 이 데이터를 한 번 받아 메모리에 올리고, 인덱스도 쿼리 언어도 없이 그냥 배열을 filter로 훑는 선형 탐색을 수행한다.
const 복수공고다중필터검사 = (채용공고목록, filters, 즐겨찾기) =>
채용공고목록.filter((공고) =>
filters.every((filter) => 단일공고단일필터검사(공고, filter, 즐겨찾기)))
정렬은 직접 하고, 즐겨찾기는 localStorage로 한다. 공고가 1만 개도 안 되기 때문에 이렇게 무식하게 선형 탐색을 해도 최장 0.5초밖에 걸리지 않는다.
결정의 이유
기술적 결정에는 합당한 이유가 있어야 한다. sangiyo.kr을 이렇게 만든 데는 다음과 같은 이유가 있다.
- 관리 난이도: 24시간 살아 있는 서버를 운영하는 것은 매우 귀찮은 일이다. DB를 관리하는 것 역시 매우 귀찮은 일이다. AWS에서 아무리 Lightsail처럼 간편한 컴퓨팅 자원을 제공해준다고 하지만, 백엔드가 없는 것만큼 간편할 수는 없다. Best server is no server.
- 비용: 정적 웹사이트 호스팅 도구(Github Pages, Azure Static Web App)는 대부분 공짜다. 비용이 10원 나가는 것과 1000원 나가는 것은 별로 차이가 없지만 비용이 아예 없는 것과 10원이라도 나가는 것은 매우 다르다. 무료라는 것은 크레딧 관리를 해줄 필요가 없고, 결제수단으로 신용카드 등록을 해두었다가 잃어버려서 다시 등록해줄 필요도 없고, 매달 결제 청구서가 날아오지도 않기 때문에 만들어놓고 잊어버려도 된다는 뜻이다. 요컨대 인지 부하가 적다.
- 읽기 전용: 어차피 공고에 지원하려면 병역일터 홈페이지에 직접 들어가야 하기 때문에 sangiyo.kr은 병역일터의 프록시로만 기능해도 충분하다. 기업 후기라든가 별점 같은 것을 우리 웹사이트에서 제공해줄 필요는 없다(어차피 잡플래닛이 있다). 따라서 처음부터 sangiyo.kr을 웹1.0을 따르는 stateless 웹사이트로만 만들기로 가닥을 잡고, 유저가 데이터를 입력해서 상태를 조작할 수 없도록 했다.
- 비동기성: 채용공고는 실시간으로 보여줄 필요가 없다. 한 시간에 한 번만 병무청에서 가져와도 충분한 데이터다.
하여 sangiyo.kr의 아키텍처를 이렇게 구성하였고, 2023년부터 지금까지 3년째 무리 없이 운영하고 있다.
