PIXIV SPRING BOOT CAMP 2022での技術基盤(Webフレームワーク)コースに参加しました。 この資料は8日間のインターンを終えて最終発表で用いた資料です! ※公開許可取得済
百科事典の責務分割PIXIV SPRING BOOT CAMP 2022 技術基盤(Webフレームワーク)pixiv Inc.usuyuki2022.3.17
View Slide
2自己紹介● アイコンの背景色とpixivのカラーが似ている● 鳥取県米子市生、島根県浜田市育ち● コーヒーが好き● しぐれうい先生を推しています(イラストレーターとしても、VTuberとしても)● なんちゃってPHPer○ Laravelをよく使います● 心ばかりの○ 自然言語処理○ インフラ環境構築○ JSやPythonなどusuyuki宇都宮大学
3ピクシブ百科事典の改善メンターのtadsanインターンのusuyukiusuyukiの力上昇メンターのtadsan
‘ピクシブ百科事典はアニメやマンガ、ゲームからデザイン・アートまであらゆる言葉・現象・文化・作品を解説するみんなでつくる百科事典です。’4ピクシブ百科事典記事数42万※日本語版月間PV1億※日本語版
2009年来からのPHP製独自フレームワーク5ピクシブ百科事典
68日間で行ったこと大きく分けると2つ
78日間で行ったこと※イメージPHPフレームワークアプリケーション
88日間で行ったこと※イメージPHPフレームワークアプリケーションルーティングをmiddlewareへ
98日間で行ったこと※イメージPHPフレームワークアプリケーション/mypageのADR化
10フレームワークのお話※イメージPHPフレームワークアプリケーション
11やったことルーティングをmiddlewareへ
12全体の流れページの閲覧index.php種々のミドルウェアDispatcherControllerまたはActionModeltplファイル● 田代砲やNGワードを弾く● HTTPSへのリダイレクト● セッションの初期化
13全体の流れページの閲覧index.php種々のミドルウェアDispatcherControllerまたはActionModeltplファイルURLを元に対応するクラスやメソッドを引っ張り出す
14全体の流れページの閲覧index.php種々のミドルウェアDispatcherControllerまたはActionModeltplファイル実際の処理(記事の登録や呼び出し )
15全体の流れページの閲覧index.php種々のミドルウェアDispatcherControllerまたはActionModeltplファイル
16何が嬉しいの?外部依存削減&責務分割
17外部依存削減外部依存削減
18外部依存削減その前に
19PSRPSR
20PSRPHPStandardRecommendationdPSR
21PSRピクシブ百科事典はPSR準拠に
22PSR-7 HTTP Message Interfaceリクエストやレスポンスのインターフェイスなどが定義されている!
23PSR-7 HTTP Message Interfaceそしてイミュータブル(不変)!
//どこかのファイル$_POST[‘title’] = ”任意の値”;PHPのスーパーグローバル変数24//どこかのファイル$title = $_POST[‘title’];//何が来るか分からない...値の代入(任意の場所で任意の回数)値の取り出し(グローバル変数)
$request = $request->withAttribute(RouteDispatchHandler::class, $new_handler);PSR-7準拠25public function handle(ServerRequestInterface $request){$request->getAttribute(RouteDispatchHandler::class, $new_handler);値の代入(1回限り)値の取り出し(引数より頂戴できる)
26こうすることで...これまでこれからsession_user()//関数内で$_SESSION['user']が呼ばれるpublic function hanlde(ServerRequestInterface $request){//中略$request->getAttribute(‘user’)
27外部依存削減外部依存削減
28責務分割責務分割
29Dispatcherこれまで● httpならリダイレクト、セッションの初期化、● urlから対応づくControllerやActionのクラスとメソッドを見つける● 問題のあるタイトルや意図しないものを弾く● 該当するクラスのメソッドを呼び出す● 該当するクラスのメソッドを呼び出すこれから
30PSR-15 HTTP Handlersmiddlewareやhandlerに関してのインターフェイス
class RoutingMiddleware implements MiddlewareInterface{インターフェイスを具象化したものを実装31class IndexAction implements RequestHandlerInterface{Mypage/IndexActionRoutingMiddleware
32PSR-15middlewaremiddlewareHTTPリクエスト HTTPレスポンス
33PSR-15middlewaremiddlewareHTTPリクエスト HTTPレスポンス
34責務分割middlewareへ切り出した
35従来https://dic.pixiv.net/a/%E3%81%97%E3%81%90%E3%82%8C%E3%81%86%E3%81%84dispatcher RouteConfigPCURLに対してどれを呼び出すかが列挙されている実際の処理(Controller,Action)を呼び出す!種々のmiddleware
36今回の実装https://dic.pixiv.net/a/%E3%81%97%E3%81%90%E3%82%8C%E3%81%86%E3%81%84dispatcherRouteConfigPCURLに対してどれを呼び出すかが列挙されているRoutingMiddleware実際の処理を呼び出すRouteDispatchHandler該当する処理を見つけ出し、RouteDispatchHandlerを$requestに包む実際の処理を準備する種々のmiddleware種々のmiddleware
//色々な処理...$new_handler = new RouteDispatchHandler($route, $controller,$this->response_factory, $this->stream_factory, $this->system_clock,$this->views_dir);$request = $request->withAttribute(RouteDispatchHandler::class, $new_handler);return $handler->handle($request);RoutingMiddleware37
//色々な処理...$handler = $request->getAttribute(RouteDispatchHandler::class);assert($handler instanceof RouteDispatchHandler);return $handler->handle($request);Dispatcher38
//色々な処理...$handler = $request->getAttribute(RouteDispatchHandler::class);assert($handler instanceof RouteDispatchHandler);return $handler->handle($request);Dispatcher39
Dispatcherの責務を減らす40237行80行
41PSRmiddlewareHTTPリクエスト HTTPレスポンスPSR-7ServerRequestInterfacePSR-7ResponseInterfacePSR-15RequestHandlerInterfacePSR-15MiddlewareInterface
42テストが書ける● 途中に謎の要素を取り込まない!● 責務が分割されている単体で完結してるのでテストが書ける!
43アプリケーションのお話※イメージPHPフレームワークアプリケーション
44やったこと/mypageのADR(風味)化
45MVCModelViewControllerレスポンスリクエスト
46ADRDomainResponderActionレスポンスリクエストHTTPレスポンス作成メソッド1つのみ(今回はDomain風味)
if (!is_login()) {return $this->createRedirectResponse('/login', ['return_to' =>(string)$this->request->getUri()]);}$user = session_user();$this->set('user', $user);[$checklist, $checklist_count] =ChecklistModel::findByUserIDWithArticle($user->user_id, 0, 5);//続く...47旧:UserController mypageメソッド
public function handle(ServerRequestInterface $request): ResponseInterface{$user = $request->getAttribute('user');if ($user instanceof NotLoggedIn) {return $this->responder->redirectForLogin((string)$request->getUri());}//中略return $this->responder->emitHtml($checklist, $created_articles, $activity,$access, $related_articles);新:Mypage/IndexAction handleメソッド48
public function emitHtml(array $checklist, array $created_articles, array$activity, array $access, array $related_articles): ResponseInterface{$html = $this->html_factory->render($this->views_dir . '/user/mypage', ['checklist' => $checklist,//略]);return $this->response_factory->createResponse(200)->withBody($this->stream_factory->createStream($html));}新:Mypage/IndexResponder49
50DIMypage/IndexActionでResponderをDI!返し方をActionは知らなくて良い※抽象に依存という点では厳密には不十分
/** @var IndexResponder */private $responder;public function __construct(IndexResponder $responder){$this->responder = $responder;}Mypage/IndexAction のコンストラクタ51
public function emitHtml(array $checklist, array $created_articles, array$activity, array $access, array $related_articles): ResponseInterface{$html = $this->html_factory->render($this->views_dir . '/user/mypage', ['checklist' => $checklist,//略]);return $this->response_factory->createResponse(200)->withBody($this->stream_factory->createStream($html));}新:Mypage/IndexResponder52
public function handle(ServerRequestInterface $request): ResponseInterface{$user = $request->getAttribute('user');if ($user instanceof NotLoggedIn) {return $this->responder->redirectForLogin((string)$request->getUri());}//中略return $this->responder->emitHtml($checklist, $created_articles, $activity,$access, $related_articles);Mypage/IndexAction handleメソッド53
54まとめ● ルーティング周りのmiddleware移行(PSR準拠)● /mypageのADR(風味)化● これらのテストを作成
55書ききれなかったけど学んだこと……● PHPStanでの静的解析● PHPDocの威力○ ジェネリックス● テストの疎結合● staticMock● autowire● git周りの知見● PSRの仕様に関して● 名前空間● オートロード● PHPの関数呼び出し順による最適化● クリーンとイージーに関して● interface,trait,abstract● 安定度抽象度等価原則に関して● デプロイ環境に関してなどなど...
56まとめこの春 ピクシブで 圧倒的猛者になりました。
57謝辞tadsanさん、kamikoさんpixiv事業本部webエンジニアリングチームの皆様、障害対応してくださった皆様、インターンの手筈整えてくださった皆様、充実した8日間をありがとうございました。
58ピクシブ百科事典の改善メンターのtadsanインターンのusuyukiusuyukiの力上昇全体を通して
59ピクシブ百科事典の改善メンターのtadsanインターンのusuyukiusuyukiの力上昇全体を通して
60おわりご清聴ありがとうございました!