#1. 웹 게임 서버 아키텍처 설계: 확장성과 유지 보수를 고려하다.
웹 게임 서버 아키텍처 설계: 확장성과 유지 보수를 위한 최적의 구조를 지향합니다.
프로젝트 배경과 목표
의 빠른 발전으로 정보 제공을 주목적으로 하는 기존 블로그의 수요가 크게 줄었습니다. 지금은 AI 시대로 넘어가는 전환점이어서 변화하는 시대에 빠르게 적응하는 것이 무엇보다 중요합니다. 이런 상황에서 문득 간단히 즐길 수 있는 게임을 만들어 보는 것은 어떨까 하는 생각이 들었습니다. 그리고 어차피 만들 거라면 여러 게임을 담을 수 있는 플랫폼 형태가 좋겠다는 생각이 들었습니다.
새로운 프로젝트를 진행할 때 반드시 거치는 과정이 있습니다. 바로 아키텍처 설계에 대한 고민입니다.
저는 새로운 것을 만들 때, 머릿속 구상에 맞춰 흐름과 구조를 기획하는 데 시간을 아끼지 않습니다. 주변에서는 "일단 빠르게 부터 만들어라"라며 당장 개발부터 시작하라고 하지만, 성급한 진행은 오히려 같은 작업을 반복하게 만들 뿐입니다. 진짜 빠른 개발은 단순히 속도만 내는 것이 아니니까요.
설계 없이 시작하는 개발은 지도 없이 사막을 걷는 것과 같습니다.
웹 게임 플랫폼 아키텍처: 통합 관리 vs 게임별 분리
고민
가장 큰 고민은 "하나의 games-front 서버에서 모든 게임의 UI를 통합 관리할 것인가"였습니다. 이렇게 하면 라우팅이 단일 앱에서 처리되어 페이지 전환이 부드럽고, 프로젝트 구조도 단순해 초기 개발 장벽이 낮을 것입니다. 하지만 하나의 코드 베이스에서 모든 게임을 관리하면 규모가 커질수록 빌드가 느려지고 장애가 발생하면 전체 서비스에 영향을 줄 수 있다는 치명적인 단점이 있습니다.
그래서 게임별로 분리하는 방식을 고려했습니다. 게임을 독립적으로 개발하면 다른 게임에 영향을 주지 않는 큰 장점이 있습니다. 반면 공통 UI와의 통신·연동 설계를 별도로 해야 하고, 초기 설정이 복잡해져 개발 장벽이 높아지는 단점이 있습니다.
결정
여러 게임을 지속적으로 추가하면서 게임별 업데이트 주기가 다르고, 장애 발생이 다른 게임에 영향을 주지 않도록 하려면 가 유리합니다. 즉 고민했던 두 가지 방식 중 후자(게임별 분리)를 선택한 것입니다.
각 게임은 독립된 프론트로 개발하고 games-front는 게이트웨이 역할로서 공통 UI만 제공합니다. 백엔드에서는 games-api가 인증, 라우팅, 보안 검증을 담당하고 게임별 API 서버로 요청을 하는 구조를 갖추려고 합니다.
이렇게 하면 새로운 게임을 추가하거나 기존 게임을 업데이트할 때, 전체 서비스에 미치는 영향을 최소화하면서도 확장성과 유지 보수성을 모두 확보할 수 있습니다.
마치 여러 개의 상점을 하나의 대형 쇼핑몰 안에서 관리하는 것과 같습니다.
구조
시스템 구조를 간단히 시각화한 입니다. 사용자가 플랫폼과 상호작용하고 API 요청이 처리되는 흐름을 한눈에 보여줍니다. 전문 아키텍트가 그린 멋진 다이어그램은 아니지만 구조를 설명하기엔 충분하다고 생각하고, 단순히 스캐치라고도 할 수 있겠습니다.
사용자는 games.whitejerry.com으로 접속해 플랫폼의 공통 UI를 이용합니다.
모든 API 요청은 api.games.whitejerry.com을 통해 전달됩니다. 이곳에서 인증, 라우팅, 보안 검증을 수행한 뒤 각 게임별 API 서버로 요청을 분배합니다.
각 게임별 백엔드 서버는 해당 게임의 로직, 실시간 통신, 데이터베이스 처리를 전담합니다. 데이터베이스는 게임마다 전용 인스턴스를 두어 서로 간섭 없이 안정적으로 데이터를 관리할 수 있도록 합니다.
폴더 구조 설계
whitejerry-games는 기반 로 apps 폴더와 packages 폴더로 구성됩니다.
- apps: 실행 가능한 애플리케이션이 위치합니다.
- packages: 프론트엔드에서 사용할 공용 컴포넌트가 위치합니다.
apps 폴더는 다음과 같은 프로젝트가 포함됩니다.
- games-api: 멀티모듈 자바 프로젝트로 공용 API와 각 게임별 API 서버 로직을 포함합니다.
- games-front: 게임 플랫폼 프론트엔드 앱으로 공용 UI 모듈과 개별 게임 UI 모듈을 묶어 관리합니다.
이 구조는 블로그와 게임 플랫폼을 물리적으로 분리해 각 영역의 변경이 서로 영향을 주지 않도록 하며, 각 게임이 독립적인 API 서버와 UI를 가짐으로써 장애나 업데이트 시 다른 게임에 미치는 영향을 최소화합니다.
모노레포를 선택한 이유는 여러 앱을 하나의 저장소에서 통합 관리하기 위함입니다. 이렇게 하면 버전 관리와 의존성 업데이트를 한 번에 처리해 일관된 개발 환경을 유지할 수 있습니다. 또한 코드 중복을 최소화하여 유지 보수에 유리한 구조로 발전시킬 수 있겠습니다.
다만 모노레포는 프로젝트 규모가 커질수록 빌드 시간이 길어지는 단점이 있습니다, 이를 보완하기 위해 turbo를 도입하여 변경된 부분만 빌드 하는 방식을 적용하고, 하드 링크 기반 의존성 관리를 통해 디스크 공간을 절약하는 등의 장점을 활용하고자 합니다.
개인적으로는 를 선호하지만 이번 프로젝트에서는 모노레포의 장점을 직접 체감해 보고자 합니다.
게임 프론트 통합 방식
각 게임의 프론트를 통합하는 방식에는 여러 가지가 있습니다. 예를 들어 iframe이나 새 탭으로 각 게임을 분리할 수 있습니다. 하지만 이런 방식은 페이지 전환 시 화면이 깜빡이거나 세션이 끊기는 등 사용자 경험이 떨어질 가능성이 큽니다.
그래서 이번 프로젝트는 방식을 적용하려 합니다. 각 게임의 UI를 완전히 독립적으로 개발하되 games-front에서 불러와 마치 하나의 서비스처럼 자연스럽게 동작하도록 만드는 것입니다. 이 방식은 구현 난이도가 비교적 높지만 장기적으로 유지 보수와 확장성에서 큰 이점이 있습니다.
주의할 점을 생각해 보았습니다.
서로 다른 빌드 환경과 모듈 로딩 방식을 맞추는 과정에서 충돌이 발생할 수 있습니다. 이를 해결하기 위해 공통 빌드 설정을 마련하고 모든 게임에서 이를 참조하도록 할 계획입니다. 또한 런타임에 외부 모듈을 불러오기 때문에 로딩 속도가 느려질 수 있습니다. 필수 모듈은 사전에 번들에 포함시키고, 게임 플레이에 필요한 리소스는 으로 처리해 이 문제를 최소화할 생각입니다.
보안 측면도 간과할 수 없습니다. 외부에서 불러오는 모듈이 변조되면 서비스 전체에 영향을 줄 수 있기 때문에 서브도메인 기반의 배포와 을 적용하며 모든 API 요청은 공통 게이트웨이를 통해 인증과 검증 절차를 거치게 하려 합니다.
개발 순서: 플랫폼 vs 게임
이번 프로젝트에서는 게임부터 먼저 구현하는 방식을 택했습니다. 그 이유는 단순합니다. 플랫폼을 먼저 만들면 겉으로는 멋져 보여도 정작 실제 게임 로직이나 실시간 통신 구조가 어떻게 동작할지 확정되지 않은 상태에서 만들게 되어 나중에 다시 뜯어고쳐야 하는 상황이 발생할 가능성이 높기 때문입니다.
게임 개발 초기에 실시간 통신, 게임 로직, 턴 처리 등 핵심 기능을 구현하면 그 과정에서 자연스럽게 기술적 난제와 UI 흐름을 미리 경험할 수 있습니다. 이렇게 얻은 경험은 games-front와 games-api 같은 플랫폼 설계에 그대로 녹아들어, 추상적인 계획이 아니라 검증된 요구사항 기반의 설계가 가능해집니다.
결국 게임을 먼저 만드는 것은 시간과 리소스를 절약하고 초기 아키텍처가 현실과 동떨어지지 않게 만드는 가장 확실한 방법이라고 생각했습니다.
실제 게임 구현: 비밀에 부친 게임
첫 번째로 구현할 게임은 아직 공개하지 않지만 실시간 상태 동기화, 게임 진행 로직 등 대부분의 온라인 게임에서 필요한 핵심 기능을 포함하고 있습니다.
이 게임을 먼저 구현하면 실시간 네트워크 처리와 UI 반응성, 서버-클라이언트 간 데이터 일관성 유지 같은 플랫폼 전반에 적용될 기술 요소들을 실제 환경에서 검증할 수 있습니다. 또한 플레이 테스트를 통해 사용자가 어떤 흐름에서 이탈하는지 어떤 UI 요소가 직관적인지 등 플랫폼 설계에 직접 반영할 수 있는 피드백을 얻을 수 있습니다.
마무리 및 다음 단계
첫 번째 게임이 안정화되면 새로운 게임을 하나씩 추가하며 공통 플랫폼 기능을 점차 확장할 계획입니다. 이 과정에서 마이크로 프론트엔드 방식의 전면 도입, API 게이트웨이 고도화, 인증·상태 관리 공유 방안 설계 등도 차례대로 구현할 예정입니다.
즉 게임 개발 → 기능 검증 → 플랫폼 확장의 사이클을 반복하며, 확장성과 유지 보수성을 모두 갖춘 웹 게임 플랫폼으로 발전시키는 것이 최종 목표입니다.
이 여정을 흔들림 없이 걸어갈 것을 다짐합니다.