Slide 1

Slide 1 text

UPDATEがシステムを 複雑にする? イミュータブルデータモデルの すすめ PHPカンファレンス新潟2025 akshimo

Slide 2

Slide 2 text

● akshimo(あくしも) ● 2021年〜新潟に移住 ● フリーランス ● 初登壇! ● おすすめのラーメン:東横

Slide 3

Slide 3 text

● 学生もわかる内容に ● 学習・設計・仕事など何かのキッカケにして欲しい 本日のコンセプト

Slide 4

Slide 4 text

● イミュータブルデータモデルの概要 ● イミュータブルデータモデルを使った実例 ● イベント駆動と合わせたPHP & Laravelへの適用 本日のお品書き

Slide 5

Slide 5 text

● イミュータブルデータモデルの概要 ● イミュータブルデータモデルを使った実例 ● イベント駆動と合わせたPHP & Laravelへの適用 イミュータブルデータモデルの 基本と例を話します

Slide 6

Slide 6 text

● イミュータブルデータモデルの概要 ● イミュータブルデータモデルを使った実例 ● イベント駆動と合わせたPHP & Laravelへの適用 ちょっとひとスパイス! もう一歩踏み込んだ使い方のご提案

Slide 7

Slide 7 text

イミュータブルデータモデルの概要

Slide 8

Slide 8 text

Yoshitaka Kawashimaさんが考案したモデリング手法。 データの更新に注目し、イミュータブル=更新されないモデルを設計し ていくことで複雑さに立ち向かうもの。 イミュータブルデータモデル https://scrapbox.io/kawasima/イミュータブルデータモデル イミュータブルデータモデル

Slide 9

Slide 9 text

イミュータブル データモデル

Slide 10

Slide 10 text

イミュータブル データモデル

Slide 11

Slide 11 text

Immutable=不変

Slide 12

Slide 12 text

Immutable=不変 => UPDATEをしない

Slide 13

Slide 13 text

Immutable=不変 => UPDATEをしない UPDATEすると複雑になるから なくしてこうぜ!

Slide 14

Slide 14 text

● ロストアップデート? ● ロック? ● ミスって変にデータを書き換えてしまったら? UPDATEは不整合を起こしやすい

Slide 15

Slide 15 text

● わかりやすく、高度な専門知識を必要としない ● モデリングのズレを一定解消できる ● シンプルな設計ができる この辺が良いなと思ってます!

Slide 16

Slide 16 text

UPDATEをしないとか そんなの無理でしょー!

Slide 17

Slide 17 text

全くUPDATEしないことも可能だけど 現実的でないことも多い! できるだけ UPDATEを減らすようにしてみよう! UPDATEをしないとか そんなの無理でしょー!

Slide 18

Slide 18 text

● 事業活動のヒト ● 業務の関心のモノ ● ユーザー、担当者、商品、店舗... データの種類 リソース ● 過去に起きたコト ● 注文、予約、キャンセル... イベント

Slide 19

Slide 19 text

● 事業活動のヒト ● 業務の関心のモノ ● ユーザー、担当者、商品、店舗... データの種類 リソース ● 過去に起きたコト ● 注文、予約、キャンセル... イベント UPDATEして OK!

Slide 20

Slide 20 text

● 事業活動のヒト ● 業務の関心のモノ ● ユーザー、担当者、商品、店舗... データの種類 リソース ● 過去に起きたコト ● 注文、予約、キャンセル... イベント UPDATEして OK! UPDATEは NG!

Slide 21

Slide 21 text

● 事業活動のヒト ● 業務の関心のモノ ● ユーザー、担当者、商品、店舗... データの種類 リソース ● 過去に起きたコト ● 注文、予約、キャンセル... イベント UPDATEして OK! UPDATEは NG! “過去に起きたこと ”が 更新されるわけないしな …

Slide 22

Slide 22 text

“起きたコト ”が変更されることはない 起きたコト 金額 ユーザーID 日時 入金 3,000円 1 2024/11/21 10:00 入金 4,000円 1 2024/11/21 10:30 出金 6,000円 1 2024/11/21 11:00 入金 2,000円 1 2024/11/21 11:30

Slide 23

Slide 23 text

“起きたコト ”から今の状態を計算できる 起きたコト 金額 ユーザー ID 日時 入金 3,000円 1 2024/11/21 10:00 入金 4,000円 1 2024/11/21 10:30 出金 6,000円 1 2024/11/21 11:00 入金 2,000円 1 2024/11/21 11:30 残高 3,000円

Slide 24

Slide 24 text

イチイチ計算するのは辛いので 計算した結果(リソース)を保存しておく

Slide 25

Slide 25 text

イミュータブルデータモデル を使った実例

Slide 26

Slide 26 text

ECサイトの荷物管理の例

Slide 27

Slide 27 text

実際にあったモデル(に近いもの)

Slide 28

Slide 28 text

実際にあったモデル(に近いもの) いろんな状態があって 複雑…

Slide 29

Slide 29 text

日時属性に注目する

Slide 30

Slide 30 text

日時属性に注目する

Slide 31

Slide 31 text

日時属性に注目する

Slide 32

Slide 32 text

日時属性に注目する

Slide 33

Slide 33 text

日時属性に注目する

Slide 34

Slide 34 text

日時属性に注目する

Slide 35

Slide 35 text

日時属性に注目する 未来日が入るであろう 配送予定日は除く!

Slide 36

Slide 36 text

リソースとイベントに分ける リソース イベント

Slide 37

Slide 37 text

勝ったぜ!完!!

Slide 38

Slide 38 text

勝ったぜ!完!! んなわけない!

Slide 39

Slide 39 text

日時属性に注目する UPDATEが発生

Slide 40

Slide 40 text

1つのイベントには 1つの日時属性のみ

Slide 41

Slide 41 text

1つのイベントには 1つの日時属性のみ

Slide 42

Slide 42 text

1つのイベントには 1つの日時属性のみ

Slide 43

Slide 43 text

1つのイベントには 1つの日時属性のみ

Slide 44

Slide 44 text

イベントへの UPDATEはなくなった!

Slide 45

Slide 45 text

勝ったぜ!完!!

Slide 46

Slide 46 text

勝ったぜ!完!! 本当に?

Slide 47

Slide 47 text

隠れた日時属性を見つけ出す

Slide 48

Slide 48 text

更新日時を保存したい状況はない?

Slide 49

Slide 49 text

更新日時を保存したい状況はない?

Slide 50

Slide 50 text

2025年 5月31日 お客様からお問い合わせあり。 住所に入力不備があったとのことなので、荷物番号XXXの配送先住所を変更 した。 運用でよく見るメモ

Slide 51

Slide 51 text

隠れた日時属性を見つけ出す

Slide 52

Slide 52 text

さらにnullをなくしていく nullは10億ドルの損失

Slide 53

Slide 53 text

nullをなくす

Slide 54

Slide 54 text

nullをなくす

Slide 55

Slide 55 text

nullをなくす

Slide 56

Slide 56 text

どうすれば nullをなくせる?

Slide 57

Slide 57 text

どうすれば nullをなくせる? 交差テーブルを使おう!

Slide 58

Slide 58 text

交差テーブルを使おう!

Slide 59

Slide 59 text

交差テーブルを使おう!

Slide 60

Slide 60 text

1. エンティティを抽出する 2. エンティティを分類する 3. イベントエンティティには1つの日時属性しかもたないようにする 4. リソースに隠されたイベントを抽出する 5. 非依存リレーションシップを交差エンティティにする イミュータブルデータモデルの手順 Kawashima 『イミュータブルデータモデル』 https://scrapbox.io/kawasima/イミュータブルデータモデル

Slide 61

Slide 61 text

イベント駆動と合わせた PHP & Laravelへの適用

Slide 62

Slide 62 text

The biggest outcome of the summit was recognizing that when people talk about “events”, they actually mean some quite different things. Martin Fowler 「What do you mean by “Event-Driven”?」 https://martinfowler.com/articles/201701-event-driven.html イベント is 何

Slide 63

Slide 63 text

LaravelにはEvent機能がある php artisan make:event PodcastProcessed php artisan make:listener SendPodcastNotification --event=PodcastProcessed https://laravel.com/docs/12.x/events

Slide 64

Slide 64 text

LaravelにはEvent機能がある class SendPodcastNotification { public function handle(PodcastProcessed $event): void { // ... } } https://laravel.com/docs/12.x/events

Slide 65

Slide 65 text

LaravelにはEvent機能がある class SendPodcastNotification { public function handle(PodcastProcessed $event): void { // ... } } https://laravel.com/docs/12.x/events Listenerクラス

Slide 66

Slide 66 text

LaravelにはEvent機能がある class SendPodcastNotification { public function handle(PodcastProcessed $event): void { // ... } } https://laravel.com/docs/12.x/events 引数で発行された イベントを受け取る

Slide 67

Slide 67 text

LaravelにはEvent機能がある class SendPodcastNotification { public function handle(PodcastProcessed $event): void { // ... } } https://laravel.com/docs/12.x/events やりたい 処理を書く

Slide 68

Slide 68 text

LaravelにはEvent機能がある class SendPodcastNotification { public function handle(PodcastProcessed $event): void { // ... } } https://laravel.com/docs/12.x/events キューとかで動くが 同期的にも動く

Slide 69

Slide 69 text

$dispatchesEvents

Slide 70

Slide 70 text

$dispatchesEvents class User extends Authenticatable { protected $dispatchesEvents = [ 'saved' => UserSaved::class, 'deleted' => UserDeleted::class, ]; } https://laravel.com/docs/12.x/eloquent

Slide 71

Slide 71 text

$dispatchesEvents class User extends Authenticatable { protected $dispatchesEvents = [ 'saved' => UserSaved::class, 'deleted' => UserDeleted::class, ]; } https://laravel.com/docs/12.x/eloquent Saveされたら UserSavedイベントを 発行

Slide 72

Slide 72 text

もうお分かりですかね?

Slide 73

Slide 73 text

ピッキングイベントが createされたらイベント発行 class Picking extends Model { protected $dispatchesEvents = [ 'created' => PickingCreated::class, ]; }

Slide 74

Slide 74 text

Listenerで発行されたイベントについて処理 class IssueInvoice { public function handle(PickingCreated $event): void { // ... } }

Slide 75

Slide 75 text

これであなたも明日からイベント駆動!

Slide 76

Slide 76 text

こんなシステムがあったとする 受注サービス 引当サービス 決済サービス 荷物作成 サービス call call call

Slide 77

Slide 77 text

イベントを使おう! 受注サービス 引当サービス 決済サービス 荷物作成 サービス Order Created pub sub sub sub

Slide 78

Slide 78 text

● 受注サービスはイベントを発行するだけ(publish) ● 呼び出されていたサービスはイベントを購読するだけ(subscribe) ● イベント発行後、どんなサービスが実行されるか受注サービスは知らない イベントを使うと …

Slide 79

Slide 79 text

👏 一旦本日のお品書きはこれで終了!

Slide 80

Slide 80 text

蛇足(ただし長い)

Slide 81

Slide 81 text

ソフトウェアの開発ってなんで 大変なんでしょうか?

Slide 82

Slide 82 text

● ビジネス要求が遅いから(Late) ※Latestで最新という意味であることに注意 ● 逆に言うと、最初からビジネス要求が完全固定されていて、 変更されることも絶対にないなら開発ってすごい楽だよね 個人的Answer

Slide 83

Slide 83 text

1. プロジェクトの開始時点にすべての要求を集めることは できない 2. 集めたところで、要求はどれも必ずといっていいほど変 わる 3. やるべきことはいつだって、与えられた時間と賃金より 多い Jonathan Rasmusson 『アジャイルサムライ』

Slide 84

Slide 84 text

ソフトウェアを書き始める時、我々は対象 を十分に理解しているわけではない。 高度に生産的なチームは、自分たちの知識 を意識的に育てて、継続的学習を実践す る。 Eric Evans『ドメイン駆動設計』

Slide 85

Slide 85 text

架橋工事がプログラミングのようなものだとすると、橋の 途中で岸がさらに50メートル先になってしまった、といった 具合です。 (中略)私たちが作成するソフトウェアはユーザ要件に柔軟 に適応し、進化するように設計されています。 Sam Newman『マイクロサービスアーキテクチャ』

Slide 86

Slide 86 text

受注サービス 引当サービス 決済サービス 荷物作成 サービス Order Created pub sub sub sub

Slide 87

Slide 87 text

受注サービス 引当サービス 決済サービス 荷物作成 サービス Message

Slide 88

Slide 88 text

Object Object Object Object Message

Slide 89

Slide 89 text

Object Object Object Message Message そうだね! Smalltalkだね! Message

Slide 90

Slide 90 text

● イベントドリブンなアーキテクチャとアラン・ケイの メッセージベースのオブジェクト指向は似ている気がする? ● キーワードは「遅延束縛」

Slide 91

Slide 91 text

The Japanese have a small word - ma - for "that which is in between" - perhaps the nearest English equivalent is "interstitial". The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be. 日本語には「間」という言葉がある。おそらく最も近い英語は「interstitial」だろう。 偉大で成長可能なシステムを作る上で重要なのは、モジュールの内部特性や動 作よりも、モジュールがどのようにコミュニケーションをとるかを設計することだ。 (意訳) Alan C.Kay http://wiki.c2.com/?AlanKayOnMessaging

Slide 92

Slide 92 text

受注サービス 引当サービス 決済サービス 荷物作成 サービス Order Created pub sub sub sub こいつが鍵って…コト!?

Slide 93

Slide 93 text

● メッセージを受信したオブジェクトが何をするかは受信側次第。 (送信側は預かり知らぬ) ● つまり、意思決定や解釈(束縛)を極力遅くしている =>遅延束縛 ● しかも、コード実行中にプログラムを書き換え、メッセージの解釈を変更で きる メッセージベースオブジェクト指向

Slide 94

Slide 94 text

● イベントを購読したサービスが何をするかは購読側次第。 (発行側は預かり知らぬ) ● つまり、意思決定や解釈(束縛)を極力遅くしている =>遅延束縛 イベント駆動

Slide 95

Slide 95 text

ビジネス要求は遅い (Late) 故に、システムの意思決定も 遅くできるような構造を採用する => 遅延束縛(LateBinding)する

Slide 96

Slide 96 text

● 間=メッセージ=イベント ● これを要素間でやり取りすることにより、意思決定を極力遅延 ● 逆の言い方をすれば「最初から全てを知っている必要がない」 => 改変の容易さに繋がる => アジャイル的な考え方

Slide 97

Slide 97 text

ご清聴 ありがとうございました! Ask The Speakerお待ちしてます!