6.1Schema Migrations
Migration File을 통해 데이터베이스 구조를 변경하기
Schema Migrations
스키마 마이그레이션이란 데이터베이스의 구조를 바꾸는 것이다. 포스팅 시리즈에서 계속 예를 들고 있었던 인스타그램 데이터베이스 클로닝 프로젝트의 사례를 통해 Schema Migration을 진행해보자.
실무에서는 개발 환경과 실제 환경이 구분되어 있다. 예를 들어, 개발 환경은 로컬 머신 내의 PostgreSQL이고 실제 환경은 AWS다.
comments
테이블을 관리하는 담당자라고 할 때, 개발팀에서 contents
라는 컬럼명이 어렵다고 body
로 바꿔달라고 요청을 하는 상황을 가정해보자. 로컬에선 아래와 같은 쿼리를 실행하면 된다.
sqlALTER TABLE comments RENAME COLUMN contents TO body;
문제 1: 클라이언트 코드
하지만, AWS에서 같은 쿼리를 사용하면 문제가 생긴다. 왜냐면 유저들이 커멘트를 달려고 할 때마다 API Server에선 SQL 쿼리를 보내서 커멘트를 추가하는데, API에선 아래와 같은 쿼리를 계속해서 쓰고 있을 것이기 때문이다:
sqlINSERT INTO comments (contents, post_id, user_id) VALUES ('asdf', 2, 3);
데이터베이스 구조를 변경할 때 클라이언트 측 변경도 함께 이루어져야만 한다.
어떤 상황에선, 서비스를 잠시 중단하고 클라이언트 코드를 변경하고 데이터베이스 구조를 변경한 후 서비스를 재개함으로 해결할 수 있다. 하지만, 어떤 서비스들은 중단하는게 불가능한 경우들이 있다.
문제 2: 협업시 불편함
API 코드를 변경해서 깃헙에 올리면, 리뷰하는 동료들 입장에선 변경된 데이터베이스 구조는 볼 수 없고 res.body
만 변경되는 것을 보기 때문에 제대로 된 리뷰를 하기 어렵다. 다시 말해, 변경된 코드를 받아서 실행하면 앞서 우리의 로컬 머신에서 변경한 데이터베이스 구조는 리뷰어들이 수동으로 적용하지 않는 한 제대로 작동하지 않는다.
다른 개발자들과 협업시에는 데이터베이스-코드를 엮을 수 있는 방식이 필요하다.
Schema Migration File
지금까지 PGAdmin4에 ALTER TABLE
키워드로 테이블 구조를 바꿨다면, 문제를 해결하기 위해 우리는 Migration File을 쓰게 된다.
Migration File은 2개의 파트로 이루어지는데, Up 파트는 DB 구조를 바꾸는 쿼리를 포함한다. Down 파트는 Up 파일에서 바꾼 DB 구조를 정확히 원상복귀하는 쿼리를 포함한다.
예를 들어, 앞서 contents
라는 컬럼명을 body
로 바꾸는 쿼리가 Up 파트라면, Down 파트는 아래와 같이 반대 방향의 쿼리다:
sqlALTER TABLE comments RENAME COLUMN body to contents;
마이그레이션 파일을 쓰면, comments
테이블을 만들 때도 Up과 Down을 작성해야 한다.
- Up: 테이블 생성
sqlCREATE TABLE comments ( id SERIAL PRIMARY KEY, created_at TIMESTAMP, updated_at TIMESTAMP, contents VARCHAR(240) );
- Down: 테이블 삭제
sqlDROP TABLE comments;
이렇게 Up과 Down 쿼리를 모두 가지고 있는 파일들을 공유하면, 모두가 동기화된 데이터베이스를 가질 수 있다. 데이터베이스 구조를 변경할 때는 API 서버를 디플로이할 동안 마이그레이션 파일들을 실행한다. 코드 리뷰를 할 때도, 바꾼 API 코드와 마이그레이션 파일을 모두 리뷰 요청하는 방식으로 코드 및 데이터베이스 구조 모두를 공유하고 점검할 수 있다.
스키마 마이그레이션 라이브러리들
라이브러리를 쓰면 마이그레이션을 보다 효율적으로 할 수 있다. 다만, 쿼리 작성과 관련해선 라이브러리들이 써주는 것 대신 직접 쿼리를 작성하는 것이 좋다. 라이브러리들이 의도한것과 다른 전제를 가지고 쿼리를 작성할 수도 있기 때문이다.
자바스크립트
자바
파이썬
이번 예시에선 첫번째로 언급한 node-pg-migrate를 사용해서 마이그레이션을 진행해보자.
자바스크립트 예시: node-pg-migrate
새로운 폴더를 만들고, 라이브러리를 설치한다. pg
(Postgres)도 함께 설치한다.
bashnpm install node-pg-migrate pg
PGAdmin4에서, 로컬 서버를 우클릭해 새로운 데이터베이스를 만든다. 예시에선 새 데이터베이스 이름은 socialnetwork로 한다.
앞서 라이브러리를 설치한 폴더의 package.json
파일에서 스크립트를 변경한다:
javascript{... "scripts": { "migrate": "node-pg-migrate" }, }
그리고 터미널에서 해당 스크립트를 실행한다. "create table comments"라는 마이그레이션 파일을 만들라는 의미다.
npm run migrate create table comments
그러면 migrations
폴더가 생기고, 아래와 같은 자바스크립트 파일이 생긴다.
javascript/** * @type {import('node-pg-migrate').ColumnDefinitions | undefined} */ exports.shorthands = undefined; /** * @param pgm {import('node-pg-migrate').MigrationBuilder} * @param run {() => void | undefined} * @returns {Promise<void> | void} */ exports.up = (pgm) => {}; /** * @param pgm {import('node-pg-migrate').MigrationBuilder} * @param run {() => void | undefined} * @returns {Promise<void> | void} */ exports.down = (pgm) => {};
up
함수와 down
함수에 쿼리를 입력한다.
javascriptexports.up = (pgm) => { pgm.sql(` CREATE TABLE comments ( id SERIAL PRIMARY KEY, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, contents VARCHAR(240) NOT NULL ); `); }; exports.down = (pgm) => { pgm.sql(` DROP TABLE comments; `); };
이렇게 마이그레이션 파일을 작성했으면 OS에 따라 다른 커맨드를 통해 실행한다.
MacOS에선 터미널에 DATABASE_URL=postgres://USERNAME@localhost:5432/socialnetwork npm run migrate up
을 타이핑하고 실행한다. (내 경우는 USERNAME대신 sungyupju를 입력했다.)
실행하면 어떤 마이그레이션이 진행되었는지를 보여주고 성공했다는 메시지가 뜬다. PGAdmin4에서도 이렇게 생성한 comments 테이블을 확인할 수 있다.
만약 마이그레이션을 잘못한 경우, 위의 커맨드에서 up
을 down
으로 바꾼 명령어를 실행하면 테이블이 지워진다. 즉, 원상복귀된다.
마이그레이션 파일 수정하기
이전의 예시에서 하려고 했던것 처럼, 컬럼의 이름을 바꿔보자. 아래의 커맨드를 실행한다(rename contents to body라는 마이그레이션 파일 생성).
bashnpm run migrate create rename contents to body
이후 파일을 작성한다.
javascriptexports.up = (pgm) => { pgm.sql(` ALTER TABLE comments RENAME COLUMN contents TO body; `); }; exports.down = (pgm) => { pgm.sql(` ALTER TABLE comments RENAME COLUMN body TO contents; `); };
그리고, 앞서 실행했던것처럼 up
명령어를 실행하면 된다. PGAdmin4에서 comments
테이블의 컬럼명이 body로 바뀐것을 확인할 수 있다.