Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

真っ当な技術を使ったふつうのWebサービス開発

1,006 views

Published on

ログミーTech Live #2「レガシーシステムのリニューアル」公園資料

Published in: Software

真っ当な技術を使ったふつうのWebサービス開発

  1. 1. 真っ当な技術を使ったふつうの Webサービス開発 ログミー株式会社 / 野崎翔太 1 / 26
  2. 2. 野崎翔太 / @emonkak Vimmer / Haskeller ログミー唯一のエンジニア OSS Feedpon - LDRライクなフィードリーダー emonkak/php-di - 高速なDIフレームワーク emonkak/php-orm - object-mapperスタイルの軽量ORM emonkak/php-enumerable - LINQ to ObjectsのPHP移植 自己紹介 2 / 26
  3. 3. 世界をログする書き起こしメディア ログミー:IT、スタートアップ関係のイベントの書き起こし ログミーTech:エンジニア勉強会の書き起こし ログミーファイナンス:決算説明会の書き起こし ログミーについて 3 / 26
  4. 4. WordPressで独自にテーマ、プラグインを開発して運用 開発・運用・デザインは社外に依頼 現在はログミーファインスについてのみこの旧システムで動作 リニューアル以前のシステム 4 / 26
  5. 5. 極度にグローバル変数に依存した設計 テンプレート主体の設計でView以外のロジックを書くべき場所がない とにかく遅い、キャッシュが必須 平均レスポンスタイムが約2000msだったことも(今は約400msまでは 改善) WordPressのつらみ 5 / 26
  6. 6. 開発者主導で仕様はほぼなし WordPressから必要な機能だけを抽出してLaravelで再実装 技術的な課題の解決を優先、ビジネスサイドの要望は後回し しかし新ためてヒアリングしてみると、同じシステムを再発明する意義 は薄かった 一度目のリニューアル 6 / 26
  7. 7. 開発の内製化 ドメイン駆動設計の導入 ユビキタス言語定義してそこからドメインモデルを構築 開発体制の変更 7 / 26
  8. 8. 基本的にシステム上での業務に関しては記事を作成して公開するという 単純なもの しかしログミーには独自の概念「シリーズ」があった 「シリーズ」は日本語で言う「連載」という続きもの記事の集合、とい うのは正確ではなかった 「シリーズ」は親子関係を持つことができる 親子関係は多いものでも3代まで 3代というのが理解の鍵に ドメインモデルの構築 8 / 26
  9. 9. 三代のそれぞれの「シリーズ」は役割が違っていた 異なる概念を同じ「シリーズ」という言葉でまとめて親子関係にしてい た 親シリーズ:イベントの主催者(コミュニティ) 子シリーズ:コニュニティによって開催されたイベント(イベント) 孫シリーズ:イベントで行なわれたセッションを記録した記事の集 合(ログ) ドメイン知識の蒸留 9 / 26
  10. 10. リニューアルするサービスは売り上げが立っている 売り上げが立っているサービスは継続可能性が高い 長期間の保守に耐えられる設計が必要 一方、売れるかわからない新規のサービスはスピードが重要 リニューアルのための技術設計 10 / 26
  11. 11. 真っ当な技術・実装を選択する 標準化・規格化された技術 デファクトスタンダートの技術 捨てられる実装 真っ当な技術≠枯れた技術 有用な枯れた技術はあまりない 保守性を担保するための技術選択 11 / 26
  12. 12. バックエンドの構成 12 / 26
  13. 13. 構成技術 PHP(FastCGI) nginx MySQL memcached crond モノリシックシステム 今後はレコメンド処理をマイクロサービス化を予定 バックエンドの構成 13 / 26
  14. 14. PHP-FIG(PHP Framework Interop Group)という組織が出している PSR(PHP Standard Recommendation)という標準勧告がある Javaで言う所のJSR(Java Specification Request) PSRはPHPコミュニティでかなりの影響力がある HTTPサーバーのインターフェイスを定義したPSR-15(HTTP Server Request Handlers)がある PHPにおける標準化 14 / 26
  15. 15. interface RequestHandlerInterface { public function handle( ServerRequestInterface $request ): ResponseInterface; } interface MiddlewareInterface { public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ): ResponseInterface; } PSR-15のインターフェイス 15 / 26
  16. 16. Webフレームワークは使わずにPSR-15に準拠した形でアプリを実装 フルスタックのWebフレームワークは便利だが最新版に追従するのが 大変 ルーティングはTrie木を利用した独自の仕組みをPSR-15のミドルウェ アとして実装 emonkak/routerを利用 パスを/区切リにして木を構築してキャッシュ それに対してマッチングをかけることで高速なルーティングを実現 PSR-11(Container interface)のDIコンテナのインターフェイスも利用 実装としては依存グラフを丸ごとキャッシュすることでが高速なイ ンスタンス化ができるemonkak/diを利用 Frameworkless PHP 16 / 26
  17. 17. JavaのPersistence API(JPA)のような永続化に関するPSRはない Object-MapperスタイルのシンプルなORM emonkak/orm を独自開 発 Entityはプレーンなオブジェクトとして定義可能 このORMに依存するのはRepositoryの実装のみ 永続化とORM 17 / 26
  18. 18. public function articleOfId(ArticleId $articleId): ?Article { return $this->grammer ->getSelect() ->with(Relations::oneToOne( 'eye_catch', 'images', 'eye_catch_id', 'image_id', $this->pdo, new ObjectFetcher(Image::class), $this->grammer->getSelect() )) ->from('articles') ->where('articles.article_id', '=', $articleId->getId()) ->getResult($this->pdo, new ObjectFetcher(Article::class)) ->firstOrDefault(); } Repositoryの実装 18 / 26
  19. 19. ユーザーにはドメインモデルで表現される形とは違う見せ方をしたい場 合がある CQRS(Command Query Responsibility Segregation)の考え方を活 用してコマンドモデルとクエリモデルに分ける データの更新を対応するコマンドモデルはドメイン知識を反映したドメ インモデル データの読取を対応するクエリモデルをプレゼンテーション用のモデル として新たに実装 実装としてはアプリケーション層に FooData、FooQueryService と いう名称で作成 これはドメイン層における Entity と Repository の関係と一緒 CQRSの活用 19 / 26
  20. 20. フロントエンドの構成 20 / 26
  21. 21. ビルドツール Webpack Babel TypeScript MPA(Multi Page Application) フロントエンドの構成 21 / 26
  22. 22. jQueryの時代はこんなコードを各所に書いていました $('#js-button').on('click', function() { ... }); コンポーネント単位での再利用が難しい 要素とJSのコードが離れてしまっていて管理が難しい Reactなら ReactDOM.render() をどこに書くべきかとう問題が生じ る JSのブートストラップをどこでやる か問題 22 / 26
  23. 23. Web Componentsはカスタム要素(タグ)を作るためのAPI群 モダンブラウザはネイティブサポート IE11はPolyfill必須 Custom Elementのみ使用 Shadow DOMは使わない HTMLElementを継承したComponent実装のための基底クラス StatefulComponentを作成 ReactライクコンポーネントAPI テンプレートの描画にはlit-htmlを利用 コンポーネント間のメッセージングにはCustomEventを活用 全部で400行程度のコンパクトな実装 WebComponents + lit-html 23 / 26
  24. 24. インフラ構成 24 / 26
  25. 25. Pull RDS(MySQL) ECS Service(Fargate) S3 Cloudflare Application Load balancer App Container (PHP-FPM) ElastiCache (Memcached) Proxy Container (nginx) Scheduler Container (PHP+crond) CodePipeline Push GitHub CodeBuild Deploy Lambda ECR インフラ構成 25 / 26
  26. 26. リニューアルするサービスは継続可能性が高いので保守性を重視して開 発 サーバーサイドはPSRの標準化技術を使って、フルスタックのフレーム ワークの利用を避けた フロントエンドはブラウザの組込みの機能であるWebComponentsと lit-htmlを使ってコンポーネントを実装 インフラはコンテナ技術とデプロイの自動化をすることで運用コストを 削減 長文を掲載するメディアなので読み易くなるようなUIデザイン まとめ 26 / 26

×