【データ基盤構築/dbt】modelディレクトリの構成のベストプラクティス

# 今回の課題
dbtの**modelディレクトリの構成のベストプラクティス**について理解しようと思った。
公式ドキュメントを読みながら、自分なりに理解してまとめてみた。

※参考：[How we structure our dbt projects](https://docs.getdbt.com/guides/best-practices/how-we-structure/1-guide-overview)

# dbtプロジェクトの構成のベストプラクティス
下記のような構成が、推奨されていた。
`models`ディレクトリ内に、`intermediate`, `marts`, `staging`フォルダを作成して管理しているかたちだ。
```
jaffle_shop
├── README.md
├── analysis
├── data
│   └── employees.csv
├── dbt_project.yml
├── macros
│   └── cents_to_dollars.sql
├── models
│   ├── intermediate
│   │   └── finance
│   │       ├── _int_finance__models.yml
│   │       └── int_payments_pivoted_to_orders.sql
│   ├── marts
│   │   ├── finance
│   │   │   ├── _finance__models.yml
│   │   │   ├── orders.sql
│   │   │   └── payments.sql
│   │   └── marketing
│   │       ├── _marketing__models.yml
│   │       └── customers.sql
│   ├── staging
│   │   ├── jaffle_shop
│   │   │   ├── _jaffle_shop__docs.md
│   │   │   ├── _jaffle_shop__models.yml
│   │   │   ├── _jaffle_shop__sources.yml
│   │   │   ├── base
│   │   │   │   ├── base_jaffle_shop__customers.sql
│   │   │   │   └── base_jaffle_shop__deleted_customers.sql
│   │   │   ├── stg_jaffle_shop__customers.sql
│   │   │   └── stg_jaffle_shop__orders.sql
│   │   └── stripe
│   │       ├── _stripe__models.yml
│   │       ├── _stripe__sources.yml
│   │       └── stg_stripe__payments.sql
│   └── utilities
│       └── all_dates.sql
├── packages.yml
├── snapshots
└── tests
    └── assert_positive_value_for_total_amount.sql
```
## Stagingディレクトリについて
stagingディレクトリにはソースデータから、
一次集計を行うためのコードが書かれたmodelを格納する。


### 1)サブディレクトリの分け方
#### ⭕推奨
データを抽出してくるシステムに応じて、サブディレクトリを作成する。
上記のドキュメントから引用したディレクトリ構成では、
`juffle_shop`、`Stripe`という、２つの異なるシステム毎にディレクトリを分けている。

#### ❌非推奨
* データのロード方法（Fivetran、Stitchなど）で、サブディレクトリを分ける。
* 「マーケティング」「ファイナンス」などビジネス上のジャンルで、サブディレクトリを分ける。


### 2)Stagingディレクトリのmodelの命名規則について
#### ⭕推奨
`stg_[source]__[entity]s.sql`といったように、ソースシステムとエンティティの間に、ダブルアンダースコアを使用すると、ソースデータが複数の要素を持つ場合に、視覚的に区別しやすい。
また、entityは複数系で命名するようにした方が良い。

(例)`stg_googleanalytics__users.sql`, `stg_googleanalytics__works`のようなイメージ

#### ❌非推奨
`stg_[entity].sql`といった命名は、ファイルの数が少ないうちは良いが増えていくと区別しづらくなる。

### 3)Stagingディレクトリのmodelで行う主な処理
* リネーム
* 型変換
* 基本的な計算（セントからドルに単位を変換する。など）
* カテゴライズ（case文で、値をグループ分けする。など）


### 4)Stagingディレクトリのmodelはビューとして実体化する
下記の理由から、staging modelはviewとして保持した方が良い。
* staging modelを参照する下流のモデルが常に最新のデータを取得できる
* ウェアハウス内のストレージの浪費を避けることができる（高速化したい場合は、table化を検討した方がいいかも）


## intermediateディレクトリについて
Staging modelで作成したテーブルを、グループ化して異なる粒度で集計するなどする。
intermediateモデルの目的は、martsモデルの複雑さを解消すること。

### 1)サブディレクトリの分け方
#### ⭕推奨
ビジネス上の関心領域ごとにサブディレクトリを分ける。
(例)financeディレクトリなど

### 2)intermediateディレクトリのmodelの命名規則について
#### ⭕推奨
`int_[entity]s_[動詞]s.sql`といったように命名する。
内部で様々な処理をするので、名前の付け方を厳密に決めるのが難しいが、
最良なのは、実施する処理の動詞（例えば`aggregated_to_user`, `joined`など）を考慮して付けるのが良い。

### 3)intermediateディレクトリのモデルはEphemeralとして実体化する
ダッシュボードやアプリケーションなどへの出力をしないため、
intermediate modelのデータは本番環境で公開しない。
データガバナンスと検出可能性を簡単に制御できるように、モデルから分離しておく。
それらの理由から、Ephemeralとして実体化する。


## martsディレクトリについて
データマートを生成するためのmodelを作成する。

### 1)サブディレクトリの分け方
マートの数が少ない場合サブフォルダが不要の可能性があるため、
早急に最適化する必要は無い。
マートが増えてきたら、部門別（`finance`, `marketing`）などでグループ化する。

### 2)martsディレクトリのmodelの命名規則について
customersやordersなど、マートのコンセプトに基づいて分かりやすい名前を付ける。
※`order_per_day`のように、時間軸は設定しないようにする。

### 3)martsディレクトリのmodelはtableまたはincrementalとして実体化する
マートを作成するまではテーブル自体の生成はしなかったが、
ここからは実体のあるテーブルを生成する。

実体のあるテーブルをダッシュボードなどに繋げておくことによって、
誰かがダッシュボードにアクセスや更新をする度に、再計算の処理をせずに済む。

# まとめ
テーブルの一次処理、統合、データマート作成など、
段階に応じて、命名規則、ディレクトリの分け方、実体化の方法など推奨されていることが異なるということが分かった。