결정-0054: 마이그레이션이 스키마 원본이고 코드는 생성물이다
상태
Accepted
맥락
스키마와 코드가 어긋난 상태를 언제 발견하는가가 이 결정의 쟁점입니다.
엔티티에서 스키마를 자동 생성하는 구성은 개발 환경에서 편하지만 운영에서 쓸 수 없습니다. 그래서 실무에서는 기동 시점에 스키마와 엔티티를 대조하는 검증 모드를 씁니다. 이 구성에서는 컬럼이 반영되지 않은 채 애플리케이션이 먼저 배포되면 그 환경이 기동되지 않습니다. 발견 시점이 배포 이후입니다.
스키마에서 코드를 생성하는 구성은 반대 방향입니다. 다만 생성기가 실행 중인 데이터베이스에 붙는 방식을 고르면 빌드가 외부 상태에 의존하게 되고, CI 가 컨테이너를 먼저 띄워야 합니다.
결정
마이그레이션 파일이 스키마의 단일 원본입니다. 생성 코드는 항상 그로부터 파생됩니다.
| 항목 | 결정 내용 |
|---|---|
| 마이그레이션 | 버전이 붙은 SQL 파일로 관리하고 적용 이력을 도구가 기록합니다 |
| 코드 생성 | 마이그레이션 SQL에서 직접 생성합니다. 실행 중인 데이터베이스가 필요하지 않습니다 |
| 생성물 | 빌드 산출물 디렉터리에만 두고 커밋하지 않습니다 |
| 정적 분석 | 생성 코드를 포맷 · 컨벤션 · 버그 패턴 검사에서 제외합니다 |
검토한 대안
실행 중인 데이터베이스에서 생성한다
| 구분 | 내용 |
|---|---|
| 장점 | 실제 스키마를 그대로 읽으므로 마이그레이션 해석 차이가 없습니다 |
| 단점 | 빌드가 외부 상태에 의존합니다. CI 가 컨테이너를 띄워야 하고, 개발자마다 로컬 DB 상태가 달라 생성 결과가 갈립니다 |
| 기각 사유 | 빌드가 재현 가능해야 한다는 조건이 더 중요합니다 |
생성 코드를 커밋한다
| 구분 | 내용 |
|---|---|
| 장점 | 생성 없이 바로 빌드됩니다. 코드 리뷰에서 스키마 변경의 영향이 눈에 보입니다 |
| 단점 | 스키마와 생성물이 어긋난 상태가 저장소에 존재할 수 있습니다. 재생성을 잊은 커밋이 그 상태를 만듭니다 |
| 기각 사유 | 단일 원본을 두 벌로 만드는 선택입니다. 어긋남을 방지하려면 CI 가 재생성 후 차이를 검사해야 하는데, 그럴 바에는 커밋하지 않는 편이 단순합니다 |
결과
스키마와 코드가 어긋난 상태가 빌드 시점에 드러납니다. 기동 시점이나 배포 이후로 미뤄지지 않습니다. 존재하지 않는 컬럼을 참조하면 컴파일이 실패합니다.
컨테이너 없이 빌드가 되므로 CI 구성이 단순해집니다. 컨테이너가 필요한 것은 통합 테스트뿐입니다.
감수하는 것은 생성기가 마이그레이션 SQL을 해석하는 범위입니다. 데이터베이스 고유 구문 중 일부는 생성기가 이해하지 못할 수 있으며, 그 경우 해당 구문을 피하거나 생성 대상에서 제외해야 합니다. 실제 데이터베이스가 아니라 파서를 통과하는 것이 기준이 되므로, 마이그레이션을 쓸 때 그 제약을 알고 있어야 합니다.