dbt

dbt ガバナンスの全体像: contracts / groups / versions の位置づけ

2026-04-19
NicheeLab編集部

dbt はソフトウェア工学の原則をデータ変換に適用できるのが強みです。特に、契約(schema を固定)、所有と境界(groups + access)、互換性の進化(versions)は、ガバナンスの要になります。

本稿では、各機能の役割と相互作用、よくある設計パターン、移行時の注意点を、公式ドキュメントに基づく安定概念に絞って解説します。

なぜ dbt ガバナンスか:境界と責務を明確にする

データ製品を継続的に改良しつつ、下流の安定性を損なわないためには、インターフェースの固定、チーム境界の明確化、破壊的変更の管理が必要です。dbt では、contracts(モデルの入出力スキーマを固定)、groups + access(所有と参照の境界を宣言)、versions(互換性を意識した進化)でこれを表現します。

これらはビルドの成否や参照可否に直接影響し、リグレッションを未然に防ぎます。試験観点では、用語の正確な使い分けと、いつどの設定を使うべきかの判断が狙われます。

  • contracts は「型と列」を固定し、逸脱すればビルドが失敗する
  • groups は「誰の資産か」を宣言し、access で外部からの参照可否を制御する
  • versions は「破壊的変更」を別バージョンとして並行提供できるようにする
機能主目的宣言場所(代表例)破壊的変更の扱い
contractsモデル出力のスキーマ固定model の config(schema.yml で columns と型)互換性を壊す変更は基本 NG。必要なら新 version を作る
groups + access所有境界と参照ポリシーの宣言groups リソース定義 + 各 model の group/accessprivate なら外部参照不可。public は参照可。protected は限定公開
versions互換性の進化と並行稼働model の versions 定義 + latest_version破壊的変更は新しい v を追加し段階的移行

最小構成の全体像(骨子)

# プロジェクトの骨子(抜粋)
# models/schema.yml などに集約する設計が読みやすい
models:
  - name: customers
    group: mart
    access: public
    config:
      contract:
        enforced: true
    columns:
      - name: customer_id
        data_type: string
      - name: country
        data_type: string
    versions:
      - v: 1
        defined_in: models/marts/customers_v1.sql
      - v: 2
        defined_in: models/marts/customers_v2.sql
    latest_version: 2

groups:
  - name: mart
    owner:
      name: Analytics Mart
      email: [email protected]

contracts の基本:型と列を“約束”にする

contracts はモデル出力の列名とデータ型を固定する仕組みです。config の contract.enforced を true にし、columns に name と data_type を宣言します。定義に合わない SELECT を書くと、ビルド時にエラーになります(アダプタにより動作は異なりますが、逸脱は少なくとも dbt 実行時に検出されます)。

実務では、信頼できる下流インターフェースを作るファサード層(例えば mart 層)に適用します。破壊的変更(列削除・型変更)が必要な場合は versions を併用して新バージョンを提供するのが安全です。

  • columns には全ての公開列を列挙し、data_type を必ず指定する
  • ビューでもテーブルでも利用可能(アダプタにより強制方法は異なる)
  • 破壊的変更は versions で吸収し、旧版の撤去は段階的に

contracts の最小例(schema.yml)

models:
  - name: orders
    group: mart
    access: public
    config:
      materialized: table
      contract:
        enforced: true
    columns:
      - name: order_id
        data_type: string
      - name: order_date
        data_type: date
      - name: amount
        data_type: numeric

# models/marts/orders.sql
-- SELECT の列と型が上記と一致しないとエラー
select
  cast(order_id as string) as order_id,
  cast(order_date as date)  as order_date,
  cast(amount as numeric)   as amount
from {{ ref('stg_orders') }}

groups と access:所有の宣言と参照ポリシー

groups はリソースの所有グループを宣言する仕組みで、owner 情報と合わせて定義します。各モデルに group を設定し、access で公開レベル(private / protected / public)を指定します。これにより、異なるグループからの参照可否がコンパイル段階でチェックされます。

実装はシンプルでも効果は大きく、プロジェクトを跨ぐ“無秩序な参照”を抑止できます。公開が必要なモデルは public、内部専用は private を基本方針にし、protected は段階的公開や合意の上での限定利用に用いるのが無難です。

  • groups 定義に owner を紐付け、意思決定者を明示する
  • access=private のモデルは同一 group 外から参照できない
  • 公開は最小限。public にする対象は contracts とドキュメントを整備する

groups と access の定義例

# groups.yml
groups:
  - name: staging
    owner:
      name: Data Platform
      email: [email protected]
  - name: finance
    owner:
      name: Finance Analytics
      email: [email protected]

# models/finance/schema.yml
models:
  - name: fct_revenue
    group: finance
    access: private    # finance 外からの ref を禁止
    config:
      contract:
        enforced: true
    columns:
      - name: revenue
        data_type: numeric

# 参照側での選択(CI 等)
# finance グループだけをビルド
# dbt build --select group:finance

versions の基本:互換性を壊す変更のための並行稼働

versions はモデルをバージョン単位で並行提供するための仕組みです。versions に v を列挙し、各バージョンの SQL を defined_in で紐付け、latest_version を指定します。ref('model') は既定で latest に解決され、ref('model', version=1) のように固定もできます。

列の削除や型変更といった破壊的変更は新しい v を追加します。旧版は一定期間残し、下流の移行完了後に廃止します。contracts と組み合わせると、各バージョンのインターフェースを明確に保てます。

  • latest_version を明示し、デフォルト参照の向き先を統一する
  • ref でバージョン固定が必要な下流は明示的に pin する
  • 削除・型変更は新 v、非破壊(列追加など)は同 v で可(要ドキュメント)

versioned model の定義と参照例

# models/mart/schema.yml
models:
  - name: customers
    group: mart
    access: public
    config:
      contract:
        enforced: true
    versions:
      - v: 1
        defined_in: models/marts/customers_v1.sql
      - v: 2
        defined_in: models/marts/customers_v2.sql
    latest_version: 2
    columns:
      - name: customer_id
        data_type: string

# 参照側
-- latest を利用
select * from {{ ref('customers') }}

-- v1 を明示的に利用
select * from {{ ref('customers', version=1) }}

連携パターン:contracts × groups × versions の設計

運用では、公開インターフェース(public)のみ contract.enforced と versioning を徹底し、private な内部モデルは簡素に保つのが現実的です。グループ境界での参照は、原則として public モデルに限定します。

移行は「新 v の追加 → 下流の段階的移行(必要なら一時的に v1/v2 のブリッジを提供) → latest 切替 → 旧 v 廃止」の順で進めます。CI では group 単位と公開モデル単位のテストを分離すると、失敗範囲が特定しやすくなります。

  • 公開面は contract と tests(not_null, unique など)を併用して堅牢化
  • 移行期間は v を並行提供し、ドキュメントで使用可否を明確化
  • selectors を併用し、group: と access:public を使い分けて検証を最適化

設計の流れ(公開モデルの進化)

stg_* (private)int_* (private)内部集約customers v1mart.public model (contract)customers v2mart.public model (contract)ref(...,v=1) / ref(...)/ref(v=2)下流アプリ

移行期の CI セレクタ例

# 旧版と新版を並行検証(公開モデルのみ)
# 新版を優先して build し、旧版は smoke テストに限定
# 最新版のグループ単位で失敗を早期検知

dbt build --select access:public +state:modified --exclude group:archive

dbt test --select model:customers,version:1 --store-failures

試験対策と実務チェックリスト

試験では、用語の対応付け(contract はスキーマ固定、group/access は参照境界、version は破壊的変更の吸収)と、どの状況でどれを使うかの判断が頻出です。具体的な YAML の書き方、ref の解決規則、エラーが出るタイミングを押さえてください。

実務では、公開面だけ厳格化する“選択と集中”が有効です。まずは public モデルの contracts と versions を整備し、groups と access で境界を固定します。移行ルールと連絡経路(owner)を明文化すれば、変更の社会コストが下がります。

  • public モデルは contract.enforced とドキュメント必須
  • 破壊的変更は新 v の追加。latest の切替はアナウンス後に実施
  • group と owner は全モデルで埋める。private は原則グループ内完結

セルフチェック用コマンド断片

# 公開モデルの契約とテストの健全性
/dbt build --select access:public

# 変更影響の把握(state 比較)
dbt ls --select state:modified+ --defer --state target/production

# グループ所有者の棚卸し(docs 生成と合わせて)
dbt docs generate && dbt docs serve

問題で確認

Analytics Engineer

問題 1

mart グループが提供する public モデル customers に対し、下流(別グループ)が参照している列 country を削除したい。最も適切な対応はどれか?

  1. A. customers の新しいバージョンを追加し(v2)、country を含まない契約を定義。latest_version を v2 に設定し、一定期間 v1 と並行提供する
  2. B. customers の contract.enforced を一時的に外し、country を削除してから再度有効化する
  3. C. 同一バージョンのまま country を削除し、下流には ref('customers') を使い続けてもらう
  4. D. groups を private に変更してから列を削除し、数日後に public に戻す

正解: A

列削除は破壊的変更の典型。versioned model で新 v を作り、contracts を更新、latest 切替と並行提供期間を設けて段階的に移行するのが安全で、dbt の推奨設計に沿います。

よくある質問

contracts はどのアダプタでも同じように強制されますか?

列名・型の不一致は少なくとも dbt 実行時に検出されますが、データベース制約の作成や動作はアダプタ依存です。Snowflake や BigQuery など主要アダプタで安定的に利用されています。実環境で一度ビルドし、期待どおりに失敗することを確認すると安心です。

groups と Git のチームや権限は連動しますか?

groups は dbt プロジェクト内のメタデータで、Git の権限とは直接連動しません。owner 情報(名前・メール等)を groups に記述し、変更フローやレビュー体制はリポジトリ側の運用(CODEOWNERS など)で補完します。

versions はすべてのモデルで必須ですか?

必須ではありません。グループ外から参照される public モデルや、長寿命の下流依存があるモデルでの適用が効果的です。private な内部モデルは、コストとのバランスを見て必要時のみ導入します。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
dbt

dbt Model の基礎: SQL で定義する変換の最小単位

Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...

dbt

dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点

dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...

dbt

dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点

dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...

dbt

dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト

Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....

dbt

dbt_project.yml の読み方:主要設定と命名を最短で掴む

dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...

dbtの記事一覧 (100件)
© 2026 NicheeLab All rights reserved.