Slide 1

Slide 1 text

Masanobu Naruse SWIMMING IN HELL

Slide 2

Slide 2 text

Slide 3

Slide 3 text

Developer Relations Team Fans Making Opportunity Interest Comprehension

Slide 4

Slide 4 text

なるせ

Slide 5

Slide 5 text

PHPerKaigi スポンサー するんだけど LT やってもらえる? なるせ

Slide 6

Slide 6 text

PHPerKaigi スポンサー するんだけど LT やってもらえる? はい喜んで! なるせ

Slide 7

Slide 7 text

PHPer 茶会の LT だから なるせ

Slide 8

Slide 8 text

!? PHPer 茶会の LT だから 面白くしてね なるせ

Slide 9

Slide 9 text

高くあげられたハードル 超えるためのネタは 面白くしてね

Slide 10

Slide 10 text

昨年 2018年9月

Slide 11

Slide 11 text

クリーンアーキテクチャの実装例について

Slide 12

Slide 12 text

その中のスライド

Slide 13

Slide 13 text

仕様書

Slide 14

Slide 14 text

無し

Slide 15

Slide 15 text

前任者

Slide 16

Slide 16 text

無し

Slide 17

Slide 17 text

頼れる仲間は

Slide 18

Slide 18 text

ベトナムへ

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

仕様書無し 前任者無し 頼れる仲間はベトナムへ

Slide 21

Slide 21 text

というわけで今日のお話は

Slide 22

Slide 22 text

というわけで今日のお話は アンチパターンマイグレガイド

Slide 23

Slide 23 text

またの名を

Slide 24

Slide 24 text

本当にあった怖いコードの話

Slide 25

Slide 25 text

第壱話 独自プロトコル

Slide 26

Slide 26 text

public function confirm(Data $data) { /* * なんかごっつい処理 */ }

Slide 27

Slide 27 text

public function confirm(Data $data) { var_dump($data); /* * なんかごっつい処理 */ }

Slide 28

Slide 28 text

public function confirm(Data $data) { var_dump($data); /* * array(3) * { * [0]=> string(9) "111|201|1" * [1]=> string(9) "112|201|3" * [2]=> string(9) "100|011|1" * } */ /* * なんかごっつい処理 */ }

Slide 29

Slide 29 text

public function confirm(Data $data) { var_dump($data); /* * array(3) * { * [0]=> string(9) "111|201|1" * [1]=> string(9) "112|201|3" * [2]=> string(9) "100|011|1" * } */ /* * なんかごっつい処理 */ } 111|201|1 112|201|3 100|011|1

Slide 30

Slide 30 text

public function confirm(Data $data) { var_dump($data); /* * array(3) * { * [0]=> string(9) "111|201|1" * [1]=> string(9) "112|201|3" * [2]=> string(9) "100|011|1" * } */ /* * なんかごっつい処理 */ } 111|201|1 112|201|3 100|011|1 Q. どういう意味 でしょうか

Slide 31

Slide 31 text

A.

Slide 32

Slide 32 text

111|201|1 112|201|3 100|011|1 商品コード|枝番|注文数 A.

Slide 33

Slide 33 text

クラス作ろう class Data { /** * @var string */ public $productCode; /** * @var string */ public $branchNumber; /** * @var string */ public $orderNum; }

Slide 34

Slide 34 text

第弐話 利口な UI

Slide 35

Slide 35 text

金額計算はどうなってるか 確認してみよう

Slide 36

Slide 36 text

class HumbleController { public function orderConfirm(string $id){ $order = DB::table('orders')->where('id', $id)->first(); $response = $order; return view('order', compact('response')); } }

Slide 37

Slide 37 text

class HumbleController { public function orderConfirm(string $id){ $order = DB::table('orders')->where('id', $id)->first(); $response = $order; return view('order', compact('response')); } } 金額計算は いずこに?

Slide 38

Slide 38 text

注文確認画面 unit_price * $response->num) * 1.08) - $response->discount); ?>

注文確認

注文番号 {{$response->id}} の合計金額は {{$price}} 円です

Slide 39

Slide 39 text

注文履歴確認画面 unit_price * $response->num) * 1.08) - $response->discount); ?>

注文履歴

注文番号 {{$response->id}} の合計金額は {{$price}} 円です

Slide 40

Slide 40 text

注文履歴 確認画面 注文 確認画面

Slide 41

Slide 41 text

注文履歴 確認画面 注文 確認画面 同じコードがコピペ

Slide 42

Slide 42 text

注文 確認画面 注文金額計算 注文履歴 確認画面 注文金額計算 注文履歴 一覧画面 注文金額計算 注文情報 サーバー

Slide 43

Slide 43 text

注文情報 注文金額計算 サーバー 注文 確認画面 注文金額計算 注文履歴 確認画面 注文金額計算 注文履歴 一覧画面 注文金額計算

Slide 44

Slide 44 text

注文情報 注文金額計算 サーバー 注文 確認画面 注文履歴 確認画面 注文履歴 一覧画面

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

フロントくん
    @foreach ($response->data as $order)
  • Name: {{$order->productName}} Status: @switch($order->status) @case('yellow') 入金待ち @break @case('green') 設定中 @break @case('blue') 稼働中 @break @case('red') エラー @break @endswitch
  • @endforeach

Slide 51

Slide 51 text

    @foreach ($response->data as $order)
  • Name: {{$order->productName}} Status: @switch($order->status) @case('yellow') 入金待ち @break @case('green') 設定中 @break @case('blue') 稼働中 @break @case('red') エラー @break @endswitch
  • @endforeach
フロントくん サーバーから 受け取ったデータが 色に・・・?

Slide 52

Slide 52 text

class MeddleController extends BaseController { public function orderList(string $userId) { $orders = DB::table('orders')->where('owner_id', $userId)->get()->toArray(); $response = new ProductOrderResponse(); $response->data = array_map(function($order) { $data = new ProductOrderData(); $data->productName = $order->productName; switch ($order->status){ case '1' : $data->status = 'yellow'; break; case '2' : $data->status = 'green'; break; case '3' : $data->status = 'blue'; break; case '-1' : $data->status = 'red'; break; default: $data->status = 'gray'; break; } $data->status = $order->status; return $data; }, $orders); return view('meddle.orders', compact('response')); } }

Slide 53

Slide 53 text

class MeddleController extends BaseController { public function orderList(string $userId) { $orders = DB::table('orders')->where('owner_id', $userId)->get()->toArray(); $response = new ProductOrderResponse(); $response->data = array_map(function($order) { $data = new ProductOrderData(); $data->productName = $order->productName; switch ($order->status){ case '1' : $data->status = 'yellow'; break; case '2' : $data->status = 'green'; break; case '3' : $data->status = 'blue'; break; case '-1' : $data->status = 'red'; break; default: $data->status = 'gray'; break; } $data->status = $order->status; return $data; }, $orders); return view('meddle.orders', compact('response')); } }

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

フロントエンドの変更のために

Slide 56

Slide 56 text

フロントエンドの変更のために バックエンドの変更が必要

Slide 57

Slide 57 text

どうする?

Slide 58

Slide 58 text

フロントくん

Slide 59

Slide 59 text

フロントくん バックエンドもやってもらって どうせならインフラもやってもらって フルスタックくん にレベルアップさせよう

Slide 60

Slide 60 text

さもなければ

Slide 61

Slide 61 text

class MeddleController extends BaseController { public function orderList(string $userId) { $orders = DB::table('orders')->where('owner_id', $userId)->get()->toArray(); $response = new ProductOrderResponse(); $response->data = array_map(function($order) { $data = new ProductOrderData(); $data->productName = $order->productName; switch ($order->status){ case '1' : $data->status = 'yellow'; break; case '2' : $data->status = 'green'; break; case '3' : $data->status = 'blue'; break; case '-1' : $data->status = 'red'; break; default: $data->status = 'gray'; break; } return $data; }, $orders); return view('meddle.orders', compact('response')); } }

Slide 62

Slide 62 text

class MeddleController extends BaseController { public function orderList(string $userId) { $orders = DB::table('orders')->where('owner_id', $userId)->get()->toArray(); $response = new ProductOrderResponse(); $response->data = array_map(function($order) { $data = new ProductOrderData(); $data->productName = $order->productName; switch ($order->status){ case '1' : $data->status = 'wait'; break; case '2' : $data->status = 'setting'; break; case '3' : $data->status = 'running'; break; case '-1' : $data->status = 'error'; break; default: $data->status = 'undefined'; break; } return $data; }, $orders); return view('meddle.orders', compact('response')); } }

Slide 63

Slide 63 text

class MeddleController extends BaseController { public function orderList(string $userId) { $orders = DB::table('orders')->where('owner_id', $userId)->get()->toArray(); $response = new ProductOrderResponse(); $response->data = array_map(function($order) { $data = new ProductOrderData(); $data->productName = $order->productName; switch ($order->status){ case '1' : $data->status = 'wait'; break; case '2' : $data->status = 'setting'; break; case '3' : $data->status = 'running'; break; case '-1' : $data->status = 'error'; break; default: $data->status = 'undefined'; break; } return $data; }, $orders); return view('meddle.orders', compact('response')); } } フロントエンドの都合は バックエンドに書かないように するのがおすすめ

Slide 64

Slide 64 text

第四話 地獄のエラーハンドリング

Slide 65

Slide 65 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 66

Slide 66 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); } class User { public $id; public $name; public $dbError; public $error; public function loadByName(string $name){ $this->error = false; try{ $user = DB::table('users')->where('name', $name)->first(); if($user !== null){ $this->id = $user->id; $this->name = $user->name; return true; }else{ return false; } }catch (¥Exception $e){ $this->dbError = $e; $this->error = true; return false; }

Slide 67

Slide 67 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 68

Slide 68 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 69

Slide 69 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 70

Slide 70 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); } class User { public $id; public $name; public $dbError; public $error; public function add() { $this->error = false; try { DB::table('users')->insert( [ 'id' => $this->id, 'name' => $this->name ] ); return true; } catch (¥Exception $e) { $this->error = true; $this->dbError = $e; return false; } } }

Slide 71

Slide 71 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 72

Slide 72 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 73

Slide 73 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 74

Slide 74 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 75

Slide 75 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 76

Slide 76 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 77

Slide 77 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 78

Slide 78 text

public function create( Request $request, UserRepositoryInterface $userRepository ) { $name = $request->input('name'); $duplicated = $userRepository->findByName($name); if($duplicated !== null) { $viewModel = UserCreateResponse::fail(); return view('user.create', compact('viewModel')); } $userId = uniqid(); $user = new User($userId, $name); $userRepository->save($user); $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 79

Slide 79 text

public function create( Request $request, UserRepositoryInterface $userRepository ) { $name = $request->input('name'); $duplicated = $userRepository->findByName($name); if($duplicated !== null) { $viewModel = UserCreateResponse::fail(); return view('user.create', compact('viewModel')); } $userId = uniqid(); $user = new User($userId, $name); $userRepository->save($user); $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); } データの永続化を 担うオブジェクト を DI

Slide 80

Slide 80 text

public function create( Request $request, UserRepositoryInterface $userRepository ) { $name = $request->input('name'); $duplicated = $userRepository->findByName($name); if($duplicated !== null) { $viewModel = UserCreateResponse::fail(); return view('user.create', compact('viewModel')); } $userId = uniqid(); $user = new User($userId, $name); $userRepository->save($user); $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); } リポジトリに 再構築・永続化を 依頼する

Slide 81

Slide 81 text

DB のエラーは リポジトリで 例外投げて終わり (ここでは取り扱わない) public function create( Request $request, UserRepositoryInterface $userRepository ) { $name = $request->input('name'); $duplicated = $userRepository->findByName($name); if($duplicated !== null) { $viewModel = UserCreateResponse::fail(); return view('user.create', compact('viewModel')); } $userId = uniqid(); $user = new User($userId, $name); $userRepository->save($user); $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 82

Slide 82 text

最終話 ソースコードが仕様書だよ

Slide 83

Slide 83 text

人は言う

Slide 84

Slide 84 text

コード読めばわかるじゃん

Slide 85

Slide 85 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 86

Slide 86 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 87

Slide 87 text

public function create(Request $request) { $name = $request->input('name'); $user = new User(); $result = $user->loadByName($name); if ($user->error) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } // ユーザ名重複 if ($result) { $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $user->id = uniqid(); $user->name = $name; $result = $user->add(); if (!$result) { Logger::Log('error occurred. error:' . $user->dbError); $viewModel = new UserCreateResponse('', ''); return view('user.create', compact('viewModel')); } $viewModel = new UserCreateResponse($user->id, $user->name); return view('user.create', compact('viewModel')); }

Slide 88

Slide 88 text

なにがあったらうれしかったか

Slide 89

Slide 89 text

テスト

Slide 90

Slide 90 text

No content

Slide 91

Slide 91 text

データを投入

Slide 92

Slide 92 text

表示 データ 変更 データを投入

Slide 93

Slide 93 text

表示 データ 変更 データを投入 ソースコードは 仕様書

Slide 94

Slide 94 text

class UserService { private $userRepository; public function __construct(UserRepositoryInterface $userRepository) { $this->userRepository = $userRepository; } public function create(UserCreateRequest $request) { $userId = new UserId(uniqid()); $createdUser = new User($userId, $request->getName()); $this->userRepository->save($createdUser); return new UserCreateResponse($userId->getValue()); } }

Slide 95

Slide 95 text

class UserService { private $userRepository; public function __construct(UserRepositoryInterface $userRepository) { $this->userRepository = $userRepository; } public function create(UserCreateRequest $request) { $userId = new UserId(uniqid()); $createdUser = new User($userId, $request->getName()); $this->userRepository->save($createdUser); return new UserCreateResponse($userId->getValue()); } } class UserController extends BaseController { public function create(UserService $service, Request $request) { $name = $request->input('name'); $request = new UserCreateRequest($name); $response = $service->create($request); $viewModel = new UserCreateViewModel($response->getCreatedUserId(), $name); return view('user.create', compact('viewModel')); } }

Slide 96

Slide 96 text

class UserService { private $userRepository; public function __construct(UserRepositoryInterface $userRepository) { $this->userRepository = $userRepository; } public function create(UserCreateRequest $request) { $userId = new UserId(uniqid()); $createdUser = new User($userId, $request->getName()); $this->userRepository->save($createdUser); return new UserCreateResponse($userId->getValue()); } } class UserRepository implements UserRepositoryInterface { public function findByName(string $name) { $target = DB::table('users')->find('name', $name)->first(); return new User($target->id, $target->name); } public function save(User $user) { DB::table('users')->insert( [ 'id' => $user->id, 'name' => $user->name ] ); } } 本番用

Slide 97

Slide 97 text

class UserService { private $userRepository; public function __construct(UserRepositoryInterface $userRepository) { $this->userRepository = $userRepository; } public function create(UserCreateRequest $request) { $userId = new UserId(uniqid()); $createdUser = new User($userId, $request->getName()); $this->userRepository->save($createdUser); return new UserCreateResponse($userId->getValue()); } } テスト用 class UserRepository implements UserRepositoryInterface { private $db = []; public function findByName(string $name) { $targets = array_filter($this->db, function ($e) use ($name) { return $e->name === $name; }); if (count($targets) > 0) { $target = array_shift($targets); return $this->cloneUser($target); } else { return null; } } public function save(User $user) { $cloned = $this->cloneUser($user); $this->db[$cloned->id] = $cloned; } private function cloneUser(User $user) { return new User($user->id, $user->name); } }

Slide 98

Slide 98 text

class UserCreateTest extends TestCase { /** * テスト:正常にユーザを生成する * * @return void */ public function testValidCreate() { $repository = new InMemoryUserRepository(); $interactor = new UserService($repository); $request = new UserCreateRequest('test-name'); $response = $interactor->create($request); $this->assertNotNull($response); $this->assertNotNull($response->getCreatedUserId()); $userId = new UserId($response->getCreatedUserId()); $saved = $repository->find($userId); $this->assertEquals($saved->getName(), 'test-name'); } /** * テスト:重複エラー * * @return void */ public function testErrorXxx(){

Slide 99

Slide 99 text

class UserCreateTest extends TestCase { /** * テスト:正常にユーザを生成する * * @return void */ public function testValidCreate() { $repository = new InMemoryUserRepository(); $interactor = new UserService($repository); $request = new UserCreateRequest('test-name'); $response = $interactor->create($request); $this->assertNotNull($response); $this->assertNotNull($response->getCreatedUserId()); $userId = new UserId($response->getCreatedUserId()); $saved = $repository->find($userId); $this->assertEquals($saved->getName(), 'test-name'); } /** * テスト:重複エラー * * @return void */ public function testErrorXxx(){ IN を表現

Slide 100

Slide 100 text

class UserCreateTest extends TestCase { /** * テスト:正常にユーザを生成する * * @return void */ public function testValidCreate() { $repository = new InMemoryUserRepository(); $interactor = new UserService($repository); $request = new UserCreateRequest('test-name'); $response = $interactor->create($request); $this->assertNotNull($response); $this->assertNotNull($response->getCreatedUserId()); $userId = new UserId($response->getCreatedUserId()); $saved = $repository->find($userId); $this->assertEquals($saved->getName(), 'test-name'); } /** * テスト:重複エラー * * @return void */ public function testErrorXxx(){ IN を表現 OUT を表現

Slide 101

Slide 101 text

class UserCreateTest extends TestCase { /** * テスト:正常にユーザを生成する * * @return void */ public function testValidCreate() { $repository = new InMemoryUserRepository(); $interactor = new UserService($repository); $request = new UserCreateRequest('test-name'); $response = $interactor->create($request); $this->assertNotNull($response); $this->assertNotNull($response->getCreatedUserId()); $userId = new UserId($response->getCreatedUserId()); $saved = $repository->find($userId); $this->assertEquals($saved->getName(), 'test-name'); } /** * テスト:重複エラー * * @return void */ public function testErrorXxx(){ IN を表現 OUT を表現 これこそ仕様書

Slide 102

Slide 102 text

最終話 ソースコードが仕様書だよ 第四話 地獄のエラーハンドリング 第参話 知りすぎたコントローラ 第壱話 独自プロトコル 第弐話 利口な UI

Slide 103

Slide 103 text

エンドロール

Slide 104

Slide 104 text

No content

Slide 105

Slide 105 text

No content

Slide 106

Slide 106 text

No content

Slide 107

Slide 107 text

No content

Slide 108

Slide 108 text

SWIMMING IN HELL

Slide 109

Slide 109 text

Auther Masanobu Naruse Company GMO Internet, Inc. SWIMMING IN HELL