分析基盤の開発・運用でデータマネジメント観点で取り組んできたこと in 2022

こんにちは。某FinTech企業でAnalytics Engineerとして働いている[@yuu_kimy](https://twitter.com/yuu_kimy)です。  
この記事は、[datatech-jp Advent Calendar](https://qiita.com/advent-calendar/2022/datatech-jp) 2022の18日目の記事です。

今年の振り返りも兼ねて、チームとしてデータマネジメント観点で取り組んできたことを紹介したいと思います。

## 所属チームの状況
- 分析基盤を作ってから、数年経過していること
    - 各テーブルの保管、集計・分析には、BigQueryを利用している状況 
- 当時の状況から変化してきており、課題が顕在してきたこと

## 取り組んできたこと
1. 不要なデータセットの削除
1. 不要なテーブルの削除
1. SQLクエリのリファクタリング
1. 似たようなテーブルの更新停止
1. Terraform Cloudの利用開始/運用対象のワークスペースの明確化
1. 新たな開発ツールの導入
1. ISSUE Buster Dayの採用

一つ一つの取組みの背景と対応を簡単に紹介していきます。

### 1. 不要なデータセットの削除
#### [背景]
ジョイン当初に気づいたことの一つとして、全くテーブルが保持されていない`データセット`が幾つかあるということでした。
当初は需要があったのだと思いますが、時間の経過に伴い、不要になってくることは多々ありますよね。

#### [対応]
現状と今後の想定利用を所属チームに確認し、不要と判断できたデータセットは削除しました。
ちなみに余談ですが、弊社では、GCPのリソース管理に`Terraform`を利用しています。
(実は、当初は、所属チーム内ではキチンとTerraformを使いきれてなかったのですが、この話は後述します。)

### 2. 不要なテーブルの削除
#### [背景]
これも、上記と同様の背景です。
作成当時は、需要があっても、ニーズが変わり、使われなくなることは多々あるかと思います。

#### [対応]
対応自体は、データセットと同様です。このケースでは、それを「いつ」実施するのかについて触れておきたいと思います。
分析基盤の改善[^1]もあり、マートテーブルで参照するソーステーブルの切替対応が必要でした。
その時に、影響範囲の洗い出しに加えて、利用状況も合わせて調査するようにしました。
利用状況の調査の流れは、以下の流れで行っています。
- `INFORMATION_SCHEMA.JOBS`で、直近3ヶ月程度の対象テーブルのアクセス数を集計
- アクセス数を踏まえて、所属チームや他部署へ利用状況を確認
- Looker側の参照や他のテーブルからの参照がないかを確認
- 問題なければ、アーカイブ用のデータセットへ移動(アーカイブテーブルは30日間のみ保持するように設定)

### 3. SQLクエリのリファクタリング
#### [背景]
可読性があまり高くはないデータマートのSQLが幾つか存在しており、今後のメンテナンス性に懸念がありました。

#### [対応]
例えば、以下のようなSQLがあった時、可読性を高めるように以下のようなリファクタリングしました。

```sql
# before
select
  t_1.*
  t_2.*
from
  target_table_1 t_1
left join
  target_table_2 t_2
  on
    t1.common_key = t_2.common_key
```

```sql
# after
select
  t_1.col_a,
  t_1.col_b,
  t_2.col_c,
  t_2.col_d,
from
  target_table_1 as t_1
left join
  target_table_2 as t_2
  on
    t1.common_key = t_2.common_key
```

このあたりの取組みは、弊社のデータ系チームのNoteで詳しく紹介できると思いますので、お楽しみに〜♪
もちろん、上記のようなリファクタリングは、闇雲に実施しているわけではなく、前述のアクセス数を踏まえて、利用率が高いもの&今後メンテナンスが必要となるものを優先的に実施しています。

### 4. 似たようなテーブルの更新停止
#### [背景]
分析基盤の運用を続けている中で、ほぼ似たようなマートテーブルを見つけました。
過去経緯までは特定できなかったのですが、何らかのきっかけで、一方のテーブルをほぼそのままコピーして、別のテーブルとして作成し、そのまま2つのテーブルとして並存してきたようでした。

#### [対応]
利用頻度が高い&今後もメンテナンスが発生するテーブルでしたので、2つのうち、一方を更新停止するようにしました。
(テーブルに含まれるカラムはほぼ同じであり、そのうちの1つのテーブルで、利用ユーザの要件を満たしていたため)

対応自体は、更新を停止するだけなのでシンプルなのですが、利用ユーザとのコミュニケーションに配慮しました。
以下の点は、特に重要な点だと感じています。
- なぜ更新廃止するのか？
- いつ更新停止するのか？
- 利用ユーザはどこで対象のテーブルを利用しているのか？

もう少し詳細を書いてみたいと思います。

##### なぜ更新廃止するのか？
そもそも、なぜ更新を止めるのかの背景はキチンと説明するようにしました。
現状のままでは、利用ユーザ側にとってはアクセシビリティが現状良くないこと、運用側にとってはメンテナンスコストが大きくなり、
後々の足かせになること(それにより、分析基盤の開発・運用で本来することが後回しになってしまうこと)を説明しました。

##### いつ更新停止するのか？
利用ユーザが納得しても、即座の更新停止はやはり困るだろうと想定していました。
今回は、移行期間を約1ヶ月設け、更新停止予定のテーブルを利用している方に、
別のテーブルへ移行頂くように促すようにしました。
移行期間中にも、何度かリマインドのアナウンスを行い、移行対応を促してきました。

##### 利用ユーザはどこで対象のテーブルを利用しているのか？
弊社の場合、利用ユーザは、スプレッドシートから`データコネクター`を利用して、データを集計したりするユースケースが圧倒的に多い状況でした。
利用ユーザがどのスプレッドシートで利用しているかをBigQueryの`Audit Log`を利用して、利用ユーザごとに、どのスプレッドシートを利用しているのかも移行時の参考情報としてお伝えしました。
(BigQueryのAudit LogをBQへ連携していため、すぐに確かめることができました。ログを利用しやすくしておくのは大事ですね)

```sql
# 下記のクエリの`doc_id`がスプレッドシートを識別するIDとなる
select
  json_extract_scalar(protopayload_auditlog.metadataJson, "$.jobInsertion.job.jobConfig.labels.sheets_access_type") as sheets_access_type,
  json_extract_scalar(protopayload_auditlog.metadataJson, "$.jobInsertion.job.jobConfig.labels.sheets_connector") as sheets_connector,
  json_extract_scalar(protopayload_auditlog.metadataJson, "$.jobInsertion.job.jobConfig.labels.sheets_trigger") as sheets_trigger,
  json_extract_scalar(protopayload_auditlog.metadataJson, "$.firstPartyAppMetadata.sheetsMetadata.docId") as doc_id,
  count(*) as cnt
from
  `{gcp-project-id}.bigquery_auditlog.{auditlog_table}`
where
  date(timestamp) >= "{start_date}"
  and protopayload_auditlog.authenticationInfo.principalEmail = "{target_user}"
  and protopayload_auditlog.metadataJson LIKE "%{target_table or target_dataset}%"
group by
  sheets_access_type,
  sheets_connector,
  sheets_trigger,
  doc_id
order by
  cnt desc
```

今回の移行対応では、上記のクエリで判明した`doc_id`を以下のURLの形式で、利用ユーザごとにリスト化して共有していました。
```
https://docs.google.com/spreadsheets/d/{doc_id}
```

##### 補足
ユーザ側が利用するスプレッドシートに対して、データ系チームがどこまで関わるべきかは議論の余地がありますが、今回は、移行をスムーズに実施すること、スプレッドシートでの利用が多いこと、それがないと業務が進まないことを踏まえて、各自のスプレッドシートのリンクも合わせてお伝えすることとしました。

### 5. Terraform Cloudの利用開始/運用対象のワークスペースの明確化
#### [背景]
元々、プロダクトの開発組織では、Terraformを利用していたのですが、所属チームのほうでは、十分に利用できている状況ではありませんでした。
(Terraform化はされていたが、明確に自分達で運用している感じは乏しかった状況です。)
また、利用しているGCPのプロジェクトはほぼ固定化されていたのですが、Terraform側のtfは、どれを所属チームが面倒をみるのかが明確にはなっていない状況でした。

#### [対応]
所属チームのAnalytics Engineerが`Terraform Cloud`を利用できるようにしてもらいました。
また、所属チームがterraform applyするべきワークスペースを明確にして、それに関するtfファイルは、別ディレクトリで分割するように切り分けてもらいました。

##### 嬉しい副次効果
チームメンバーから、新たなデータセットを作る際は、「これ、Terraformで追加しますよね？PRを投げますね〜」という声が増えてきたのは嬉しいことでした。オペレーションがキチンとトレースできるようになったことは今後の運用に必ずプラスになると感じています。

### 6. 新たな開発ツールの導入
#### [背景]
今までデータマートの更新環境は、`Cloud Composer(Airflow)`を利用していました。様々なソーステーブルを読み込んで、全体のワークフローとして運用管理することには向いていますが、データマートの更新に関しては、Airflowは「帯に短し襷に長し」だと感じていました。

データマートの更新で言えば、BigQueryのマートテーブルを更新することがメインのため、機能的にはtoo much感があること、マートテーブルを実装(=SQLクエリを書く)以外にも、DAGの依存関係を気にする必要があり、純粋にデータマートの実装以外にも注意しないといけないことが多いと思っていました。
所属チームは、データアナリストも在籍しており、必ずしも、そういった開発に慣れていない方もいる中で開発コストが大きいと感じていました。
また、何よりデータマートの開発時のテストのやりづらさも痛感していました。

#### [対応]
ちょうど、所属チームで新規にデータマートを開発するプロジェクトがあり、`dbt`(dbt Core)を導入することにしました。
所属チームや別のチームでdbtに明るいAnalytics Engineerがいたことも追い風になりました。

##### 嬉しい副次効果
dbtを導入することで、圧倒的にデータマートの開発がしやすくなったと感じています。
開発の中で、必要なモデルを実装し、モデル単位でテストが実行できることは、個人的に素晴らしい開発体験だな、と感じています。
また、マートの開発が一通り終わり、品質担保のためのテスト(≒結合テスト)を実施したのですが、
その際でも、必要なテストをモデルのyamlに定義すればテストができるため、圧倒的にテストも実施しやすくなりました。

##### 今後の課題
今後、新規にデータマートを開発する際は、dbtを利用することを想定していますが、既存のデータマート等は、Airfloｗでも動いており、2つの実行環境を並存させることになります。
今後のメンテナンス性を考えると、dbtへの移行は一定必要と考えています。
ただ、何でもdbtに寄せたいとは考えておらず、適材適所の考え方の元、開発運用ツールの使い分けも検討していかねば、と思っているところです。

### 7. ISSUE Buster Dayの採用
#### [背景]
検知/発覚した課題をGitHub ISSUEで管理していますが、ISSUEが積み上がっていき、対応しきれていないものが増えるようになってきました。
緊急度が高い&重要度が高いISSUEを優先的に対応していくため、どうしても`緊急度は低い&重要度が高い`ISSUEが特に残ってしまう状態でした。

#### [対応]
月に一度、Analytics Engineerを中心に、`「ISSUE Buster Day」`を実施することにしました。
チーム全体で重要な会議が少ない金曜の午後に4時間程度時間を取り、解決しきれていないISSUEへ集中して向き合う時間を作りました！
ちなみに、ISSUE Buster Dayは、所属チームのヘッドが「バスターするぞ！」という掛け声の元、名付けしてくれました。(一説によれば、某ゴー○トバスターズから引用した噂もあるとかw)

先日のISSUE Buster Day開始時のSlackでのアナウンスはこんな感じでした。

![スクリーンショット 2022-12-18 14.18.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67571/27eb88e7-bbb4-4889-9f7f-8363be381c0d.png)

メンバーから「ISSUE Buster Dayが楽しみです〜」といった声もあり、結構楽しく実施できているのは良いなと感じています。
前述のリファクタリングは、このISSUE Buster Dayを活用して取組みでもあります。

## まとめ
細かい点を挙げれば他にもあるのですが、主に取り組んできたことは上記の通りです。
日々、分析基盤の運用に向き合う中で、データマネジメントを意識して、直接的・間接的な取組みがある程度はできたかなと感じています。
正直、どれも当たり前の取組みが多いのですが、そういった取組みを普段の開発・運用のプロセスに取り込めたのはとても良かったと思っています。
データが生み出す価値を一定に保つためにも、今後も、日々の開発・運用の中で、データマネジメントを意識した取組みを継続していきたいと考えています。

## 最後に
所属チームでは、データアナリスト・アナリティクスエンジニアを募集しています。
先日も、Noteでチーム紹介をしておりますので、よろしければご参照ください。
[マネフォの「分析推進室」で働く人たちはこんな人たち！（アナリティクスエンジニア編）](https://note.com/mfdata/n/n3e02499439f9)

カジュアル面談も受け付けておりますので、お気軽にご連絡頂けたら幸いですm(_ _)m


[^1]: 先日、弊社のエンジニアブログで、分析基盤の改善が紹介されていますので、よろしければ、ご参照ください。[^2]
[モダンデータスタックでデータ分析基盤の改善〜可用性と保守性もアップ！〜](https://moneyforward.com/engineers_blog/2022/11/16/modern-data-stack/)

[^2]: 実は、弊社には、幾つかのデータ系チームが存在しており、エンジニアブログでの記事は、私が所属するチームとは別のチームの取組みです。
ただ、普段からよくやり取りしているので、ここの記事でも紹介させて頂きました。