주요 컨텐츠로 이동
파트너

진화하는 데이터베이스 개발 지원: Lakebase를 이용한 데이터베이스 브랜칭

주로 세 부분으로 구성된 시리즈

작성자: Pramod Sadalage , Kevin Hartman

이 시리즈가 존재하는 이유

진화적 데이터베이스 설계에 설명되고 데이터베이스 리팩토링: 진화적 데이터베이스 설계에서 구현된 방법론은 20년 동안 명확했습니다. 7가지 실천 방법, 70개 이상의 명명된 리팩토링 카탈로그, 전환 메커니즘 – 이 모든 것이 문서화되고, 동료 검토를 거치고, 교육되었습니다.

그 방법론은 2010년 지속적 배포(12장: 데이터 관리)과 함께 CI/CD에 도달했습니다. 마이그레이션은 배포 파이프라인에서 일등석 아티팩트가 되었습니다. 코드로서의 데이터베이스 변경이라는 규율은 더 넓은 CI/CD 운동에 도달했습니다. CD가 해결하지 못한 것은 파이프라인별 격리였습니다. 파이프라인은 마이그레이션을 실행할 수 있었지만 여전히 대상 데이터베이스가 필요했고, 그 대상은 공유되었습니다. 실천 방법 #4 – 모든 사람이 자신의 데이터베이스 인스턴스를 갖습니다 – 대부분의 팀에서는 여전히 열망적인 상태로 남아 있었습니다. 왜냐하면 진정한 개발자별 프로덕션 모양의 데이터베이스는 시간, 돈, DBA 사이클을 소비하기 때문입니다. 격차를 해소하기 위해 등장한 보상 계층(모의 객체, 공유 스테이징 환경, 인메모리 데이터베이스 대체물, DBA 티켓 대기열)은 설계가 아닌 기본값으로 기본 방법론이 되었습니다.

2026년, 복사 후 쓰기(copy-on-write) 데이터베이스 분기가 Databricks Lakebase에 도입됩니다. 테라바이트 규모의 프로덕션 데이터베이스의 1초, 생성 시 제로 스토리지 분기는 이제 O(1) 작업입니다. 실천 방법 #4를 열망적인 상태로 유지했던 제약이 해제되었습니다.

이 시리즈는 제약이 해제될 때 무엇이 변하는지 설명합니다. 방법론은 그대로 유지되지만, 처음으로 등장하는 실천 방법, 자동화되는 팀 규모의 거버넌스, DBA의 역할 진화, 에이전트가 인간 동료와 공유하는 새로운 하위 시스템이 그것입니다.

Jen 소개

Jen은 진화적 데이터베이스 설계의 개발자 캐릭터입니다. 해당 에세이에서 그녀는 데이터베이스 리팩토링 – inventory_code 필드를 location_code, batch_number, 그리고 serial_number로 분할하는 것 – 을 일상적인 사용자 스토리로 구현하여 DBA와 개발자가 협력할 수 있고, 스키마가 작은 증분으로 진화할 수 있으며, 마이그레이션이 변경 사항을 안전하게 전달한다는 것을 보여주었습니다.

이 시리즈는 20년 후 Jen을 따라갑니다. 그녀가 따르는 방법론은 2003년에 따랐던 것과 동일합니다. 새로운 점은 그녀의 워크플로 아래에 있는 하위 시스템입니다. 복사 후 쓰기 데이터베이스 분기는 그녀가 읽고 있던 실천 방법들을 프로덕션 규모에서 운영상 현실로 만듭니다. 이 시리즈의 세 부분에 걸쳐 그녀는 세 가지 범위 – 그녀의 하루(1부), 그녀의 새로운 플레이북(2부), 그리고 그녀의 팀(3부) – 에서 동일한 Jen입니다.

1부: Jen의 이야기: 하나의 기능, 하나의 데이터베이스 변경

이것이 어떻게 작동하는지 이해하기 위해, Jen이라는 개발자가 사용자가 재고에 있는 제품의 위치, 배치 및 일련 번호를 보고, 검색하고, 업데이트할 수 있도록 하는 작업을 구현하는 여정을 살펴보겠습니다.

다음은 Jen이 이 작업을 완료하기 위해 거쳐야 하는 다양한 단계를 설명하며, 이 단계들을 설명하면서 전통적인 데이터베이스를 사용할 때와 데이터베이스 분기를 최소한의 비용으로 허용하는 Lakebase를 사용할 때 Jen의 워크플로가 어떻게 변화하는지 비교해 보겠습니다.

Jen이 기능 작업 시작

Jen은 간단해 보이는 기능을 맡습니다. 제품 팀은 사용자가 재고 추가 중에 항목의 위치, 배치 및 일련 번호를 캡처하고 나중에 애플리케이션 흐름에서 사용할 수 있도록 하기를 원합니다. 외부에서 보면 변경 사항은 작게 느껴집니다. 화면에 필드를 추가하고, 값을 저장하고, 항목에 대한 재고 화면에 표시하고, 나중에 다운스트림 결정에 사용할 수도 있습니다.

Jen에게는 애플리케이션 변경이 쉽게 그려집니다. 그녀는 폼이 어디에 있는지 압니다. 요청을 처리하는 서비스를 압니다. 더 많은 속성이 필요한 모델 객체를 볼 수 있습니다. 그러나 변경 사항을 끝까지 추적하는 순간, 그녀는 실제 종속성, 즉 데이터베이스도 변경되어야 한다는 것을 알게 됩니다.

몇 가지 새로운 열이 필요하고, 프로덕션 환경의 기존 데이터는 보존되어야 하며 의미론적으로 올바르게 유지되어야 합니다. 애플리케이션은 이전 및 새 데이터를 안전하게 처리해야 하며, 새 필드가 올바르게 저장, 읽기 및 표시됨을 증명하기 위해 테스트를 추가해야 합니다. 간단해 보였던 기능은 이제 조정된 애플리케이션 및 데이터베이스 변경이 되었으며, 기존 프로덕션 스키마 및 데이터가 새 스키마로 마이그레이션되도록 보장하는 추가 책임이 따릅니다.

공유 데이터베이스

Jen은 앞으로 할 작업에 대한 코드 분기를 생성합니다. 팀은 공유 데이터베이스를 사용하고 있으며 나머지 팀원들도 개발을 위해 동일한 데이터베이스를 사용하고 있기 때문에, 그녀는 즉시 데이터베이스 계층에 도입할 변경 사항이 공유 데이터베이스의 다른 사용자에게 영향을 미칠 수 있다는 점을 생각하기 시작하고 다른 사람들에게 안전하게 만들 방법을 계획합니다. 로컬에서 애플리케이션 변경을 실행하고 단위 및 통합 테스트를 실행할 수 있을까요? 각 옵션에는 비용이 따릅니다. 기다릴 수 있습니다. 팀에 조정을 요청할 수 있습니다. Docker에서 자체 로컬 Postgres를 시작하고, 일주일 전의 오래된 pg_dump로 시드하고, 차이가 중요하지 않기를 바랄 수 있습니다. 컨테이너에서 로컬 데이터베이스를 실행하거나, 빠르게 실행되지만 잘못된 방언을 사용하는 인메모리 데이터베이스 H2 또는 SQLite를 실행하여 로컬에서는 테스트가 통과하지만 실제 Postgres에서는 알 수 없는 실패가 발생하도록 할 수 있습니다. 스키마 및 데이터 마이그레이션 스크립트를 테스트할 수 있을까요? 다른 사람을 망가뜨릴 것이라는 두려움은 그녀를 둔화시키고 동시에 여러 기능 구축 옵션을 실험하는 것을 허용하지 않습니다.

그림 1: 모든 유형의 사용자가 개발 데이터베이스에 액세스하는 공유 데이터베이스를 보여줍니다.

공유 데이터베이스에서는 한 개발자가 비즈니스 로직 변경을 테스트하고 있을 수 있고, 다른 개발자는 데이터 마이그레이션을 디버깅하고 있을 수 있으며, 다른 누군가는 Jen이 이해하지 못하는 테스트 데이터를 생성했을 수 있습니다. Jen이 공유 데이터베이스에 스키마 변경을 적용하면 다른 사람의 작업을 망가뜨릴 수 있습니다. 그녀가 테스트하는 동안 다른 사람이 스키마를 변경하면 그녀의 결과는 더 이상 신뢰할 수 없을 수 있습니다. 테스트 데이터를 추가하면 다른 개발자의 가정과 충돌할 수 있습니다.

Jen은 공유 데이터베이스가 비어 있을 때까지 기다릴 수 있습니다. 이는 팀을 충돌로부터 보호하지만, 작은 기능을 일정 문제와 생산성 손실로 만듭니다. 다른 개발자들과 수동으로 조정할 수 있습니다. “지금 개발 사용 중인가요?” “마이그레이션을 실행해도 될까요?” “다음 한 시간 동안은 데이터를 재설정하지 말아 주세요.” 마치 릴레이 경주에서 배턴처럼요. 이것은 한동안 작동하지만, 특히 원격 또는 여러 시간대에 있는 팀의 경우 확장되지 않습니다.

Jen은 또 다른 옵션을 생각합니다. 로컬 인메모리 데이터베이스를 사용하는 것입니다. 그녀는 이 설정이 팀의 나머지 개발자들이 사용하는 데이터베이스 상태와 일치하지 않는다는 것을 알고 있습니다. 즉, 그녀의 솔루션에 대한 확신을 갖지 못할 것이며, 변경 사항이 로컬에서는 작동하지만 나중에 스테이징 및 프로덕션과 같은 상위 환경의 실제 데이터 및 스키마를 만나면 실패할 수 있습니다.

Jen이 겪고 있는 실제 문제는 느린 피드백입니다. 변경 사항을 만들 수는 있지만, 변경 사항이 작동하는지 알아내는 데 시간이 걸립니다. 빠르고 현실적인 피드백 없이는 데이터베이스 변경이 팀이 신중하게 다루는 것이 되어 결국 작동하는 첫 번째 솔루션을 선택하고 실험하거나 여러 솔루션을 시도하지 않아 최적화되지 않은 솔루션, 생산성 감소 및 불만족스러운 개발자로 이어집니다.

개별 데이터베이스 분기

Lakebase를 사용하면 Jen은 개인 용도로 데이터베이스를 분기할 수 있으며, 이 기능은 그녀의 작업 방식을 완전히 바꿉니다.

공유 개발 데이터베이스를 사용할 수 있을 때까지 기다리는 대신, Jen은 기능에 대한 데이터베이스 분기 또는 databricks postgres create-branchVS Code / Cursor 확장 프로그램을 사용합니다. 이렇게 하면 작업의 형태가 즉시 변경됩니다. 더 이상 팀에 조용한 시간을 요청하지 않습니다. 더 이상 어떤 마이그레이션을 언제 실행할지에 대해 다른 개발자와 협상하지 않습니다. 그녀는 자신의 절반만 완료된 변경 사항을 다른 모든 사람의 절반만 완료된 변경 사항으로부터 보호하려고 더 이상 노력하지 않습니다. 그녀는 애플리케이션이 결국 프로덕션에서 사용할 데이터베이스 환경과 동일한 종류의 데이터베이스 환경에서 생성된 자신만의 격리된 데이터베이스 공간을 갖게 됩니다.

그림 2: 팀의 모든 구성원은 자신만의 데이터베이스를 가지며 필요한 경우 여러 데이터베이스를 가질 수 있습니다.

이 분기는 Jen에게 작업할 데이터베이스 상태의 빠른 복사본을 제공합니다. 이제 그녀는 프로덕션을 직접 쿼리하는 경우와 동일한 Postgres 엔진, 동일한 스키마, 동일한 거버넌스 정책 및 동일한 프로덕션 형태의 데이터를 갖게 됩니다. 유일한 차이점은 이 분기를 수정, 삭제 또는 다시 생성해도 다른 워크로드에 영향을 미치지 않는다는 것입니다. 그녀는 프로덕션과 다르게 작동하는 단순화된 로컬 데이터베이스를 상대로 테스트하는 것이 아닙니다. 그녀는 팀이 프로덕션에서 사용하는 것과 동일한 데이터베이스 유형, 데이터베이스 변경이 실제 세계에서 성공하거나 실패하게 만드는 동일한 종류의 스키마 규칙, 제약 조건, 인덱스, 참조 데이터 및 마이그레이션 기록을 사용하여 작업하고 있습니다. 이러한 현실성은 많은 데이터베이스 문제가 격리된 단위 테스트에서 나타나지 않기 때문에 중요합니다. 이러한 문제는 새로운 마이그레이션이 기존 구조, 기존 데이터, 기존 가정 및 기존 애플리케이션 동작과 충돌할 때 나타납니다.

이제 Jen은 데이터베이스 변경을 배포 단계뿐만 아니라 설계의 일부로 취급할 수 있습니다. 그녀는 먼저 명백한 버전을 시도할 수 있습니다. 새 열을 추가하고, 기존 열을 분할하기 위한 기본 로직을 설정하고, 데이터베이스 마이그레이션 스크립트를 만들고, 애플리케이션을 업데이트하고, 테스트를 실행합니다. 그런 다음 더 나은 질문을 할 수 있습니다. 이 마이그레이션 스크립트가 프로덕션 데이터 볼륨에 대해 작동해야 합니까? 프로덕션의 데이터 품질이 스크립트가 예상하는 대로입니까? 데이터 마이그레이션 스크립트가 누락된 비즈니스 정보를 숨기고 있습니까? 기본 설정은 간단한 열, 조회 테이블 또는 나중에 더 많은 정보가 올 것으로 예상되므로 별도의 item_information 테이블로 모델링되어야 합니까? 쿼리 패턴에 인덱스가 필요합니까? 이 설계가 다운스트림 보고를 더 쉽게 또는 더 어렵게 만들 것입니까? 이전 워크플로에서는 데이터베이스 변경이 비용이 많이 들기 때문에 이러한 질문이 종종 압축되었습니다.

그림 3: 데이터베이스 분기 기능으로 작업하는 Jen의 워크플로

분기된 워크플로에서는 Jen이 기능이 아직 형성되는 동안 이러한 질문을 탐색할 수 있습니다. DBA는 그녀와 협력하여 프로덕션의 미묘한 차이와 데이터 볼륨에 대해 안내하여 사후 검토자가 아닌 솔루션 설계에 귀중한 입력을 제공할 수 있습니다.

애플리케이션과 데이터베이스 변경을 함께 수행

Jen은 마이그레이션 스크립트를 작성합니다. 팀에서 Flyway, Liquibase, Alembic, Knex, Prisma 등 무엇을 사용하든 스크립트는 애플리케이션 변경과 함께 코드 리포지토리에 저장됩니다. 스키마 및 데이터 마이그레이션은 코드와 함께 이동합니다.

(이것은 열 분할 리팩토링이며, 7가지 실천 방안을 운영화한 책 Refactoring Databases에 분류된 약 70가지 패턴 중 하나입니다.)

그녀는 flyway migrate을 사용하여 분기에 마이그레이션을 적용합니다. 이 도구는 실제 형태의 데이터에 대해 1초도 안 되어 실행됩니다. 그녀는 세 개의 새 열을 읽고 쓰도록 리포지토리 코드를 업데이트합니다. 테스트 스위트를 실행합니다. 테스트는 실제 Postgres에서 통과하며 모의 또는 인메모리 대체가 없습니다.

다른 접근 방식을 시도하기 위해 깨끗한 상태를 원하면 분기를 삭제하고 프로덕션에서 새 분기를 만듭니다. 또 1초. 정리 티켓 없음. DBA 없음.

동일한 Jen. 동일한 리팩토링. 변경된 것은 기능입니다.

더 빨리 실패할 수 있는 공간

실험할 수 있는 능력은 중요합니다. 진화적 설계 및 개발은 미리 정의된 체크리스트를 빠르게 통과하는 것만이 아닙니다. 또한 작업이 구체화됨에 따라 학습하는 것이기도 합니다. Jen은 첫 번째 스키마 설계가 작동하지만 어색한 애플리케이션 로직을 생성한다는 것을 발견할 수 있습니다. 두 번째 설계가 더 깔끔하지만 기존 레코드의 마이그레이션이 더 복잡해진다는 것을 발견할 수 있습니다. 지금의 작은 정규화 결정이 향후 변경을 더 쉽게 만들 것이라는 것을 발견할 수 있습니다. 그녀가 작성한 첫 번째 마이그레이션 스크립트의 SUBSTRING 인덱스가 잘못되었습니다. 새 열에 올바르게 채워졌는지 확인하기 전에 파괴적인 DROP COLUMN이 실행되었습니다. 그녀는 자신만의 분기를 가지고 있기 때문에 이러한 발견은 비용이 적게 듭니다. 그녀는 마이그레이션을 적용하고, 애플리케이션을 실행하고, 데이터를 검사하고, 다른 마이그레이션으로 앞으로 나아가거나, 재설정하고 다른 경로를 시도할 수 있습니다.

이 분기는 또한 작업의 감정적 자세를 바꿉니다. Jen은 공유 개발 데이터베이스에 다른 사람이 의존할 수 있기 때문에 지나치게 신중할 필요가 없습니다. 그녀는 모든 실험을 팀에 알릴 필요가 없습니다. 다른 개발자가 테스트 데이터에 걸려 넘어질 수 있기 때문에 즉시 정리할 필요가 없습니다. 그녀의 분기는 미완성된 사고를 위한 안전한 장소입니다. 임시 테이블, 실패한 마이그레이션 시도, 어색한 테스트 데이터 및 반쯤 형성된 설계를 포함할 수 있으며 다른 사람에게 소음을 발생시키지 않습니다.

동시에 격리가 팀의 표준에서 분리됨을 의미하는 것은 아닙니다. Jen은 여전히 마이그레이션 스크립트를 작성합니다. 그녀는 여전히 애플리케이션 코드와 데이터베이스 변경을 함께 유지합니다. 그녀는 여전히 테스트를 실행합니다. 그녀는 여전히 최종 설계가 검토될 것으로 예상합니다. 차이점은 그녀가 팀이 완성된 버전에 대해 추론하도록 요청하기 전에 작업의 지저분한 부분을 사적으로 그리고 빠르게 수행할 수 있다는 것입니다. PR을 열 때쯤이면 대화는 그녀가 테스트할 안전한 장소가 있었는지 여부가 아니라 설계가 올바른지 여부에 초점을 맞출 수 있습니다.

이것이 핵심 전환입니다. 데이터베이스 분기는 Jen에게 빠르고 현실적이며 격리된 피드백을 제공하며, 이는 그녀의 데이터베이스 분기를 보여줌으로써 기술 리드 또는 DBA로부터 검토받을 수도 있습니다. 빠르다는 것은 그녀가 필요할 때 환경을 프로비저닝해 주는 사람이 아닌, 필요할 때 환경을 생성할 수 있다는 것을 의미합니다. 현실적이라는 것은 프로덕션에서 중요한 것과 동일한 종류의 데이터베이스 동작을 상대로 테스트하고 있다는 것을 의미합니다. 격리되어 있다는 것은 그녀의 실험이 다른 누구에게도 방해를 주지 않는다는 것을 의미합니다. 이 세 가지 속성이 결합되어 데이터베이스 변경을 병목 현상에서 기능 개발의 정상적인 부분으로 전환합니다.

이제 Jen은 애플리케이션과 데이터베이스를 함께 진행할 수 있습니다. 그녀의 코드 분기와 데이터베이스 분기는 동일한 작업의 두 측면이 됩니다. 하나는 애플리케이션 변경을 보유합니다. 다른 하나는 해당 변경 사항이 작동할 실제 데이터베이스를 제공합니다. 기다리거나, 조정하거나, 단순화된 설정으로 시늉하는 대신, Jen은 설계하고, 테스트하고, 수정하고, 배울 수 있습니다. 기능은 여전히 작지만 이제 데이터베이스는 더 이상 그것을 느리게 만드는 요인이 아닙니다.

풀 리퀘스트 열기

Jen은 애플리케이션 코드와 마이그레이션 스크립트를 모두 커밋합니다. PR을 엽니다.

CI는 Jen이 방금 한 일을 팀을 위해 수행합니다. 자체 임시 Lakebase 분기를 생성하고, 마이그레이션을 적용하고, 애플리케이션 테스트 스위트를 실행하고, 마이그레이션된 스키마를 상대로 데이터베이스 테스트를 실행하고, 마이그레이션 자체를 검증하고(깔끔하게 적용됨, 멱등성, 복구 가능), PR에 데이터베이스 개체가 변경된 내용을 정확히 보여주는 schema-diff 댓글을 게시합니다.

검토자는 이제 코드와 함께 사용되는 스키마 변경이 무엇인지 볼 수 있으며, 컨텍스트 이해를 추상적인 것에서 구체적인 것으로 바꿉니다.

Lakebase SCM Extension의 분기 차이 요약 보기 스크린샷

변경 사항 검토

이전 워크플로에서는 데이터베이스 검토 질문이 "이것이 데이터베이스를 망가뜨릴까?"였습니다. 모든 변경 사항이 통제 불능 상태가 될 경우 프로덕션 규모의 결과를 초래할 수 있었기 때문에 모든 변경 사항을 개별적으로 검토해야 하는 DBA가 이를 통제했습니다. 검토는 동기식으로 진행되었습니다. 일정이 충돌했습니다. DBA의 캘린더는 대기열이 되었고, 때로는 "시장 출시 시간"상의 이유로 DBA가 건너뛰어지기도 했습니다.

새로운 워크플로에서는 질문이 "이것이 올바른 설계인가?"입니다. DBA는 이미 CI에서 게시한 스키마 차이를 확인했습니다. 이미 실제 데이터 브랜치에서 마이그레이션이 성공적으로 실행되는 것을 보았습니다. Jen은 또한 DBA를 논의에 참여시켜 자신이 무엇을 생각하고 있는지, 그리고 시도했던 다른 모든 옵션을 보여줄 수 있습니다. DBA는 Jen의 일정에 맞추는 것이 아니라 자신의 일정에 따라 검토할 수 있습니다. 그들은 솔루션 개발 주기 초기에 검토를 제공하고, 모든 시간을 소모했던 보호 게이트키핑이 아니라 데이터 무결성, 인덱싱 전략, 향후 확장성 또는 장기 유지 관리 측면에서 솔루션을 개선할 수 있습니다.

팀은 코드와 데이터베이스를 함께 검토합니다. 하나의 PR. 하나의 대화. 같은 창에서.

자신감을 가지고 병합하기

마이그레이션은 이미 실제 데이터 브랜치에서 테스트되었습니다. 애플리케이션은 이미 변경된 스키마를 대상으로 실행되었습니다. 스키마 마이그레이션이 검토되었습니다. CI 빌드는 동일한 단계를 실행했으며 한 시간 동안 녹색 상태였습니다.

Jen이 병합하면 마이그레이션이 다음 환경에 적용되고, CI 환경 및 Jen의 데이터베이스와 코드 브랜치가 정리됩니다. 따라서 데이터베이스 변경이 더 이상 릴리스 밤의 놀라움이 되지 않도록 보장합니다.

Jen이 방금 한 일은 2003년 에세이 "데이터베이스 변경의 지속적인 통합"의 다섯 번째 관행입니다.

Jen의 여정이 보여주는 것

데이터베이스 변경은 일반 개발의 일부가 됩니다. 브랜칭은 대기, 위험 및 조정 오버헤드를 줄입니다. Jen의 일일 루프는 이제 데이터베이스 계층에서 빠르고 격리된 피드백을 제공합니다.

파트 2 – Jen의 새로운 플레이북에서는 무엇이 향상되었는지, 그리고 Jen이 경력 내내 작업했던 보상 계층이 왜 제거될 수 있는지 설명합니다. 복사 후 쓰기 브랜칭, 이를 가능하게 하는 아키텍처, 그리고 그에 따른 방법론 최적화에 대해 설명합니다.

파트 3 – Jen의 팀 규모에서는 Jen이 50명의 개발자 중 한 명일 때, 또는 화이트 라벨 제품을 작업할 때, 또는 내부에 많은 도메인이 있는 모듈식 모놀리스에서 작업할 때 Jen의 이야기가 어떻게 보이는지 살펴봅니다. 브랜치 생성 시 거버넌스, DBA 재구성, 에이전트 인 루프, 그리고 DBA의 캘린더가 티켓 대기열이 아닐 때 열리는 플랫폼 설계 작업에 대해 살펴봅니다.

이 게시물에서 Jen이 사용한 IDE 도구에 대한 투어를 원하는 독자를 위해, Lakebase SCM Extension for VS Code / Cursor의 동반자: 플러그인 워크스루가 처음부터 끝까지 제공됩니다.

마지막으로, 에이전트가 사용할 수 있는 Lakebase App Dev Kit와 함께 사람이 따를 수 있는 전자책이 곧 출시될 예정입니다.

(이 글은 AI의 도움을 받아 번역되었습니다. 원문이 궁금하시다면 여기를 클릭해 주세요)

최신 게시물을 이메일로 받아보세요

블로그를 구독하고 최신 게시물을 이메일로 받아보세요.