イミュータブルデータ・モデルを1年使ってみた

2018-02-09

@grimrose

吉祥寺.pm13

テーマ

「新しい挑戦、新しい視点」

お前、誰よ

  • よしだ

  • とある人材紹介会社のマーケティング部門のデータエンジニア(自称)

  • 好きな言語: Groovy
  • 好きなIDE: IntelliJ IDEA
  • Scala歴: 3年(2015~)
  • ScalaMatsuri 2016, 2017, 2018 スタッフ

普段の仕事

  • 事業KPIの可視化を行うためのWebアプリケーションの設計から運用
  • Scalaを使って日次や月次の集計バッチを実行するアプリケーションの作成
  • 帳票や外部APIなどからデータベースへデータを投入するツールの作成
  • 部門の日常業務を改善するためのちょっとしたツールの作成

きっかけ

話すこと

イミュータブルデータ・モデルを1年使ってみてどうだったかを端折って

image

要件

  • とある業務に関する操作履歴(どのカラムの値をどう変更したか等)を残す
  • ある時点での結果で集計を行うが、同月内に複数回人為的に集計と確認のタイミングが発生する
    • 前回の集計との比較が行えるようにする
    • カラムの値を操作をするので前回との差分も見えるようにする

ORM

  • プロジェクトが始まったのは2016年
  • PHPを使うメンバーが多かった
    • FuelPHPのアップデートが止まっていた
    • 別のフレームワークを選定 -> Laravel
  • 集計は、日次バッチを運用しているScalaに

PHP

主に登録

Scala

主に集計

insert

// イベントの登録
$event = new Event();
...

$id = DB::table('登録イベントテーブル')->insertGetId($event->as_array());

update(delete -> insert)

// 現在のレコードを取得
$record = DB::table('登録イベントテーブル')->where('id', '=', $id)->get();

// 履歴テーブルへのinsert
DB::table('登録イベント履歴テーブル')->insert($record->as_array());

// 前イベントIDのレコードを削除
$previousId = $record->id;
DB::table('登録イベントテーブル')->where('id', '=', $previousId)->delete();

// イベントの登録
$event = new Event();
$event->previousId = $previousId;
...

$id = DB::table('登録イベントテーブル')->insertGetId($event->as_array());

ぶっちゃけどうなの?

  • マスタに関してReladomo知っていれば、使っていた
    • 2年前は知らなかった
    • 有効時間データモデルという名前がついてたのは知らなかった

ぶっちゃけどうなの?

  • 前イベントIDを辿る際に再帰クエリ使えないDB(MySQL5.x)だとアプリケーション側で頑張るしか無い
    • SQLアンチパターンのナイーブツリー
    • 単方向への履歴なのでやむを得ず

ぶっちゃけどうなの?

ORMについて

  • ORMの機能は殆ど使わなかった(使えなかった)
    • 下手にクエリビルダー使うより素直にSQL書いた方が見やすい
    • updated_atのカラムが無いので暗黙的更新が邪魔
  • Repositoryのinterfaceを提供
    • store
      • $storedId = (is_null($entity->id)) ? insert($entity) : update($entity)

ぶっちゃけどうなの?

パフォーマンス

  • 書き込みが多い業務だとパフォーマンスに影響がでるかも
    • 書き込みは、DBのインスタンスに依存するが、利用頻度が少ないので影響は出ていない。
    • 読み込みは、地道にインデックスを貼れば問題ない

おわりに

データモデルは、要件に合わせて採用しましょう。