데이터베이스의 버전 관리

이 문서는 NDC 2011 발표 분량 중 KGC 2011 에서 빠진 내용을 다룹니다. KGC 2011 에서는 기초에 집중하려 합니다. 대구에서 봐요~

KGC 2011

소스코드 버전 관리를 멀리하는 조직이 아직도 있다 하지만 그 개념과 필요성만큼은 충분히 인지되는 것 같다. “올바르게 일하는 법”에 대해 고민하는 사람이 있고 그런 이의 의견을 받아들일 넉넉함이 있는 곳이라면 서브버전(Subversion), Git, Mercurial 또는 Perforce 등의 버전 관리 시스템을 사용한다.

이렇게 소스코드를 체계적으로 관리함으로써 문제가 생겼을 때 그 원인을 추적하기 쉬워졌다. 새 패치를 내놓고 나서 멀쩡하던 버튼이 보이지 않게 됐다면, 최근 일주일간 바뀐 소스코드만 살펴보면 된다. 수십 만 줄이나 되는 전체 소스코드를 뒤질 필요는 없다.

콘솔 게임이라면 여기서 끝!

하지만 온라인 게임은 소스코드만 확인해서는 문제를 해결 못하는 일이 많다. 콘솔 게임과 달리 온라인 게임 서버와 연동하는 데이터베이스가 뒤에 있기 때문이다.

오랜 만에 게임을 즐기는 플레이어에게 할로윈 기념 호박 머리를 주기로 했는데 월드컵 이벤트용 축구공이 전달된다고 한다. 이제 어떻게 해야 할까? 작업자를 불러서 해결하라고 시키면 된다. 그런데 작업자가 휴가 중이라면?

  1. 소스코드 저장소를 뒤졌으나 작업자가 바꾼 내용에는 이상한 점이 없다. 아무래도 DB 문제 같다.
  2. 서버를 띄워놓고 상황을 재현해서 어떤 테이블이 문제인지, 어떤 저장프로시저가 문제인지 알아낸다.

보통은 이렇게 일한다. 저장프로시저나 데이터베이스의 변경사항은 소스 서버에 넣지 않기 때문이다. 무얼 고쳤는지 모르기 때문에 일일이 뒤져서 문제 지점을 찾아야 한다. 만약 변경되거나 추가된 데이터베이스 객체(테이블, 저장프로시저, 사용자 계정 등)와 레코드를 스크립트로 빼내 소스 서버에 넣었다면 좀더 쉽게 일이 끝났을지 모른다.

  1. 소스코드 저장소를 뒤져서 일주일 간 작업자가 변경한 데이터베이스 객체 또는 레코드를 확인한다.
  2. 이벤트 테이블에 새로 추가한 레코드를 살펴보니 호박 머리의 아이디인 1 대신 축구공의 아이디인 2가 들어 있다.

서비스 로직의 상당한 비율이 데이터베이스에 들어가곤 한다. 이런 상황에서 데이터베이스를 버전 관리하지 않는다면 사실상 가장 중요한 에셋이 통제 불가능한 상황에 놓이게 된다. 그만큼 데이터베이스의 버전 관리는 중요하지만, 이를 구현하기가 꽤 만만치 않기 때문에 실제로 이뤄지는 경우는 많지 않다.

자, 그러면 어떠한 접근 방법을 취하면 될지 알아보자.

ORM 객체관계매핑

ORM 객체관계매핑

#1 ORM 객체관계매핑

현대적인 웹 서비스 프레임워크에서 주로 사용하는 방법이다. ORM 방식은 프로그램 소스코드에 데이터베이스 객체를 정의하고 이에 맞춰 실제 데이터베이스 객체를 자동으로 생성한다. 개발 인원이 적은 프로젝트 초창기에 데이터베이스 관리자가 필요하지 않고, 별도의 데이터베이스 버전 관리 도구를 사용할 필요가 없다는 장점이 있다.

다만, 대부분의 게임 프로젝트가 C++ 로 진행되는데 반해 C++ 용으로 개발된 쓸만한 ORM 프레임워크는 찾아보기 힘들다. 게다가 대부분의 ORM 프레임워크가 웹 용으로 개발되는데, 웹과 온라인 게임의 요구사항에는 차이가 있을 수 있다. 하여 개발 초기에 프로젝트에 쓸 ORM 프레임워크를 구현해 적용하곤 한다. 그만한 여력이 있을 때는 말이다.

마지막으로 레가시 프로젝트인 경우, ORM 프레임워크를 도입하려면 데이터베이스 접근 계층과 비즈니스 로직 계층을 모두 리팩터링해야 한다. 그나마 계층 구분을 잘해놓은 프로젝트일 때에야 리팩터링을 할 엄두라도 날 것이다.

DTS를 이용한 스크립트 백업

레가시 프로젝트라면 좀더 수월한 접근 방법이 있다. Microsoft SQL Server 에 한정하는 이야기이지만 데이터 변환 서비스를 이용하면 된다.

DTS를 이용한 스크립트 백업 #1

#2 DTS를 이용한 스크립트 백업

DTS라 하면 보통 위와 같은 GUI 화면이 친숙하다. 어떤 데이터를 원하는지, 어떤 포맷으로 꾸미길 원하는지 선택하면 사용자가 뜻하는 대로 데이터베이스 객체와 레코드를 스크립트로 뽑아준다.

DTS 는 콘솔 버전도 있다. 그래서 간단한 작업을 할 때는 특별한 준비 없이 자동화에 써먹을 수 있다. 하지만 안타깝게도 특정 객체에 대한 예외 처리 등 복잡한 구현에는 쓰기 불편하다.

그래서 복잡한 작업을 할 때는 Microsoft 가 제공하는 DTS API (SQL Server Management Objects, 일명 SMO)를 이용한다. SMO 는 하위 수준의 API 를 제공하기 때문에 복잡한 기능을 구현하는데 적합하다. 그래서 개인적으로 지인과 진행하는 오픈소스 프로젝트 Earlgrey에서는 이를 기반으로 MSBuild 용 데이터베이스 추출 기능인 GenerateSqlScripts 를 구현하였다(참고 문헌 – UnitBuild 배포).

DTS를 이용한 스크립트 백업 #2

#3 DTS를 이용한 스크립트 백업

GenerateSqlScripts 를 사용하여 소스 코드를 버전 관리할 때는 위와 같은 절차를 거친다.

  1. 프로그래머와 데이터베이스 개발자가 개발 데이터베이스에 새 기능을 추가한다.
  2. GenerateSqlScripts 로 변경된 내역을 스크립트로 추출한다.
  3. 전에 뽑아 놓은 스크립트와 비교하여 이상한 점이 없는지 확인한다. 바뀌거나 추가된 코드는 SVN 폴더에서 색으로 표시된다.
  4. SVN 에 바뀐 코드를 커밋한다.
DTS 방식의 세부 구현

#4 DTS 방식의 세부 구현

위의 스크린샷은 컴뱃암즈 프로젝트에 실제 사용하는 코드 예제이다(NDC 발표 때 공개를 허락 받았다). 이 예제는 GenerateSqlScripts 를 활용하는 방법을 보여준다. 테이블은 보통 기획 테이블과 히스토리 테이블로 구분된다. 기획 테이블은 버전 관리해야 하는 레코드가 들어간다. 온라인으로 판매하는 아이템의 종류(호박 머리가 여기 들어간다)라던가, 각 캐릭터의 특성은 기획 테이블에 들어간다. 그에 비해 히스토리 테이블은 그 정의(스키마)만 관리하면 되고 레코드는 필요 없는 게 보통이다. 사용자의 아이템 구매 내역 등은 아무래도 버전 관리의 대상이 되기 힘들 것이다.

첫 번째 코드는 기획 테이블을 추출하는 예이다. 스키마와 레코드를 함께 스크립트로 뽑으라고 지시한다.

두 번째 예제는 히스토리 테이블을 뽑아내는 예이다. 스키마만 스크립트로 추출한다.

마무리

데이터베이스 버전 관리의 필요성과 방법에 대해 알아보았다. 대부분의 한국 게임 개발사가 온라인 서비스에 주력하는 이상 이와 같은 관리의 필요성은 차차 증가하리라 생각한다. 이 글이 이러한 요구에 대처하는 개인과 조직에 도움이 되길 기대한다.

This work, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.