Slide 1

Slide 1 text

1 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 徹底解剖! 医療業務システムのReactコンポーネント設計 2024/11/23 髙橋 佑太 / Yuta Takahashi JSConf JP 2024 スポンサーワークショップ

Slide 2

Slide 2 text

2 Copyright© Medley, Inc. ALL RIGHTS RESERVED. メドレーのミッション はじめに

Slide 3

Slide 3 text

3 Copyright© Medley, Inc. ALL RIGHTS RESERVED. メドレーの事業 はじめに

Slide 4

Slide 4 text

4 Copyright© Medley, Inc. ALL RIGHTS RESERVED. ⾃⼰紹介:髙橋 佑太 / Yuta Takahashi 2021年に現職に新卒⼊社 クラウド診療⽀援システムCLINICSの開発に従事 APIモックツールに依存しない軽量なStorybookを 布教している はじめに

Slide 5

Slide 5 text

5 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 本ワークショップのねらい はじめに ● ⼤規模‧複雑化するWebフロントエンドの開発において品質と保守性の維持 は重要な課題です。 ● ⾼い品質と保守性を実現するために実践しているReactコンポーネント設 計、開発プロセス、テスト戦略を紹介します。

Slide 6

Slide 6 text

6 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 1. クラウド診療⽀援システムCLINICSにおけるコンポーネント設計の重要性 2. コンポーネントの分割粒度 3. 複合コンポーネントのStorybook駆動開発 4. 複合コンポーネントの構造 5. 開発速度と品質を両⽴するためのテスト戦略 本ワークショップのテーマ 徹底解剖!医療業務システムのReactコンポーネント設計

Slide 7

Slide 7 text

7 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 1. クラウド診療⽀援システムCLINICSにおける コンポーネント設計の重要性 徹底解剖!医療業務システムのReactコンポーネント設計

Slide 8

Slide 8 text

8 Copyright© Medley, Inc. ALL RIGHTS RESERVED. クラウド診療⽀援システムCLINICSと開発体制 開発8年⽬の医科診療所向け業務アプリケーション ● 診療業務に必要なオンライン診療、予約、カルテ、問診などの機能を⼀気通貫で提供 ● 画⾯数が200以上のSingle Page Application ⾮職能別なエンジニアリング体制 ● 領域を分けず1つのIssueを1⼈が⼀気通貫で実装することが多い ● 得意‧不得意に関わらずフロントエンドを実装する機会がある 2.Storybook駆動開発を活⽤したフロントエンドリアーキテクト ※ 本資料では以降、クラウド診療⽀援システムCLINICSを 「CLINICS」と省略して表記します

Slide 9

Slide 9 text

9 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 1.クラウド診療⽀援システムCLINICSにおけるコンポーネント設計の重要性 CLINICSのWebフロントエンドを⽀える技術 Language TypeScript UI React / Radix UI State Management Tanstack Query / React Hook Form / Redux Styling Emotion Toolchain webpack / Vite (移行中 ) Routing React Router Form Validation Zod Testing Vitest / Storybook / Testing Library / jsdom / Storycap / reg-suit / MagicPod API Schema OpenAPI

Slide 10

Slide 10 text

10 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 1.クラウド診療⽀援システムCLINICSにおけるコンポーネント設計の重要性 CLINICSのWebフロントエンド事情 ● インタラクションが多めのSingle Page Application ● 診療業務は複数のリソースやタスクを元に構成されているため 複合的な画⾯設計が要求される ● 個々のリソースやタスクを表現するUIの中には、 効率的な診療体験を提供するために複雑な制御が求められる場合がある

Slide 11

Slide 11 text

11 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 1.クラウド診療⽀援システムCLINICSにおけるコンポーネント設計の重要性 様々なリソース‧タスクを複合的に扱う画⾯仕様 診察画⾯の例:円滑な診察業務を実現するため、 診察に必要なリソースやタスクを1画⾯で複合的に提供することが求められる

Slide 12

Slide 12 text

12 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 複雑な診療業務を⽀えるUI:電⼦処⽅箋の登録 1.クラウド診療⽀援システムCLINICSにおけるコンポーネント設計の重要性 16種類の表⽰状態を持つ電⼦処⽅箋登録ボタン

Slide 13

Slide 13 text

13 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 複雑な診療業務を⽀えるUI:電⼦処⽅箋の登録 1.クラウド診療⽀援システムCLINICSにおけるコンポーネント設計の重要性 登録ダイアログの実⾏結果に応じて 次に必要なタスクのダイアログを⾃動的に表⽰することで 滑らかな診療業務体験を提供 要投薬チェック 要電⼦署名 電⼦処⽅箋登録ダイアログ 投薬チェックダイアログ 電⼦署名ダイアログ

Slide 14

Slide 14 text

14 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 課題:複雑な画⾯仕様に対して 「当たり前品質」をどのように担保するか? 1.クラウド診療⽀援システムCLINICSにおけるコンポーネント設計の重要性

Slide 15

Slide 15 text

15 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 医療業務システムにおける「当たり前品質」の重要性 ● ソフトウェアにおける「当たり前品質」 ○ 仕様通りに機能すること ○ バグが少ないこと ○ セキュリティが確保されていること等 ● 前提として、どのようなソフトウェアも「当 たり前品質」は重要 ● 医療業務システムにおいては、たった⼀つの 不具合が重⼤な医療事故に繋がる恐れがあ るため「当たり前品質」は徹底しなければ ならない 1.クラウド診療⽀援システムCLINICSにおけるコンポーネント設計の重要性 満⾜ 不満⾜ 充⾜ 不充⾜ 当たり前品質 狩野モデル:顧客満⾜‧充⾜の軸で品質をマッピングした図[参考1] ⼀元的品質 魅⼒的品質

Slide 16

Slide 16 text

16 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 1.クラウド診療⽀援システムCLINICSにおけるコンポーネント設計の重要性 「当たり前品質」をコンポーネント設計で⽀える 当たり前品質 ⾃動テスト 保守性の⾼いUI Reactコンポーネント設計 当たり前品質を⽀えるReactコンポーネント設計 ⾃動テストを書きやすくするための基盤 当たり前品質を担保するための基盤 保守性の⾼いUIを築くための型 ※アプリケーションの性質などによって 最適な形は異なる 価値を届けるうえで最低限必要な品質

Slide 17

Slide 17 text

17 Copyright© Medley, Inc. ALL RIGHTS RESERVED. CLINICSにおけるコンポーネント設計の重要性 ● コンポーネント設計は保守性の⾼いUIを築くための型 ● 保守性の⾼いUIは⾃動テストの実装を容易にする ● 必要⼗分な⾃動テストを構築しながら開発を進めることで「当たり前品質」 を担保して顧客へ価値を提供することができる 1.クラウド診療⽀援システムCLINICSにおけるコンポーネント設計の重要性

Slide 18

Slide 18 text

18 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 2. コンポーネントの分割粒度 徹底解剖!医療業務システムのReactコンポーネント設計

Slide 19

Slide 19 text

19 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 2.コンポーネントの分割粒度 componentsディレクトリ配下を役割ごとに分類 # 分類 役割 具体例/備考 1 layouts ページ間を横断する共通レイアウト 例:グローバルヘッダ , 患者詳細画面のナビゲーション 2 pages ページパスと1対1で対応するページの実体 例:診察画面, 患者基本情報画面 ※複数のusecasesから構成される 3 usecases 単一のリソースやタスクの表現に特化した 複合コンポーネント 例:診察一覧, 診察完了ダイアログ 4 uiParts リソースやタスクに紐づかない汎用 UI 例:Button, Flex, Grid, Dialog, Input, RhfInput ※ Headlessライブラリのradix-uiを一部活用 5 utilities 見た目を伴わない汎用機能を提供するコンポーネント 例:Sortable, ImagePreview, WatchHookFormValue componentsディレクトリ直下の分割粒度:5つの役割ごとに分類

Slide 20

Slide 20 text

20 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 複合コンポーネントは関⼼事の単位で分類 2.コンポーネントの分割粒度 src/components/usecases ├── dashboard │ └── DashboardBarChart ├── invoice │ ├── InvoiceConfimationDialog │ └── InvoiceSubmissionForm └── patient ├── PatientOnlineStatusChip └── PatientProfileForm ├── PatientProfileForm.tsx ├── … (⼦コンポーネント, Storybook, テスト, etc) ├── index.ts └── usePatientProfileForm.ts 関⼼事の サブディレクトリ コンポーネント名は原則 {関⼼事}{状況}{ベースコンポーネント名} の形式で命名[参考2] コンポーネントごとの ディレクトリ コンポーネントごとの ディレクトリに コンポーネント内に 閉じる実装を すべて内包

Slide 21

Slide 21 text

21 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 複合コンポーネントファーストなコンポーネント分割 単⼀リソースの表現や特定タスクの実⾏を担当する複合コンポーネント単位で分割 複合コンポーネント単位で品質と保守性を担保することで、複雑かつ多様な医療ドメインに対応 2.コンポーネントの分割粒度 layout layout usecase A page usecase B usecase C usecase D 1画⾯のコンポーネント分割イメージ:usecase(複合コンポーネント)ごとに単⼀責務となるように分解し、 pageはusecaseを組み合わせて構築する usecase F usecase E usecase G

Slide 22

Slide 22 text

22 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 具体例:診察画⾯のコンポーネント分割 2.コンポーネントの分割粒度

Slide 23

Slide 23 text

23 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 具体例:診察画⾯のコンポーネント分割(⾚枠単位) 2.コンポーネントの分割粒度 複雑な表⽰ロジックや ダイアログを持っている コンポーネントを分割 個別に品質を担保しながら 開発する

Slide 24

Slide 24 text

24 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 具体例:主訴‧所⾒テンプレート 2.コンポーネントの分割粒度 主訴‧所⾒テンプレートコンポーネントの例:⼀⾒シンプルに⾒えるが、その中に5種類のダイアログが潜んでいる ダイアログ単位で1つの複合コンポーネントに分割して個別にコンポーネントテストを実装している

Slide 25

Slide 25 text

25 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 複合コンポーネントファーストで分割する理由 ● 画⾯内で表⽰する情報量が多いため、分割していかないと 1つのコンポーネントがあっという間に肥⼤化してしまう ● 機能の責務単位で複合コンポーネントに分割することで、 各機能の保守性(モジュール性、再利⽤性、解析性、修正性、試験性)[参考3] を向上することがねらい 2.コンポーネントの分割粒度

Slide 26

Slide 26 text

26 Copyright© Medley, Inc. ALL RIGHTS RESERVED. クイズ:どこが違うでしょうか? 2.コンポーネントの分割粒度 主訴‧所⾒テンプレート登録ダイアログ 主訴‧所⾒テンプレート編集ダイアログ

Slide 27

Slide 27 text

27 Copyright© Medley, Inc. ALL RIGHTS RESERVED. クイズ:どこが違うでしょうか? (回答) 2.コンポーネントの分割粒度 主訴‧所⾒テンプレート登録ダイアログ 主訴‧所⾒テンプレート編集ダイアログ UIだけでなく ネットワーク処理も 異なる どちらか⽚⽅だけ 存在する仕様 テキストが 異なる

Slide 28

Slide 28 text

28 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 落とし⽳:作成画⾯と編集画⾯の共通化 ● ⾒た⽬がなんとなく似ているからといって実装を共通化すると 内部で様々な分岐が発⽣してしまう ● 先の例の場合、ダイアログレベルでは作成と編集で要件が異なるため別々の 複合コンポーネントとして定義すると保守性が向上する ● 両者が持つフォームコンポーネントは仕様レベルで同じなため 共通化している 2.コンポーネントの分割粒度

Slide 29

Slide 29 text

29 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 議論:レイヤー単位分割 vs 機能単位分割 src/features ├── comments │ ├── api │ ├── components │ ├── hooks │ ├── routes │ └── utils └── users └── … 2.コンポーネントの分割粒度 機能単位分割 src ├── components │ ├── layouts │ ├── pages │ ├── uiParts │ ├── usecases │ │ └── comments │ └── utilities └── routes レイヤー単位分割

Slide 30

Slide 30 text

30 Copyright© Medley, Inc. ALL RIGHTS RESERVED. レイヤー分割の採⽤理由:マルチスタックな開発⽂化 メドレーの開発⽂化 ● 得意な技術領域をベースとしつつも、チームでの開発効率を⾼めるために領域を越えて開発 ● メンバーによってフロントエンドを実装する頻度は異なる レイヤー分割のねらい ● コードレビューの負荷軽減:コードの分割粒度の統制が効きやすく実装のブレを減らすことが容易 ● 悩みの少ない開発:どこに何を書けば良いか明確になり、新規実装時の悩みを減らすことができる ● 隣のコードがお⼿本:ディレクトリ上で近い実装を参考にすることができる 2.コンポーネントの分割粒度

Slide 31

Slide 31 text

31 Copyright© Medley, Inc. ALL RIGHTS RESERVED. まとめ:コンポーネントの分割粒度 ● CLINICSではレイヤー単位でディレクトリを分類 ● 機能に特化した複合コンポーネント(usecases)に関しては 内部で機能単位に分類する折衷案を採⽤している ● 複合コンポーネントは機能の責務ごとに積極的に分割することで、 各々の保守性を⾼めて肥⼤化を抑⽌している 2.コンポーネントの分割粒度

Slide 32

Slide 32 text

32 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 3. 複合コンポーネントのStorybook駆動開発 徹底解剖!医療業務システムのReactコンポーネント設計

Slide 33

Slide 33 text

33 Copyright© Medley, Inc. ALL RIGHTS RESERVED. Storybookとは ● UIコンポーネントとページを分離して構築するためのフロントエンドワークショップ [参考4] ● アプリ全体を実⾏する必要なく、到達しにくいステートやエッジケースを開発できる ● 様々な⼿法のテストをサポート(インタラクション, ビジュアルリグレッション, アクセシビリティ等) 3.複合コンポーネントのStorybook駆動開発 引⽤:https://storybook.js.org/

Slide 34

Slide 34 text

34 Copyright© Medley, Inc. ALL RIGHTS RESERVED. Play Function:インタラクションを⾃動化する 3.複合コンポーネントのStorybook駆動開発

Slide 35

Slide 35 text

35 Copyright© Medley, Inc. ALL RIGHTS RESERVED. Portable Stories:Storyの実⾏結果をテストする ● StoryをJest, Vitest, Playwright CTなどの テストツールで利⽤できるユーティリティ [参考 5,6,7,8] ● インタラクションとアサーションを 実⾏レベルで分離できる ● Storybook上で確認したテストケースに対してア サーションを書くだけで簡単にテストを実装で きる 3.複合コンポーネントのStorybook駆動開発

Slide 36

Slide 36 text

36 Copyright© Medley, Inc. ALL RIGHTS RESERVED. Storybook駆動開発 3.複合コンポーネントのStorybook駆動開発 󰞵 Storybook上で作り込み ✅ コンポーネントテスト 🚀 アプリケーションへ統合 ● Storybook駆動開発[参考9]は堅牢な開発とテストをサポートしてくれる強⼒な開発⼿法 ● Storybook上で実装‧テストしたコンポーネントをアプリケーションへ統合するのが主な流れ

Slide 37

Slide 37 text

37 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 実践例:複合コンポーネントのStorybook(1/2) 3.複合コンポーネントのStorybook駆動開発 ● 正常な⼊⼒で保存に成功したときの例 ● 保存ボタンを押すと最終的にダイアログが 閉じることをテストする 保存に成功したときダイアログが閉じる例(アニメーション)

Slide 38

Slide 38 text

38 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 実践例:複合コンポーネントのStorybook(2/2) 3.複合コンポーネントのStorybook駆動開発 ● 保存時にエラーレスポンスが返ってきた例 ● モーダルが閉じずにアラートが表⽰される ことをテストする ● ほかにも次のようなStoryを作成する ○ バリデーションエラー ○ 読込中 保存に失敗したときエラーが表⽰される例(アニメーション)

Slide 39

Slide 39 text

39 Copyright© Medley, Inc. ALL RIGHTS RESERVED. Storybook駆動開発をする理由 3.複合コンポーネントのStorybook駆動開発 ● インタラクションが多いため、コンポーネントレベルで品質を担保しながら 開発したい ● Storybookの資材を活⽤してコンポーネントテストを効率よく実装できる ● テスト対象が視覚的に確認できるのでデバッグしやすい ● QAエンジニア/デザイナーとのコラボレーションツールとして活⽤できる

Slide 40

Slide 40 text

40 Copyright© Medley, Inc. ALL RIGHTS RESERVED. ところでこれ、実はAPIモックツールを使っていません 3.複合コンポーネントのStorybook駆動開発 保存に成功したときダイアログが閉じる例(アニメーション) 保存に失敗したときエラーが表⽰される例(アニメーション)

Slide 41

Slide 41 text

41 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 軽量なStorybook駆動開発 ● APIモックツールに依存しないことで軽量かつ安定なStorybookを構築する⼿法 ● 軽量なStorybookを始めたところStorybook駆動開発がチームに定着した 3.複合コンポーネントのStorybook駆動開発 https://zenn.dev/yuta_takahashi/articles/600e62c7ac7b3c

Slide 42

Slide 42 text

42 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 実装例:軽量なStorybook 3.複合コンポーネントのStorybook駆動開発 ● データ取得結果のモックはobjectで定義 ● 更新処理のモックはResult型を返す関数を定義 ● ライブラリに依存せず、最⼩限のコードでモッ クを実装できる

Slide 43

Slide 43 text

43 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 私達がAPIモックツールを使わない理由 ● 当初はMock Service Workerを使ってAPIレスポンスをモックしていた ● フロントエンド‧バックエンドで分業していないため、Storybookのためだけ にAPIモックコードを実装するのは開発負荷が⾼かった ● 結果、「時間がないからStorybookを作らない」という状況が発⽣してしまい Storybook駆動開発が定着しなかった ● テストがFlakyになりがちで悩みの種だった 3.複合コンポーネントのStorybook駆動開発

Slide 44

Slide 44 text

44 Copyright© Medley, Inc. ALL RIGHTS RESERVED. まとめ:複合コンポーネントのStorybook駆動開発 ● Storybook駆動開発は堅牢な開発とテストをサポートしてくれる強⼒な開発 ⼿法 ● インタラクションが多い背景で、コンポーネントレベルで 品質を担保しながら開発したいためStorybook駆動開発を採⽤している ● マルチスタックな開発組織のため、APIモックツールを使わずに 効率よくStorybookを実装している 3.複合コンポーネントのStorybook駆動開発

Slide 45

Slide 45 text

45 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 4. 複合コンポーネントの構造 徹底解剖!医療業務システムのReactコンポーネント設計

Slide 46

Slide 46 text

46 Copyright© Medley, Inc. ALL RIGHTS RESERVED. Container/Presentation分割によるネットワークの分離 ● 1つの複合コンポーネントをContainer/Presentation(C/P)に分割 ● Containerレイヤーはネットワーク処理、PresentationレイヤーはUIの関⼼に集中 ● 独⽴して動作するようにネットワーク処理までセットでモジュール化 4.複合コンポーネントの構造 Container ネットワーク処理 データの相互変換 複合コンポーネントのC/P分割イメージ ネットワーク処理までモジュール化されているため のように1⾏で呼び出しが可能となる Presentation UI UI関連の状態管理 表⽰のためのロジック レガシーコードとの接続 Containerと Presentationで Pull Requestを分割する ことも可能

Slide 47

Slide 47 text

47 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 実装例:Container Component[参考10] 4.複合コンポーネントの構造 ● データの取得や更新処理を担当する ● API通信部分はResult型を返す⾮同期関数 としてPresentationに渡す ● API通信の結果、UIをどのように更新する かはすべてPresentationに任せる ● ネットワークレスポンス/リクエストの整形 は純粋関数のセレクタに切り出して単体テ ストする

Slide 48

Slide 48 text

48 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 実装例:Presentation Component[参考10] 4.複合コンポーネントの構造 ● Containerから受け取った⾮同期関数を イベント時に実⾏する ● Result型の結果に応じてステートの更新を ハンドリングする ● UIの表⽰に関する処理はPresentationに 閉じていることがコンポーネントテストに おいて重要なポイント

Slide 49

Slide 49 text

49 Copyright© Medley, Inc. ALL RIGHTS RESERVED. データ取得の重複排除とキャッシュの活⽤ ● 各々の複合コンポーネントがデータ取得を同時に実⾏する場合、 同じリソースを参照すると重複リクエストが発⽣してしまう ● Tanstack QueryやSWRなどのライブラリやその他フレームワークが 備えている重複リクエスト排除機能[参考11, 12]を使って 無駄なリクエストを抑⽌する必要がある ● CLINICSではTanstackQueryを利⽤することで重複リクエストを排除 している ● 必要に応じてキャッシュから取得する場合もある 4.複合コンポーネントの構造

Slide 50

Slide 50 text

50 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 複合コンポーネントのディレクトリ構造例 4.複合コンポーネントの構造 src/components/usecases/user/UserProfileForm ├── UserProfileForm.container.tsx ├── UserProfileForm.schema.ts ├── UserProfileForm.selector.test.ts ├── UserProfileForm.selector.ts ├── UserProfileForm.stories.tsx ├── UserProfileForm.test.tsx ├── UserProfileForm.tsx ├── useUserProfileForm.ts └── index.ts フォームのバリデーションスキーマ Containerコンポーネント、ネットワーク処理がないときは定義しない データ整形のための純粋関数のテスト データ整形のための純粋関数 Storybookの定義 Storybookの資材を活⽤したコンポーネントテスト Presentationコンポーネント カスタムフック、状態のリフトアップが必要またはロジックが⼤きいときのみ定義 外部からの呼び出しを許可するモジュールをexport

Slide 51

Slide 51 text

51 Copyright© Medley, Inc. ALL RIGHTS RESERVED. Render Hooks:リフトアップした状態をカプセル化する ● ダイアログの開閉など、リフトアップが必要な状態とコンポーネントをカプセル化したい場合は Render Hooks[参考13]を使って実装することで⾼いモジュール性を実現 4.複合コンポーネントの構造

Slide 52

Slide 52 text

52 Copyright© Medley, Inc. ALL RIGHTS RESERVED. C/P分割がネストするときはどうすれば良いか? ● 親のPresentationで⼦のC/Pを出し分けるようにすると良い ● 本ワークショップでは詳細は省略 4.複合コンポーネントの構造 https://zenn.dev/yuta_takahashi/articles/45c6ceecd6b12a

Slide 53

Slide 53 text

53 Copyright© Medley, Inc. ALL RIGHTS RESERVED. まとめ:複合コンポーネントの構造 ● Container/Presentation分割でネットワーク処理とそれ以外を分離すること で、APIモックツールに依存しないStorybook駆動開発を実現している ● ネットワーク処理までモジュール化されているため のように1⾏で呼び出しが可能となる ● 個々の複合コンポーネントが独⽴していることで保守性が向上する ● ただし、ライブラリやフレームワークの重複リクエスト排除機能を活⽤して 重複リクエストを抑⽌する必要がある 4.複合コンポーネントの構造

Slide 54

Slide 54 text

54 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 5. 開発速度と品質を両⽴するためのテスト戦略 徹底解剖!医療業務システムのReactコンポーネント設計

Slide 55

Slide 55 text

55 Copyright© Medley, Inc. ALL RIGHTS RESERVED. CLINICSにおけるフロントエンドの⾃動テスト テストケースレベルで重複しないように次の⾃動テストを実装 1. ユニットテスト 2. コンポーネントテスト 3. ビジュアルリグレッションテスト 4. E2Eテスト 5.開発速度と品質を両⽴するためのテスト戦略

Slide 56

Slide 56 text

56 Copyright© Medley, Inc. ALL RIGHTS RESERVED. ユニットテスト:純粋関数の振る舞いを検証 テスト対象 ● ネットワーク境界と値を相互変換する純粋関数 ● 表⽰状態やインタラクションに必要な値を計算するための純粋関数 ○ 例:フォーム送信時の後続処理の分岐を⼊⼒値に応じて計算するロジック ● 複雑なバリデーションスキーマ(コンポーネントテストだと効率が悪くなってしまう場合) 使⽤ツール ● Vitest 5.開発速度と品質を両⽴するためのテスト戦略

Slide 57

Slide 57 text

57 Copyright© Medley, Inc. ALL RIGHTS RESERVED. コンポーネントテスト:コンポーネントの振る舞いを検証 テスト対象 ● インタラクションを含む複合コンポーネント(Storybook駆動開発の過程で実装したStory) ○ 例:フォーム送信時のインタラクション、フォームのバリデーションエラー等 ● uiParts, utilitiesに分類される汎⽤コンポーネント 使⽤ツール ● Vitest ● Storybook ● Testing Library, jsdom 備考 ● 複雑なコンポーネントの改修やライブラリアップデート時に役⽴つ 5.開発速度と品質を両⽴するためのテスト戦略

Slide 58

Slide 58 text

58 Copyright© Medley, Inc. ALL RIGHTS RESERVED. テスト対象 ● Storybookが定義されているコンポーネント ○ uiPartsに分類される汎⽤コンポーネント ○ インタラクションを含む複合コンポーネント(※ 不要なものは適宜除外) 使⽤ツール ● Storybook ● Storycap ● reg-suit 備考 ● 他と⽐較してFlakyになりやすいためCIでのチェックはマストではなく、参考程度の扱いで運⽤ ● ライブラリアップデートや汎⽤UIの改修時に役⽴つ ビジュアルリグレッションテスト:画像の差分を検証 5.開発速度と品質を両⽴するためのテスト戦略

Slide 59

Slide 59 text

59 Copyright© Medley, Inc. ALL RIGHTS RESERVED. E2Eテスト:業務シナリオのハッピーパスを検証 テスト対象 ● デプロイされたステージング環境 ● バックエンドや外部連携サービスを含めたシステム全体の動作 使⽤ツール ● MagicPod 備考 ● QAエンジニアが実装 ● 実⾏コストが⾼いため次の頻度で運⽤ ○ 毎朝developブランチに定期実⾏ ○ 週次でリリース対象ブランチに実⾏ ○ その他は必要な際にマニュアルで実⾏ 5.開発速度と品質を両⽴するためのテスト戦略

Slide 60

Slide 60 text

60 Copyright© Medley, Inc. ALL RIGHTS RESERVED. まとめ:開発速度と品質を両⽴するためのテスト戦略 5.開発速度と品質を両⽴するためのテスト戦略 # テスト分類 内容 ツール 実装者 1 ユニットテスト 純粋関数に切り分けたデータ変換 や表示のための複雑な値計算の振 る舞いを検証 複雑なバリデーションスキーマの振 る舞いを検証 Vitest プロダクト開発エンジニア 2 コンポーネントテスト コンポーネントの振る舞いを検証 Vitest, Storybook, Testing Library, jsdom プロダクト開発エンジニア 3 ビジュアルリグレッション テスト 画像差分を検証 Storybook, Storycap, reg-suit プロダクト開発エンジニア 4 E2Eテスト 業務シナリオのハッピーパスを検証 MagicPod QAエンジニア プロダクト開発エンジニアとQAエンジニアが連携しながら有効な⾃動テストを素早く実装

Slide 61

Slide 61 text

61 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 本ワークショップのまとめ ● ⼤規模‧複雑化するWebフロントエンドの開発において当たり前品質を維持し続けることは重要な 課題 ● Reactコンポーネント設計を⼯夫することでテストしやすく保守しやすいUIを構築している 事例を紹介した ● 複合コンポーネントとして機能の単⼀責務に特化したコンポーネントに分割している ● APIモックツールを使わない軽量なStorybook駆動開発を実践することでテスト⽂化を醸成した ● プロダクト開発エンジニアとQAエンジニアが連携しながら、ユニットテスト、コンポーネントテ スト、ビジュアルリグレッションテスト、E2Eテストを実装することで 全体の品質を効率的に担保している おわりに

Slide 62

Slide 62 text

62 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 参考 1. 狩野モデル - Wikipedia 2. BCD Design によるコンポーネントの分類 #設計 - Qiita 3. JISX25010:2013 システム及びソフトウェア製品の品質要求及び評価(SQuaRE)-システム 及びソフトウェア品質モデル 4. Storybook: Frontend workshop for UI development 5. Stories in unit tests 6. Portable stories in Jest - Docs 7. Portable stories in Playwright CT 8. Portable stories in Vitest 9. Storybook 駆動開発 @ CSF3.0 おわりに

Slide 63

Slide 63 text

63 Copyright© Medley, Inc. ALL RIGHTS RESERVED. 参考 10. frontend-articles-code/apps/lightweight-storybook at main · YTakahashii/frontend-articles-code 11. Overview | TanStack Query React Docs 12. Performance ‒ SWR 13. Render hooksをコンポーネントの拡張として理解する #React - Qiita おわりに

Slide 64

Slide 64 text

64 Copyright© Medley, Inc. ALL RIGHTS RESERVED.