파트 2: 젠의 새로운 플레이북
작성자: Pramod Sadalage , Kevin Hartman
이 시리즈는 20년이 지난 지금, 진화적 데이터베이스 설계(Evolutionary Database Design) 방법론을 다시 살펴봅니다. 코드로 관리하는 데이터베이스 변경(database-changes-as-code)의 핵심 제약 조건은 항상 공유 데이터베이스 리소스에 있었습니다. Databricks Lakebase의 copy-on-write 브랜칭을 사용하면 테라바이트 규모의 프로덕션 데이터베이스에서 생성 시 스토리지 사용량이 전혀 없고 1초 만에 완료되는 브랜치 생성이 이제 O(1) 작업이 되며, 실천법 #4(모든 사람이 자신만의 데이터베이스 인스턴스를 갖는다)를 이상적인 목표로만 머물게 했던 제약이 사라졌습니다. 이 시리즈에서 저자는 제약 조건이 사라질 때 무엇이 변하는지 설명합니다. 방법론 자체는 그대로 유지되지만, 최초로 등장하는 실천법들, 자동으로 이루어지는 팀 규모의 거버넌스, DBA의 역할 진화, 그리고 에이전트가 인간 동료들과 공유하는 새로운 기능 등이 그것입니다.
젠(Jen)은 Evolutionary Database Design에 등장하는 개발자 캐릭터입니다. 이 에세이에서 그녀는 일상적인 사용자 스토리로 데이터베이스 리팩터링을 구현하여 inventory_code 필드를 location_code, batch_number, 및 serial_number(으)로 분할함으로써, DBA와 개발자가 협업할 수 있고, 스키마가 소규모로 점진적으로 진화할 수 있으며, 마이그레이션을 통해 변경 사항을 안전하게 전달할 수 있음을 보여주었습니다.
이 시리즈는 20년 후의 젠의 이야기로 이어집니다. 그녀가 따르는 방법론은 2003년에 따랐던 것과 동일합니다. 새로운 점은 lakebase 아키텍처를 통해 가능해진 워크플로의 기술적 기능인 copy-on-write 데이터베이스 브랜칭입니다. 이를 통해 그녀가 읽어왔던 실천법들이 프로덕션 규모에서 운영상 실제로 구현될 수 있게 되었습니다. 이 시리즈의 세 파트 전체에서 그녀는 하루 일과(파트 1), 새로운 플레이북(파트 2), 그리고 팀(파트 3)이라는 세 가지 범위에서 동일한 젠으로 등장합니다.
파트 1에서는 젠이 하나의 기능을 구현하는 과정을 살펴보았습니다. 그녀가 따른 실천법들은 2003년 Evolutionary Database Design 에세이에 설명되어 있고, 2006년 Refactoring Databases 서적에서 확장되었으며, 2010년 Continuous Delivery 서적(12장)에서 CI/CD 파이프라인에 도입되었습니다.
2003년 에세이에서는 7가지 실천법을 제시했습니다. 이 중 5가지는 2026년까지 적용하는 데 한계가 있었습니다.
Databricks Lakebase가 도입한 기술은 위의 실천법을 구현하는 데 가로막던 장애물을 제거합니다. Databricks Lakebase는 나머지 Databricks 레이크하우스가 실행되는 것과 동일한 오브젝트 스토리지 레이어(데이터 레이크)를 사용하는 관리형 Postgres 데이터베이스입니다. 데이터베이스의 데이터는 공유되는 내구성 있는 스토리지(실질적으로 S3 버킷)에 저장되며, Postgres 엔진은 그 위의 별도 컴퓨팅 레이어로 실행됩니다. 컴퓨팅과 스토리지는 독립적으로 확장됩니다. 엔진은 부하가 걸릴 때 확장(scale up)하고, 트래픽이 감소할 때 축소(scale down)하며, 유휴 상태일 때는 제로(0)로 축소할 수 있습니다. Lakebase는 Unity Catalog와 통합되어 여러 환경에서 통합된 거버넌스를 제공합니다.
Copy-on-write 데이터베이스 브랜칭은 분리된 아키텍처 덕분에 대규모로 실용화된 기술입니다. 브랜치는 분기 마커와 함께 동일한 공유 스토리지에 대한 새 포인터를 생성합니다. 브랜치에 쓰기 작업이 발생하기 전까지는 상위(parent)와 모든 페이지를 공유합니다. 브랜치에 쓰기가 발생하면 수정된 페이지 페이지만 분기되고 상위는 그대로 유지됩니다. 브랜칭은 메타데이터 작업이므로 데이터 복사가 필요하지 않으며, 상위 크기에 관계없이 약 1초 만에 완료됩니다. 브랜치는 변경된 페이지의 데이터만 유지합니다.
브랜치의 기 술적 비용이 내부 데이터 크기와 분리되면, 실천법 #4(모든 사람이 자신만의 데이터베이스 인스턴스를 갖는다)의 이면에 있던 제약이 해제됩니다. 개발자별, PR별, 실험별 브랜치가 일상화됩니다. 상위의 보완 레이어가 필요 없어집니다. 테스트 루프에서 모크(mock)가 제거되고, 테스트별 브랜치의 실제 Postgres로 대체됩니다. 공유 스테이징이 스키마 변경을 테스트할 수 있는 유일한 공간이 아니게 됩니다. 인메모리 데이터베이스 대체재(H2, SQLite)가 단위 테스트 레이어에서 제거됩니다. 로컬 데이터베이스를 실행하기 위해 Docker 기반 컨테이너를 생성하는 DevOps 비용이 필요하지 않으며, 브랜치가 셀프 서비스로 제공되므로 프로비저닝을 위한 DBA 티켓 대기열이 줄어듭니다.
이 기술은 방법론 최적화를 가능하게 하고 원래 2003년 포스트의 이면에 있는 실천법의 목표를 완성합니다.
Lakebase의 copy-on-write 데이터베이스 브랜칭은 기존 실천법에 대한 이전의 제한 사항을 해제하고, 더 자세히 설명할 네 가지 추가 실천법을 가능하게 합니다.
Lakebase가 제공하는 기능 덕분에 가장 크게 개선된 두 가지 프랙티스는 #4(모든 사람이 자신만의 데이터베이스 인스턴스를 가짐)와 #5(개발자가 데이터베이스 변경 사항을 지속적으로 통합함)입니다. 이제 단순히 모든 사람이 데이터베이스를 갖는 것을 넘어, 거의 비용과 시간을 들이지 않고도 모든 PR이나 모든 브랜치, 또는 브랜치당 여러 개의 데이터베이스를 가질 수 있습니다. 이 메커니즘은 모든 프로젝트에 스캐폴딩할 수 있는 두 개의 GitHub Actions 워크플로 템플릿을 사용하여 자동화할 수 있습니다.
PR별 브랜치 생성. pr.yml이(가) pull_request: [opened, synchronize]에서 트리거되어 PR의 베이스 브랜치에서 포크된 ci-pr-<N>을(를) 생성합니다:
동일한 작업이 CI 브랜치에 마이그레이션을 적용하고 실제 Postgres를 대상으로 애플리케이션의 테스트 제품군을 실행합니다. 워크플로의 전체 예시는 다음에서 확인할 수 있습니다: pr.yml
PR에 게시된 스키마 diff. 동일한 pr.yml 작업이 두 브랜치의 스키마를 덤프하고, diff 형식을 지정하여 PR 댓글로 게시합니다. 이를 통해 DBA는 다른 코드 리뷰어처럼 비동기식으로 리뷰를 진행할 수 있습니다(프랙티스 #1, 재구성):
DBA, 코드 리뷰어, 팀, 그리고 마이그레이션을 작성한 에이전트는 모두 PR에서 동일한 아티팩트를 볼 수 있습니다.
머지 시 브랜치 정리. merge.yml은(는) PR이 머지되는 즉시 CI PR 브랜치인 ci-pr-<N> 및 연결된 피처 브랜치의 Lakebase 브랜치를 삭제합니다:
머지 워크플로의 전체 예시는 여기에서 확인할 수 있습니다: merge.yml 수많은 브랜치가 생성되므로 분리되거나 사용되지 않는 브랜치를 제거하는 주간 정리 스크립트를 두는 것이 좋습니다. 예시 워크플로는 여기에서 확인할 수 있습니다: cleanup-orphans.yml. 마지막으로, 스테이징 또는 메인/운영 환경(이 개념은 3부에서 자세히 설명합니다)에 사용되는 '계층형(tiered)' 브랜치로 머지하는 경우, 사용자가 실제로 사용 중이고 지속적으로 데이터를 추가하는 환경에 최종 마이그레이션을 적용하기 전에, 해당 계층에서 새 브랜치를 생성하여 마이그레이션을 테스트하도록 워크플로를 구성할 수 있습니다.
이러한 워크플로가 함께 작동하면 개발자의 규율에 의존하는 것이 아니라 파이프라인의 속성으로서 모든 PR이 자체 데이터베이스를 갖고 브랜치가 임시로 유지되도록 강제할 수 있습니다.
규칙. DBA는 최종 검토(gate-review) 시점뿐만 아니라 기능 개발 전반에 걸쳐 개발자와 협업합니다. 이 협업은 다른 코드 리뷰어가 참여하는 방식과 마찬가지로 PR 내에서 비동기식으로 진 행됩니다.
이것이 이제 지속 가능한 습관이 된 이유는 무엇일까요? 스키마 diff 및 마이그레이션 테스트 결과가 모든 PR에 자동으로 표시됩니다(위의 CI에서 워크플로가 실행되는 방식 참조). DBA는 본인의 일정에 맞춰 구체적인 아티팩트를 검토합니다. 마이그레이션이 실제 데이터가 있는 CI 브랜치에서 이미 실행되었으므로, DBA가 머릿속으로 변경 사항을 시뮬레이션해 볼 필요가 없습니다.
작동 방식:
migrations/, db/, 스키마 테스트 디렉터리)의 CODEOWNER입니다.안티패턴. 검토할 명확한 아티팩트가 있음에도 불구하고 PR 흐름에 DBA를 포함하지 않는 것.
또한 DBA 역할에는 팀 규모의 정책 관리 및 거버넌스에 대한 새로운 책임이 추가됩니다. 3부에서 이 내용을 다룹니다.
규칙. 모든 SQL 파일, 마이그레이션 스크립트, 스키마 테스트는 애플리케이션 코드와 동일한 리포지토리에 위치합니다. 스키마 diff 및 마이그레이션 테스트 결과는 PR 시점의 출력으로 아티팩트 세트에 추가됩니다.
왜 이것이 지금 지속 가능한 습관이 되었을까요? 브랜칭을 통해 세트에 두 개의 새로운 아티팩트가 추가됩니다. 바로 PR별 스키마 diff와 PR별 스키마 마이그레이션 테스트 결과입니다. 둘 다 실제 브랜치 상태를 기반으로 CI에서 생성됩니다. 둘 다 무엇이 변경되었고 변경 마이그레이션 스크립트가 어떻게 수행되었는지에 대한 구체적인 증거로서 PR에 남게 됩니다.
작동 방식:
migrations/, db/migration/, alembic/versions/, 프레임워크에 따라 다름).안티패턴. PR 흐름 외부에서 스키마 diff를 생성하는 것 (리뷰어가 별도로 열어야 하는 대시보드). 아티팩트는 리뷰가 진행되는 곳에 있어야 합니다. 스키마 변경 사항은 코드 변경 사항과 연결되어 있으며, 이 종속성을 깨뜨리면 배포 시 다운스트림 문제가 발생하기 때문입니다.
규칙. 어떤 환경에서도 수동 ALTER TABLE을 수행하지 않습니다. 모든 스키마 변경은 버전이 관리되고 체크인된 마이그레이션 스크립트입니다. 마이그레이션은 멱등성을 가집니다.
왜 이것이 지금 지속 가능한 습관이 되었을까요? 아티팩트로서의 마이그레이션 규칙은 2003년 이후로 변하지 않았습니다. 새로운 점은 멱등성이라는 작성 규율입니다. 전환 과정 동안 동일한 마이그레이션이 여러 브랜치에서 실행되므로 매번 동일하게 작동해야 합니다. 재적용 시 실패하는 마이그레이션은 버그입니다.
작동 방식:
flyway, liquibase, Knex, Alembic 등과 같은 마이그레이션 프레임워크를 사용하세요. 이러한 프레임워크는 어떤 마이그레이션이 실행되었고 실행되지 않았는지 추적하므로, 팀은 메타데이터 테이블에서 변경 사항을 추적하여 아직 적용되지 않은 변경 사항만 적용하는 flyway migrate와 같은 명령을 적용할 수 있습니다.안티패턴. 브랜치에서 발생한 로컬 변경 사항 때문에 스키마가 특정 중간 상태에 있어야만 작동하는 마이그레이션. 마이그레이션은 이전 마이그레이션을 포함하는 모든 상위 브랜치에 대해 올바르게 적용되어야 합니다.
규칙. 모든 개발자, 모든 PR, 모든 실험, 모든 테스트 실행은 자신만의 Lakebase 브랜치를 가집니다.
왜 이것이 지금 지속 가능한 습관이 되었을까요? Docker 컨테이너를 생성하고, 로컬 데이터베이스 서버를 설치하고, 라이선스를 획득하고, 기존 스키마와 테스트 데이터로 빈 데이터베이스를 채우는 추가적인 노력이 더 이상 필요하지 않습니다. 간단한 create-branch Lakebase 명령만으로 1TB 데이터베이스를 1MB 데이터베이스와 마찬가지로 단 1초 만에 브랜칭할 수 있습니다. 생성 시 데이터가 복사되지 않으며, 수정된 페이지만 스토리지를 소비합니다. 개발자별, PR별, 실험별 인스턴스 생성이 일상화됩니다.
작동 방식:
databricks postgres create-branch 또는 SCM 확장의 branch-create 흐름을 통해 필요에 따라 생성됩니다.pr.yml), 병합되거나 닫힐 때 삭제됩니다(merge.yml). PR 및 병합 코드 조각은 위의 CI에서 워크플로가 실행되는 방식 을 참조하세요.안티패턴. "편의상" 팀 전체가 개발 데이터베이스를 공유하는 것. 브랜치가 병합되는 순간 파트 1에서 언급한 경합 중심의 직렬화 문제가 다시 발생합니다.
Jen의 사례가 확장되는 부분입니다. 그녀의 개발자별 브랜치는 기능 개발 시작 시 스테이징에서 포크되었습니다. CI 브랜치는 PR이 열릴 때 스테이징에서 포크되었습니다. 그녀의 A/B 탐색 브랜치(실천법 #9)는 스테이징에서 병렬로 포크되었습니다. 하나의 기능에 대해 4개의 브랜치가 단 몇 초 만에 모두 격리된 상태로 생성되었습니다.
규칙. 모든 PR은 마이그레이션이 적용되고 실제 Postgres를 대상으로 테스트가 실행되는 새로운 Lakebase 브랜치에 대해 CI를 거칩니다.
왜 이것이 지금 지속 가능한 습관이 되었을까요? CI 파이프라인은 2010년부터 마이그레이션 규율을 유지해 왔습니다. 새로운 점은 파이프라인별 격리입니다. 각 PR이 고유한 브랜치를 가지므로 경합 없이 실제 형태의 데이터를 대상으로 통합이 실행됩니다.
작동 방식:
lakebase-migrate apply를 통해 브랜치에 마이그레이션이 적용됩니다.안티패턴. 공유 스테이징을 대상으로 PR 검증을 실행하는 것. 직렬화 문제가 다시 발생하며 PR별 격리 특성이 손실됩니다.
규칙. 스키마 변경은 Split Column, Rename Column, Move Column, Replace Type 등 명명된 리팩터링 패턴을 따릅니다. 각 패턴에는 명시적인 전환 메커니즘이 있습니다 (기존 항목과 새 항목을 병렬로 유지, 기존 항목에서 데이터 채우기, 리더 전환, 기존 항목 삭제).
왜 이것이 지금 지속 가능한 습관이 되었을까요? databaserefactoring.com의 2006년 카탈로그에는 실제 예제와 함께 70개 이상의 리팩터링이 명시되어 있습니다. 2026년에 새로워진 점은 전환 메커니즘을 저렴하게 연습할 수 있는 공간이 생겼다는 것입니다. 개발자 브랜치에서 연습을 진행하고, CI 브랜치에서 검증하며, 프로덕션에는 검증된 결과만 반영됩니다.
작동 방식:
안티패턴. 명명된 리팩터링에 매핑되지 않는 일회성 스키마 변경. 70개 이상의 카탈로그가 일반적인 사례를 다룹니다. 만약 여기에 해당하지 않는다면 여러 리팩터링을 하나의 마이그레이션으로 결합하고 있을 가능성이 높으므로 분할해야 합니다.
Jen의 예시가 확장되는 부분. 그녀의 V87 마이그레이션은 열 분할(Split Column) 리팩터링입니다. 즉, inventory_code을(를) location_code, batch_number, 그리고 serial_number(으)로 분할하는 것입니다. databaserefactoring.com/SplitColumns.html의 카탈로그 페이지에 전환 메커니즘이 명시되어 있습니다. 그녀의 브랜치는 연습 공간이었고, PR의 CI 실행은 검증 과정이었습니다.
규칙. 개발자는 필요할 때 언제든지 브랜치의 데이터베이스 상태를 새로 고칠 수 있습니다. 상위 브랜치의 현재 상태로 재설정하거나, 프로덕션에서 새 브랜치를 포크하거나, 실험용 브랜치를 폐기하거나, 팀원과 브랜치를 공유하는 등의 작업을 모두 몇 초 만에 수행할 수 있습니다.
이것이 왜 이제 지속 가능한 습관이 되었을까요? 2026년의 '온디맨드(필요할 때 언제든지)'는 프로덕션 형태의 데이터를 대상으로 격리된 환경에서 1초 만에 수행됨을 의미합니다. 이러한 작업은 운영 일정이나 DBA 대기열을 확인할 필요가 전혀 없습니다.
작동 방식:
databricks postgres create-branch --source production.databricks postgres delete-branch.안티패턴. 브랜치를 목적 이상으로 오랫동안 유지하려는 태도입니다. 마이그레이션 결과물이 영구적인 아티팩트이며, 브랜치는 임시 작업 공간일 뿐입니다.
규칙. 파괴적인 작업의 영향 범위(blast radius)가 0일 때, 파괴적 테스트는 분기별 행사가 아닌 일상적인 옵션이 됩니다.
이것이 왜 이제 지속 가능한 습관이 되었을까요? 브랜치는 1초 만에 재설정됩니다. 브랜치에 수행한 모든 작업은 동일한 상위 브랜치에서 새 브랜치를 생성하여 되돌릴 수 있습니다. 파괴적 테스트를 위해 더 이상 운영 일정이나 승인 절차를 거칠 필요가 없습니다.
이제 일반적인 기능 개발 주기에 포함될 수 있는 작업들: