Upgrade to Pro — share decks privately, control downloads, hide ads and more …

TechPlay22_06_28_Full TypeScriptで新規プロダクトを立ち上げた際に実践した設計と反省

kakehashi
June 30, 2022
900

TechPlay22_06_28_Full TypeScriptで新規プロダクトを立ち上げた際に実践した設計と反省

kakehashi

June 30, 2022
Tweet

More Decks by kakehashi

Transcript

  1. Full TypeScriptで新規プロダクトを
    立ち上げた際に実践した設計と反省
    株式会社カケハシ 小室 雅春

    View Slide

  2. 小室雅春 (コムロ マサハル)
    ● WEBソフトウェアエンジニア
    ● 経歴
    ○ 某新聞社(2016 ~ 2022/05)
    ○ 株式会社カケハシ(2021/06~)
    ● TypeScript, SPA, Express, AWS CDK
    ● 患者さんの服薬をサポートする新規プロダクトの立
    上げを担当
    自己紹介
    @_hedrall
    hedrall
    https://blog.hedrall.work

    View Slide

  3. 1. 背景
    2. 技術選定と設計
    ● 言語
    ● レポ管理
    ● アーキテクチャー
    ● フロントエンド
    ● バックエンド
    ● テスト
    3. まとめ
    アジェンダ

    View Slide

  4. カケハシとは?
    https://www.kakehashi.life/

    View Slide

  5. ● 21年6月入社した当時、新規プロダクトの立上げの話があった
    ○ => 患者さんの服薬を薬局がサポートするための業務システム
    ● 明確なDeadLineはないが、概ね3, 4ヶ月くらいでMVP版をリリースした

    ○ その後、正式リリース => スケールしていく前提
    ● リソースは、私 + 兼業メンバー2, 3名のサポート
    新規プロダクト開発の背景
    スピーディにプロダクトを立ち上げて、
    PMFに向けたサイクルを回したい!

    View Slide

  6. ● 薬局がWindows Desc/Tabで利用するJamstackな業務WEBアプリ
    ○ SPAアプリ (SSR不要)
    ● 患者の個人情報が含まれる
    ○ (クライアント証明書による制限が必要)
    ● 薬局が患者をサポートした履歴など、書き込みが必要
    ● (ログインセッションは既存の別システムと共有化する(SSO))
    ● 将来的に実装されうる機能が特定しきれていない
    ○ 既存にない業務、今までになかったプロダクト
    構築するシステムの特性

    View Slide

  7. ● 開発速度
    ○ 軽量な技術スタックでTryErrorのサイクルを短縮
    ○ 効果の高いツールは、新興ツールでも利用する
    ■ 捨てられる事が前提
    ● シンプルさ
    ○ 兼業のメンバーや、今後加わるメンバーが理解しやすい
    ● 属人化しない
    ○ 一般的な技術 or 可換な技術 or 使いやすい技術
    ○ 整理されつつ、複雑化しないアーキテクチャー
    技術選定・設計方針

    View Slide

  8. 2. 技術選定・設計

    View Slide

  9. ● WEBフロントエンドを開発する以上必ず使う
    ● 全部TypeScriptで無理なく開発可能
    ○ AWS CDK (2019 ~) により、IaC もTypeScriptで簡単に
    ● 立ち上がり期、フルスタックなメンバーの多い環境
    ○ (周辺エコシステムを含む) コンテキストスイッチの最小化
    ■ 他の言語を導入する場合はコストを考慮する必要がある
    ● (バックエンドに重い集計などはない)
    ● TSの良さ
    ○ 型によるドキュメンテーション効果の向上
    ■ 構造的部分型による人に優しい型 (情報量・可読性)
    2.1 言語 => Full TypeScript!!

    View Slide

  10. ● 最近のエディターは複数のtsconfig.jsonに対応
    ● フロント・バックが一体のシステム
    ● 一部コードを共有したい
    ○ Domain Model, DTO, コアロジック, 共通関数
    ○ FullTS環境では大きな利点
    ● cons
    ○ コード共有は循環参照に気をつける
    ○ precommit hook, eslintの設定などは工夫する
    2.2 レポジトリ管理 => モノレポ
    Github Repository
    frontend
    backend
    infra
    package.json
    tsconfig.json
    ・・・
    package.json
    tsconfig.json
    common

    View Slide

  11. ● クリーンアーキテクチャー(CA)、DDDの手法を漸進的に導入する
    ● CA
    ○ ロジックの置き場を整理
    ○ コンポーネントを差し替えできるようにしておく
    ■ β版からプロダクトのスケールの準備
    ● DDD
    ○ ドメインモデルを整備する
    ■ ビジネス要件をコードに反映しやすくする
    ■ ドキュメンテーションとしての価値
    ● 週2回 (+ 都度)、PdMと要件を整理
    2.3 アーキテクチャー

    View Slide

  12. 実装にあたって参考にする物
    出典: https://github.com/esakik/clean-architecture-python
    Clean Architecture 図22-2 典型的な例

    View Slide

  13. バックエンド(API) フロントエンド(SPA)
    Controller
    UseCase
    Repository
    DB
    MySQL
    HTTP Request

    View Slide

  14. バックエンド(API) フロントエンド(SPA)
    Controller
    UseCase
    Repository
    DB
    HTTP Request
    MySQL
    データモデルをどうするか?

    View Slide

  15. バックエンド(API) フロントエンド(SPA)
    Controller
    UseCase
    Repository
    DB
    MySQL
    HTTP Request
    Domain Model
    DAO
    DTO
    TypeORM
    (DynamoDBなら省略可能? )
    ドメインモデルの改修サイクルで
    APIに破壊的な変更が入る事があ

    変換
    変換

    View Slide

  16. Domain Model
    DAO
    TypeORM
    (DynamoDBなら省略可能? )
    ドメインモデルの改修サイクルで
    APIに破壊的な変更が入る事があ

    バックエンド(API) フロントエンド(SPA)
    Controller
    UseCase
    Repository
    DB
    MySQL
    HTTP Request
    リリース時の
    ダウンタイムを
    許容するか?
    変換
    変換
    DTO

    View Slide

  17. バックエンド(API) フロントエンド(SPA)
    Controller
    UseCase
    Repository
    DB
    MySQL
    変換
    UIComponent (View)
    Repository
    Hooks
    変換
    変換
    Domain Model
    DAO
    DTO
    API Request

    View Slide

  18. ● フレームワーク(Next.js, Angularなど)に依存したくない
    ○ 素早くプロダクトを立ち上げる為に身軽でいたい
    ○ たち上がりは早い?
    ■ 当初知識がなくても利用しやすいが、将来的な学習コストが高い
    ○ 不必要なツールに依存する
    ■ ビルドに時間がかかる
    ■ TryErrorサイクルに影響
    ■ 手を加えるのが大変
    ● 判断のポイント
    ○ toCかtoBかで非機能要件が大きく異なる
    ■ SSR(SEO)、パフォーマンス、負荷対策
    ● 大まかなトレンドは The State of JS などを参考
    2.4 フロントエンド 前提

    View Slide

  19. ● React
    ○ 内部が全てJS
    ○ TSによるドキュメンテーション効果が高い => 属人化しない
    ○ ビルド開発環境が選びやすい => DX改善がしやすい
    ● ビルド
    ○ esbuild <= Webpackの100倍早い !!
    ■ 軽量かつ可換
    ■ 話題のesbuildをさっくりと調査してみた
    ○ ローカルは、expressとbrowsersyncでホスト
    ■ Advent Calender: esbuild + React(TS) で実現する超軽量な開発環境
    ● パッケージ: pnpm <= npm よりも高速でエコ
    ● Inversify.js => DIコンテナ
    ○ APIクライアントをstabと差替し、standaloneで起動
    2.4 フロントエンド
    React

    View Slide

  20. ● 開発速度の向上!ドキュメント作成!
    ● とはいえ、活用方法は十人十色
    ● TSOAを採用
    ○ CodeFirstでOpenAPIスペックを生成
    ○ 更にOpenAPI-generatorでAPIクライアントを生成
    ● => 手間なく、フロントとバックの整合性を担保
    ● => ボイラープレート部分を自動生成
    詳細な活用方法 ▼
    Code Firstで疲弊しないOpenAPI活用方法
    2.5 OpenAPIの活用
    OpenAPI

    View Slide

  21. バックエンド
    コントローラを記述
    import express from 'express';
    import { Controller , Get, OperationId , Body, Request, Route,
    Security } from 'tsoa';
    @Route('user')
    export class UserController extends Controller {
    constructor (private service: IUserService) { super();}
    /**
    * ユーザ一覧取得
    */
    @Get('list')
    @Security(SECURITIES.COGNITO)
    @OperationId ('list-user' )
    public async get(
    @Request() request: express.Request,
    @Body() params: InputDto
    ): Promise {
    const res = await this .service.list(
    request. user, apiDtoConverter(params)
    );
    return apiDtoConverters.user.list.serviceToOutput (res);
    }
    }
    Controller
    後続の処理
    変換
    HTTP Request

    View Slide

  22. import express from 'express';
    import { Controller , Get, OperationId , Body, Request, Route,
    Security } from 'tsoa';
    @Route('user')
    export class UserController extends Controller {
    constructor (private service: IUserService) { super();}
    /**
    * ユーザ一覧取得
    */
    @Get('list')
    @Security(SECURITIES.COGNITO)
    @OperationId ('list-user' )
    public async get(
    @Request () request: express.Request,
    @Body() params: InputDto
    ): Promise {
    const res = await this .service.list(
    request. user, apiDtoConverter(params)
    );
    return apiDtoConverters.user.list.serviceToOutput (res);
    }
    }
    Controller
    後続の処理
    変換
    バックエンド
    コントローラを記述
    GET: /user/listへのリクエストを処理
    HTTP Request

    View Slide

  23. ● schemaでのvalidationなど
    ● Auth Middlewareの差し込み
    Controller
    後続の処理
    生成
    バックエンド
    OpenAPI Spec
     ボイラープレート
    生成
    HTTP Request

    View Slide

  24. Controller
    後続の処理
    バックエンド
    OpenAPI Spec
     ボイラープレート
    フロントエンド(SPA)
    Component (View)
    Repository
    Controller
    (Presenter)
    変換
    API Client
    生成
    生成
    生成
    ● schemaでのvalidationなど
    ● Auth Middlewareの差し込み
    型の効いた API Request !
    DB
    HTTP Request

    View Slide

  25. ● Testing Trophyを念頭に
    ● 静的解析を頼る
    ● Unitを減らして、Unitに縛られない
    ● 統合テストはDBをモックしない
    ○ https://github.com/testjavascript/nodejs-integration-tests-
    best-practices
    ● Github Actions で実行
    2.6 Testing
    出典: https://twitter.com/kentcdodds/status/960723172591992832?lang=zh-Hant

    View Slide

  26. ● Goods
    ○ 機能全体のテストができるので、安心感が
    ある
    ○ 障害が発生した場合に、修正以降の動作
    を保証できる
    ● Bads
    ○ テストデータの作成が大変
    ■ JSONで記述するSeeds
    ■ APIによるMutationを利用
    ○ テストケースが網羅できない場合がある
    ■ 細かな文言の違い
    ■ 局所的に複雑なロジック
    ■ => UnitTestで担保できないか?
    ● Jestの起動が遅い?
    ○ Jestのテストを高速実行する自作ツール 既
    存のJestで書かれたテストを爆速実行するツール、uvu-jest を作りました
    2.5 Testing
    出典: https://twitter.com/kentcdodds/status/960723172591992832?lang=zh-Hant

    View Slide

  27. ● 新規プロダクトの構築に際して、軽量な開発環境を工夫することで、順調
    に開発・リリースすることができた 🎉
    ● 現在もより多くの薬剤師にご活用頂けるように、より加速してプロダクトを
    成長中!
    ● 次プロダクトを立ち上げるときに事前によく検討するべき事項がわかった
    😆
    まとめ

    View Slide

  28. エンジニア採用中
    ● 医療分野にて社会的意義のある開発をしたい方
    ● アプリケーション構築に興味がある方
    ● フルスタックに開発をしたい方
    ● データの利活用に興味がある方
    まずはカジュアル面談をご利用下さい!
    採用ページ

    View Slide

  29. 以上です!
    ありがとうございましたmm
    採用ページ

    View Slide