
はじめに
株式会社PLEXでコーポレートエンジニアをしている石川です!
社内で使われている業務用システムの開発など、社内業務の改善に取り組んでいます。
この記事では、初めてdbtの開発を任された私が、どのようにアプローチしたか・つまずいたか・改善したかについて共有します。
対象読者
以下の項目に関心・該当する方におすすめの記事です!
- 自社でdbtを導入予定で、dbt開発を任されたが何をすべきかわからない方
背景
社内業務の一貫として、社内のさまざまなデータソースに存在する企業情報を元に、BigQueryに企業テーブルを作成する必要性が生じました。
BIツール越しにSQLを書くことも考えましたが、下記の要件を満たすためにdbtを導入することになりました。
課題
- SQLは何となく書けるが、dbtは完全初見の私が1人で開発をする
実践、アプローチと改善について
1. ローカルでいじってみよう
dbtをまずはローカル環境で動かしてみることで、“触って学ぶ”アプローチが有効だった話です。
手を動かしながら概念を理解していくことが、自分にとって最も定着につながると実感しました。
良かったポイント
dbtで始めるデータパイプライン構築〜入門から実践〜を一番最初に読み、試したことです。
dbtとは? から始まり、dbtの概要をざっと理解できます。
ざっくりdbtについて記載すると、ELTのアプローチにおける「T」層の部分を担います。すなわち、データの変換が責務です。
当時の私もたまたまこの記事と巡り会い、ローカルで手を動かしたのはとても良い選択でした。
公式ドキュメントをもとに作成されたこの記事は、「dbtとは何か?」の手助けとなり初手やるべきこととしてベストだと思います。
今思うと改善できたポイント
dbtで始めるデータパイプライン構築〜入門から実践〜を一度試して、後半の紹介をさらっと目を通して終わらせてしまったことです。
後半部分のdbt向けPythonライブラリのご紹介にライブラリの紹介などが記載されています。
ブログ後半にも記載していますが、言わずもがなdbtでもライブラリ利用が開発効率性を大幅にあげます。
なのでdbtとは何か?のイメージを掴むだけで終わらせるのではなく、「〇〇できるライブラリあるんだー」と雰囲気を知るためにも、一度は目を通すべきでした。
2. dbtベストプラクティスに目を通そう
「公式が言っている正解」を先に知ることで、設計や命名での迷いがぐっと減ります。
やみくもに試すのではなく、ベストプラクティスを押さえた上で判断できるようになったのは大きな収穫でした。
良かったポイント
ローカルで手を動かした後、dbt公式のベストプラクティスガイドを読んだことです。
先ほどの記事を見たからと言って、dbtを全て理解できるわけではありません。
「staging・marts層のSQLファイル名は何がよくて、何が悪いのか?」であったり、「baseフォルダはいつ作るべきなのか?」など深掘り知識を付けるには、公式ドキュメントを読み込むしかないです。
特にフォルダ構成のあるべき姿を、最初のうちに見てイメージをさらに固められたのが良かったです。
また、staging層やmarts層に求められている責務や、joinはどの層でやるべきなども書いてあるため、初見のdbt開発でもレールに従って開発ができます。
今思うと改善できたポイント
dbtのフォルダ構成・命名規則に問題はないが(運用上支障は出てない)、ymlファイル周りのコードが膨れ上がった際にどういうアプローチを取れば良いか、事前に公式ドキュメントを読み込んでイメージを作っておくべきでした。
弊社のstaging層の一部抜粋ですが、_{source}__{entity}s.sqlの公式ルールに従って設計いたしました。
bqやgcsでフォルダ分けしてますが、ファイル名にそもそもソース元を記載してるので、なくても良いのかなと運用してから気づきました。
models/staging
├── bq
│ ├── _bq__models.yml
│ ├── _bq__sources.yml
│ ├── stg_bq__dm_logs.sql
│ └── stg_bq__zip_codes.sql
│
│
└── gcs
├── _gcs__models.yml
├── _gcs__sources.yml
├── stg_gcs__companies.sql
└── stg_gcs__geographical_coordinates.sql
一部抜粋なので、sqlファイルが少ないですが、本来は数倍以上あります。 実装当初の名残で各ymlファイルに全てメタ情報を詰め込んでいるため、800行近くあります。
とはいえ社内でのdbt知識に差があるため、1つの箇所に情報がある方がたどりやすいかと思い、当初の設計のままになっています。
いつかリファクタリングを行いたいと思ってます。
3. dbt Packagesの存在を知ろう
便利なライブラリを知らなかったせいで、手作業・重複コードが増えてしまった話です。
スター数が少ないからといって信用しないのはもったいないです。
良かったポイント
反省点多数。最低限dbt-utilsを導入していたのは良かったです。
今思うと改善できたポイント
当時の私は、dbt関連のライブラリのスター数が基本低いため(1000以下が多かった)、あまり利用しない方が良いのかと考えてました。
ですが、dbtの開発を進めていく中で、色々なブログでよく聞くpackage(dbt-external-tablesやdbt-osmosis)も、スター数が少ないものが多く、無駄な重複するコードをたくさん量産してしまったのが失敗点です。
なので、一から始める場合は、下記のライブラリには最低限目を通して、導入するか検討すべきだったと思います。
dbtモデル開発時の便利関数やテストが豊富
dbt-utilsexpect_column_to_exist など、データ品質チェックに特化した豊富なGenericテストが多数
dbt-expectationsモデル定義(ymlなど)を自動生成・保守できるツール。手動管理の負担を大幅に軽減
dbt-osmosisdbt Labsのベストプラクティスに基づいて、命名や構成をチェックし、ソースコードの品質を担保
dbt-project-evaluatordbtプロジェクトのデータの可視化・アラート・監視などを可能に
elementary-data/elementaryGCS・S2など外部データをテーブルとして定義可能
dbt-external-tables
4. メタデータを管理しよう
メタ情報の整備は地味だけど重要です。手動管理は非効率なので自動化できるとすごく楽になります。
ymlファイルの記述を毎回手でやっていた当初の自分に「自動生成できるぞ」と教えてあげたいです。
良かったポイント
手間ではあるが、sources,modelsのymlを毎回定義していたのはよかったです。
今思うと改善できたポイント
手間な作業をもっと効率的にできないか? の視点が抜けていたことです。
dbt開発当初、コピペの連続でymlファイルを定義してました。
ですがdbt-osmosisという、とても便利なライブラリがあります。(プロジェクト後半で存在を知りました。)
dbt-osmosisについての説明は記事が多く存在するため割愛します。
いくらdbtの設計が綺麗でも使われるテーブルを生成しなければビジネスに何も影響がありません。
利用者を増やすためにもメタデータの豊富さは必要不可欠です。
特にdbt LabsがSDF Labs を買収したことにより、dbt-osmosisの必要性は今以上に上がると考えます。
カラムリネームはもう怖くない!dbt‑osmosisを超えるSDFの挑戦
の記事が大変参考になります。
5. awesomeを見よう
他のdbtプロジェクトを見ると、自分たちの設計や実装に活かせるヒントが山ほどあります。
特にmacroの実装例やフォルダ構成は、ベストプラクティスと合わせて学ぶと設計の視野が広がります。
良かったポイント
dbt公式でjaffle-shopのディレクトリ構成以外にも、他のdbtプロジェクトの事例がないか検索しawesome-public-dbt-projectsとawesome-dbtに辿り着き、どのような実装を行っているのかを知れたのは良かったです。
dbt公式のベストプラクティスに基づいてないような場合もありますが、フォルダやファイル名の切り方など色々な角度から学習できます。
macro層や実装方法では、mattermost-data-warehouseの書き方を参考にしたりしました。
Jinja自体初見だったため、dbtの文法なのかJinjaの文法なのかわからず何も分からなかったので、helpers.sqlのSQLコードを見たりして、書き方の一例としてインプットしてました。
今思うと改善できたポイント
特段ないです。良い視点で情報収集できたかと思います。
6. テストを書こう
dbtにも“制約に近い”テストが存在し、使うことでデータ品質を担保できます。
SingularテストとGenericテストの違いを理解しておくと、最小工数で最大の保守性を得られます。
良かったポイント
改善点多数あり。テストの認識を間違えていました。
今思うと改善できたポイント
Singularテストのような、一種のDB制約のようなものが機能として存在していたことを見落としていました。
dbtのtestには大きく分けて、SingularテストとGenericテストがあります。
Singularテストはtestsディレクトリ配下に定義する下記のようなものです。
一例ですが、法人番号(corporate_number)がnullのレコードが存在してると落ちるテストです。
## tests/test_companies_corporate_number_not_null.sql
select
id,
corporate_number
from {{ ref('companies')}
where
corporate_number is null
私がdbt開発を行ってる際、知識不足で「テスト = 上記のようなSQLを毎回書くもの」と勘違いしており、dbt自体開発が完成して、運用した後に書く判断をしてしまいました。
これは大きな反省点です。
本来ならば、作成したテーブルで確実にnullを許容しないカラムには絶対テストを書くべきでした。
ここでGenericテストが登場です。
- unique
- not_null
- accepted_values
- relationships
の4つがあり、「ymlの定義だけで」テストを実装できます。
先ほどのSingularテストを書き換えると下記のようになります。
version: 2
models:
- name: companies
columns:
- name: corporate_number
tests:
- not_null
- unique // 一意であることも確認したいなら
当時の実装では、テストを一切書いていなかったため、nullを許容すべきではない箇所にnullが入ったりと、開発以上に調査時間が増えてしまいました。
なので、最低限Genericテストは書きましょう。時間がなくても。
参考: dbt公式-テストについて
最後に
弊社では各事業部でエンジニアを募集しております! 気になるポジションあればお気軽にお問い合わせください。一緒に働きましょう。
弊社の各事業部でエンジニアを求めています!
SaaS
100兆円規模のインフラ産業の課題解決に挑戦|業務支援SaaSのテックリード - 株式会社プレックス
急成長する業務支援SaaSのソフトウェアエンジニア・リードエンジニア - 株式会社プレックス
PLEX JOB
インフラ産業の人材課題を解決 | フロントエンドの技術を牽引するテックリード - 株式会社プレックス
インフラ領域で日本を動かす仕組みを作るスタートアップのエンジニア - 株式会社プレックス


































