#!/usr/bin/env python # coding: utf-8 # ## イミュータブルデータ・モデルを1年使ってみた # # 2018-02-09 # # [@grimrose](https://twitter.com/grimrose) # # [吉祥寺.pm13](https://kichijojipm.connpass.com/event/75327/) # ### テーマ # # **「新しい挑戦、新しい視点」** # # ### お前、誰よ # # * よしだ # # * twitter: [@grimrose](https://twitter.com/grimrose) # * github: [@grimrose](https://github.com/grimrose) # # * とある人材紹介会社のマーケティング部門のデータエンジニア(自称) # * 好きな言語: Groovy # * 好きなIDE: IntelliJ IDEA # * Scala歴: 3年(2015~) # * [ScalaMatsuri](http://scalamatsuri.org) 2016, 2017, 2018 スタッフ # ### 普段の仕事 # # * 事業KPIの可視化を行うためのWebアプリケーションの設計から運用 # * Scalaを使って日次や月次の集計バッチを実行するアプリケーションの作成 # * 帳票や外部APIなどからデータベースへデータを投入するツールの作成 # * 部門の日常業務を改善するためのちょっとしたツールの作成 # ### きっかけ # #

update文、使わなくてもロジック組めるよって分かると、update使わなくなるなぁ

— とーます (@grimrose) 2017年8月30日
# # ### 話すこと # # イミュータブルデータ・モデルを1年使ってみてどうだったかを端折って # ### 参考資料 # # [イミュータブルデータモデル(入門編)](https://www.slideshare.net/kawasima/ss-40471672) # # [イミュータブルデータモデル(世代編)](https://www.slideshare.net/kawasima/ss-44958468) # # [データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3](https://www.slideshare.net/itohiro73/jjug-ccc-2017-spring-bitemporal-data-modeling-and-reladomo) # # [イミュータブルデータモデルと webアプリケーションにおける現実解](https://qiita.com/urakawa/items/3d7777e6734cb5c15bd1) # ![image](img/ER.svg) # ### 要件 # # * とある業務に関する操作履歴(どのカラムの値をどう変更したか等)を残す # * ある時点での結果で集計を行うが、同月内に複数回人為的に集計と確認のタイミングが発生する # * 前回の集計との比較が行えるようにする # * カラムの値を操作をするので前回との差分も見えるようにする # ### ORM # # * プロジェクトが始まったのは2016年 # * PHPを使うメンバーが多かった # * FuelPHPのアップデートが止まっていた # * 別のフレームワークを選定 -> Laravel # * 集計は、日次バッチを運用しているScalaに # #### PHP # # 主に登録 # # * [Laravel](https://readouble.com/laravel/5.2/ja/) 5.2(とある事情により) # * [クエリービルダー](https://readouble.com/laravel/5.2/ja/queries.html) # * [Eloquent](https://readouble.com/laravel/5.2/ja/eloquent.html) # #### Scala # # 主に集計 # # * [Skinny-ORM](http://skinny-framework.org/documentation/orm.html) # * [ScalikeJDBC](http://scalikejdbc.org/) # ### insert # # ```php # // イベントの登録 # $event = new Event(); # ... # # $id = DB::table('登録イベントテーブル')->insertGetId($event->as_array()); # ``` # # ### update(delete -> insert) # # ```php # // 現在のレコードを取得 # $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のインスタンスに依存するが、利用頻度が少ないので影響は出ていない。 # * 読み込みは、地道にインデックスを貼れば問題ない # ### おわりに # # データモデルは、要件に合わせて採用しましょう。 #