Slide 1

Slide 1 text

古き良き Laravel のシステムは 関数型スタイルでリファクタできるのか レバテック開発部 ひがき

Slide 2

Slide 2 text

今回の話

Slide 3

Slide 3 text

| © 2025 Levtech Co., Ltd. 3 VISIONとMISSION 今回の話 ITエンジニアと開発組織の 挑戦と成長を加速させる HR プラットフォーム

Slide 4

Slide 4 text

| © 2025 Levtech Co., Ltd. 4 今回は「繋げる」領域でのお話 今回の話 QA事業 コンサル事業 レバテックが目指す HR プラットフォーム

Slide 5

Slide 5 text

| © 2025 Levtech Co., Ltd. 5 「繋げる」を実現する 内製システム 今回の話 LTSF に 案件 と IT フリーランス の情報があつまり、マッチングされている 案件 登録 ITフリーランス 営業支援システム LTSF ( LevTech Sales Force Automation )

Slide 6

Slide 6 text

| © 2025 Levtech Co., Ltd. 6 PHP + 関数型スタイル で負債を低減したい 今回の話 Scott Wlaschin (著) 猪股 健太郎 (翻訳) 株式会社ドワンゴ 「関数型ドメインモデリング」 LTSF 10年の歴史が積み重なった 古き良き MVC システムに 関数型スタイルを適用して 改善することをめざす

Slide 7

Slide 7 text

| © 2025 Levtech Co., Ltd. 7 レバテック開発部 ひがき HIGAKI ぺちおだ2025のスタッフです! 本日はあじの部屋にいることが多いです! LIKE:筋トレ・ポーカー・Switch2(予約済)

Slide 8

Slide 8 text

LTSF|改善のターゲット

Slide 9

Slide 9 text

| © 2025 Levtech Co., Ltd. 9 「案件推薦」がターゲット LTSF|改善のターゲット LTSF この案件どうですか? 「案件推薦」 案 件 企業とエンジニアに提案してから決定するかどうかまで その進捗情報はひとつのレコードで管理される… 案 件 案 件

Slide 10

Slide 10 text

| © 2025 Levtech Co., Ltd. 10 商談フェーズ 登録フェーズ 合意フェーズ 提案フェーズ 「案件推薦」の状態遷移 LTSF|改善のターゲット 初期 状態 色々 ある 企業 承諾 双方 承諾 色々 ある NG 企業 に提案 エンジニア に推薦 エンジニアが承諾する エンジニアが書類確認する … 面談する オファーする … 推薦を希望 する … 状態数は25個ほど!

Slide 11

Slide 11 text

| © 2025 Levtech Co., Ltd. 11 ひとつのレコードで状態を管理 LTSF|改善のターゲット id status kama boko aji 1 1 hoge _ _ … id status kama boko aji 1 2 fuga 5 _ … 案件推薦 Model (MVC) 約 120 の Nullable カラムの 神テーブル&神モデル 😨 状態(status) によって値が 入力されたりされなかったり…

Slide 12

Slide 12 text

| © 2025 Levtech Co., Ltd. 12 ひとつのエンドポイントで状態を管理 LTSF|改善のターゲット Request クラスに状態遷移の ビジネスロジックが集中 約 1300 行の バリデーション 😨 もろもろの情報更新も同時に実行

Slide 13

Slide 13 text

| © 2025 Levtech Co., Ltd. 13 POINT 01 ひとつのエンドポイント POINT 02 Request クラスにビジネスロジックが集中 POINT 03 辛いポイント ひとつのテーブル

Slide 14

Slide 14 text

| © 2025 Levtech Co., Ltd. 14 一気にすべてを解決できれば理想だけど… "刻むんだ" 目の前の1段を登るために必要な要素を 1段の中でさらに刻んで 自分が登れる小さいステップを作るんだ その行動を努力と呼ぶ 葦原大介『ワールドトリガー』第247話(集英社)より引用

Slide 15

Slide 15 text

| © 2025 Levtech Co., Ltd. 15 POINT 01 ひとつのエンドポイント POINT 02 Request クラスにビジネスロジックが集中 POINT 03 解決のステップを刻む ひとつのテーブル 今回はこの部分を改善する!

Slide 16

Slide 16 text

| © 2025 Levtech Co., Ltd. 16 つまり LTSF|改善のターゲット リクエストバリデーション処理をドメイン層に移動させたい Scott Wlaschin (著), 猪股 健太郎 (翻訳) 株式会社ドワンゴ 「関数型ドメインモデリング」 3.5.1 オニオンアーキテクチャより引用

Slide 17

Slide 17 text

| © 2025 Levtech Co., Ltd. 17 商談フェーズ 登録フェーズ 合意フェーズ 提案フェーズ (再掲)ひとつのエンドポイントで実行される状態遷移 LTSF|改善のターゲット 初期 状態 色々 ある 企業 承諾 双方 承諾 色々 ある NG 企業 に提案 エンジニア に推薦 エンジニアが承諾する エンジニアが書類確認する … 面談する オファーする … 推薦を希望 する …

Slide 18

Slide 18 text

| © 2025 Levtech Co., Ltd. 18 状態ごとの情報更新/状態遷移でわけて考える LTSF|改善のターゲット 初期 状態 色々 ある 企業 承諾 双方 承諾 色々 ある NG 企業 に提案 エンジニア に推薦 エンジニアが承諾した エンジニアが書類確認した … 面談した オファーした … 推薦を希望 した … 情報更新 状態遷移 状態遷移できる条件

Slide 19

Slide 19 text

| © 2025 Levtech Co., Ltd. 19 さらにターゲットを 1 項目のみに刻む LTSF|改善のターゲット 初期 状態 色々 ある 企業 承諾 双方 承諾 色々 ある NG 企業 に提案 エンジニア に推薦 エンジニアが承諾した エンジニアが書類確認した … 面談した オファーした … 推薦を希望 した … 情報更新 状態遷移 状態遷移できる条件

Slide 20

Slide 20 text

やっていき

Slide 21

Slide 21 text

| © 2025 Levtech Co., Ltd. 21 まずは動作が変わっていないことを保証するためのテストを書きたい が、リクエストバリデーションにロジックが集中しているため統合テストしか書けない… 統合テストは正常系のみ検査したい(実行時間との兼ね合い) が、統合テストでしか準正常系のテストが書けない… リファクタ方針 やっていき 実行時間との兼ね合い?? ■ 統合テストではDBも含めてテストを行う ■ IOに時間がかかる Eloquentのモデルイベントを多用しているため、 0からモデルイベントを発火させる必要がある LTSF DB

Slide 22

Slide 22 text

| © 2025 Levtech Co., Ltd. 22 リファクタ方針 やっていき 1. 統合テストに正常系・準正常系のテストを追加 2. ドメイン層にロジックを移行 3. 統合テストをユニットテストに移行し、統合テストの準正常系のテストを削除 Scott Wlaschin (著), 猪股 健太郎 (翻訳) 株式会社ドワンゴ「関数型ドメインモデリング」より引用 テスト自体も ロジックとともに移行させる

Slide 23

Slide 23 text

| © 2025 Levtech Co., Ltd. 23 ステップ やっていき 1. 正常系・準正常系の統合テスト追加 2. ドメイン層でロジックを実現 3. ドメイン層の正常系・準正常系のユニットテスト追加 4. 元々のロジック削除 5. 準正常系の統合テスト削除

Slide 24

Slide 24 text

| © 2025 Levtech Co., Ltd. 24 ステップ やっていき 1. 正常系・準正常系の統合テスト追加 2. ドメイン層でロジックを実現 3. ドメイン層の正常系・準正常系のユニットテスト追加 4. 元々のロジック削除 5. 準正常系の統合テスト削除

Slide 25

Slide 25 text

| © 2025 Levtech Co., Ltd. 25 1. 正常系・準正常系の統合テスト追加 ▽ 正常系のテスト 遷移条件を全て満たす 企業承諾 の案件推薦を作成 → 双方承諾 に遷移できること確認 ▽ 準正常系のテスト 未確認の書類が存在する 企業承諾 の案件推薦を作成 → 双方承諾 に遷移できないことを確認 やっていき 企業 承諾 双方 承諾 エンジニアが書類確認済

Slide 26

Slide 26 text

| © 2025 Levtech Co., Ltd. 26 1. 正常系・準正常系の統合テスト追加 やっていき コード載せる 統合テスト 追加!  約750行 ● Eloquentのモデルイベントを多用しているため、 0からモデルイベントを発火させる必要がある ● DBレコードの更新を何度も行う必要があるため、 IOの処理を何度も行っており時間もかかる… ほとんどはテスト対象の準備 🥲

Slide 27

Slide 27 text

| © 2025 Levtech Co., Ltd. 27 ステップ やっていき 1. 正常系・準正常系の統合テスト追加 2. ドメイン層でロジックを実現 3. ドメイン層の正常系・準正常系のユニットテスト追加 4. 元々のロジック削除 5. 準正常系の統合テスト削除

Slide 28

Slide 28 text

| © 2025 Levtech Co., Ltd. 28 ビジネスロジック 企業承諾 → 双方承諾 の遷移には「エンジニアが書類確認済」が条件 2. ドメイン層でロジックを実現 やっていき 企業 承諾 双方 承諾 エンジニアが書類確認済

Slide 29

Slide 29 text

| © 2025 Levtech Co., Ltd. 29 2. ドメイン層でロジックを実現 やっていき 案件推薦更新用のエンドポイント

Slide 30

Slide 30 text

| © 2025 Levtech Co., Ltd. 30 2. ドメイン層でロジックを実現 1⃣ デシリアライズ 2⃣ IO処理 3⃣ 状態遷移 やっていき

Slide 31

Slide 31 text

| © 2025 Levtech Co., Ltd. 31 1⃣ デシリアライズ APIリクエストからDTOを作成 - Godモデル と 双方承諾モデル のみ作成 - ドメインモデルを作りきらず、今回必要なドメインプロパティのみに限定 2. ドメイン層でロジックを実現 やっていき

Slide 32

Slide 32 text

| © 2025 Levtech Co., Ltd. 32 2⃣ IO処理 状態遷移判定に必要な情報をDBから取得 - 状態遷移関数内の副作用を避けるため、DBアクセスした結果を状態遷移関数に渡す 2. ドメイン層でロジックを実現 やっていき

Slide 33

Slide 33 text

| © 2025 Levtech Co., Ltd. 33 3⃣ 状態遷移 企業承諾 → 双方承諾 の遷移には「エンジニアが書類確認済」が条件 純粋関数として実現する 詳細は次のスライド 2. ドメイン層でロジックを実現 やっていき Godモデル 書類 双方承諾モデル ドメインエラー 純粋 関数

Slide 34

Slide 34 text

| © 2025 Levtech Co., Ltd. 34 ■ 純粋なPHPですべて実装されおり、入力が決まれば、出力が一意に決まる ■ 全ての条件をチェックする 2.1. 状態遷移 やっていき Godモデル 書類 契約書類が 確認済 WorkflowErrorを追加 Workflow Errorが 存在しない No 双方承諾モデル ドメインエラー No このブロックを追加していくことで ロジックの移行を進められる 今回移行するロジック

Slide 35

Slide 35 text

| © 2025 Levtech Co., Ltd. 35 「関数型ドメインモデリング」で参考にしたこと ■ 内部を見なくても、予測可能で理解しやすい関数にする ■ I/Oを端に追いやる 副作用を避けるためDBアクセスの結果を状態遷移の関数に渡した 2. ドメイン層でロジックを実現 やっていき Scott Wlaschin (著) 猪股 健太郎 (翻訳) 株式会社ドワンゴ 「関数型ドメインモデリング」 Godモデル 書類 双方承諾モデル ドメインエラー 純粋 関数

Slide 36

Slide 36 text

| © 2025 Levtech Co., Ltd. 36 ステップ やっていき 1. 正常系・準正常系の統合テスト追加 2. ドメイン層でロジックを実現 3. ドメイン層の正常系・準正常系のユニットテスト追加 4. 元々のロジック削除 5. 準正常系の統合テスト削除

Slide 37

Slide 37 text

| © 2025 Levtech Co., Ltd. 37 3. ドメイン層の正常系・準正常系のユニットテスト追加 ▽ 正常系のテスト - 入力(Godモデルと確認済みの書類) - 期待の出力(双方承諾モデル) ▽ 準正常系のテスト - 入力(Godクラスと未確認の書類) - 期待の出力(ドメインエラー) やっていき Godモデル 書類 双方承諾モデル 純粋 関数 Godモデル 書類 ドメインエラー 純粋 関数

Slide 38

Slide 38 text

| © 2025 Levtech Co., Ltd. 38 コード載せる 統合テスト  約 750 行 3. ドメイン層の正常系・準正常系のユニットテスト追加 やっていき ユニットテスト  約 30 行 🎉

Slide 39

Slide 39 text

| © 2025 Levtech Co., Ltd. 39 嬉しいポイント 😊 ■ テストの準備が楽になった - DBにデータを作らなくても良くなった → IO処理がなくなった - 複雑なバリデーションを通す必要がなくなった ■ テストの実行時間が短くなった - ビジネスロジックのテストはユニットテストに寄せていきたい 3. ドメイン層の正常系・準正常系のユニットテスト追加 やっていき

Slide 40

Slide 40 text

| © 2025 Levtech Co., Ltd. 40 1. 正常系・準正常系の統合テスト追加 2. ドメイン層でロジックを実現 3. ドメイン層の正常系・準正常系のユニットテスト追加 4. 元々のロジック削除 5. 準正常系の統合テスト削除 ステップ やっていき

Slide 41

Slide 41 text

| © 2025 Levtech Co., Ltd. 41 4. 元々のロジック削除 元々のリクエストバリデーションを消して、統合テストが通過するかチェック 統合テストで元々の振る舞いに変更がないことを確認 やっていき

Slide 42

Slide 42 text

| © 2025 Levtech Co., Ltd. 42 ステップ やっていき 1. 正常系・準正常系の統合テスト追加 2. ドメイン層でロジックを実現 3. ドメイン層の正常系・準正常系のユニットテスト追加 4. 元々のロジック削除 5. 準正常系の統合テスト削除

Slide 43

Slide 43 text

| © 2025 Levtech Co., Ltd. 43 5. 準正常系の統合テスト削除 正常系のみチェックする方針なので、準正常系のテストを削除 やっていき

Slide 44

Slide 44 text

| © 2025 Levtech Co., Ltd. 44 リファクタ完了 🎉

Slide 45

Slide 45 text

リファクタを通して

Slide 46

Slide 46 text

| © 2025 Levtech Co., Ltd. 46 関数型スタイルにより享受できたメリット リファクタを通して ■ 状態と振る舞いを分離 「モデル」 と 「モデルへの遷移」 で関心ごとを分離できた 今回の対象のビジネスロジックを「モデルへの遷移」の条件として表現できた ■ ドメイン層(状態遷移関数)が参照透過性を満たす IOを端に追いやったことで実現できた ■ 内部を見なくても、予測可能で理解しやすい関数にする Godモデル 書類 双方承諾モデル ドメインエラー 純粋 関数

Slide 47

Slide 47 text

| © 2025 Levtech Co., Ltd. 47 振り返り ■ Result型(クラス)を作ればもう少し整理して書けたかも   PHPでResult型デフォルトであったら使ってた ■ PHPで関数型を再現する場合、クラスを大量に作ることになりそう   ある集合を作ろうと思った場合、PHPではクラスで表現することが多い ■ 0から理想のコードを作るより、   今あるコードをどう理想に近づけるかの面白さを学んだ(大変だけど) リファクタを通して

Slide 48

Slide 48 text

まとめ

Slide 49

Slide 49 text

| © 2025 Levtech Co., Ltd. 49 古き良き Laravel のシステムは 関数型スタイルでリファクタできるのか まとめ 現状と理想のギャップを段階的に整理し、 局所的に関数型スタイルを取り込むことでリファクタできるかも

Slide 50

Slide 50 text

宣伝

Slide 51

Slide 51 text

開発職向け会社紹介資料 プロダクトや開発組織についてご紹介しています。 https://speakerdeck.com/leverages/levtech-hui-she-shao-jie-zi-liao-enzi niazhi-xiang-ke レバテック開発部テックブログ 日々の開発におけるリアルをお届けしています! https://zenn.dev/p/levtech カジュアル面談フォーム 気軽にご応募ください!いろんなお話しましょう! https://hrmos.co/pages/leverages/jobs/A_c_00071

Slide 52

Slide 52 text

| © 2025 Levtech Co., Ltd. 52 We Are Hiring! ブースに遊びに来てください〜

Slide 53

Slide 53 text

Appendix: プログラム

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

| © 2025 Levtech Co., Ltd. 56