Slide 1

Slide 1 text

1 Storybook駆動開発で フロントエンドリアーキテクトに⽴ち向かう 2024/09/05 髙橋 佑太 / Yuta Takahashi 各社から学ぶ!フロントエンドのためのリアーキテクチャ #リアーキテクチャ_findy

Slide 2

Slide 2 text

2 ⾃⼰紹介:髙橋 佑太 / Yuta Takahashi 2021年に現職に新卒⼊社 医科診療所向け業務アプリケーションの開発に従事 普段はReactやRuby on Railsを書いている Webフロントエンドの設計を考えるのが好き X(Twitter):@Wakeupsloth はじめに

Slide 3

Slide 3 text

3 内容 1. Storybook駆動開発を始めよう 2. Storybook駆動開発を活⽤したフロントエンドリアーキテクト 3. Storybook駆動開発を軌道に乗せるためのアプローチ はじめに

Slide 4

Slide 4 text

4 1. Storybook駆動開発を始めよう

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

6 Play Function:インタラクションを⾃動化する 1.Storybook駆動開発を始めよう

Slide 7

Slide 7 text

7 Portable Stories:Storyの実⾏結果をテストする ● StoryをJest, Vitest, Playwright CTなどの テストツールで利⽤できるユーティリティ [2][3][4][5] ● インタラクションとアサーションを 実⾏レベルで分離できる ● Storybook上で確認したテストケースに対してア サーションを書くだけで簡単にテストを実装で きる 1.Storybook駆動開発を始めよう

Slide 8

Slide 8 text

8 Storybook駆動開発 1.Storybook駆動開発を始めよう 󰞵Storybook上で作り込み ✅テスト 🚀アプリケーションへ統合 ● Storybook駆動開発[6]は堅牢な開発とテストをサポートしてくれる強⼒な開発⼿法 ● Storybook上で実装‧テストしたコンポーネントをアプリケーションへ統合するのが主な流れ

Slide 9

Slide 9 text

9 2. Storybook駆動開発を活⽤した フロントエンドリアーキテクト

Slide 10

Slide 10 text

10 概要:私達のフロントエンドリアーキテクト 2.Storybook駆動開発を活⽤したフロントエンドリアーキテクト 課題 ● 複数の課題が⼭積みされ、変更に時間がかかり、開発が難しいコードベースになっていた ● 可読性、変更容易性、テスト容易性、モダンフロントエンドとのギャップなどが主な課題 達成したい⽬標 ● モダンな技術スタックへの移⾏による開発体験の向上 ● 持続可能なコードベースの構築による可読性、拡張容易性、内部品質の向上 採⽤したアプローチ ● ページ/コンポーネント単位のリアーキテクト(ライブラリ移⾏等を含む) ● 複合コンポーネント単位のStorybook駆動開発によるテストコードの整備

Slide 11

Slide 11 text

11 実践例:複合コンポーネント単位のStorybook駆動開発 ● 単⼀責任の原則に従った複合コンポーネント(機能単位)ごとに開発 ● 複合コンポーネントは⾃律的に動作するようにネットワーク処理までセットでモジュール化 ● Container/Presentationで分割し、PresentationレイヤーはUIの関⼼に集中 2.Storybook駆動開発を活⽤したフロントエンドリアーキテクト 開発の流れとテスト戦略 1. PresentationをStorybook駆動開発でテスト ○ ビジネスロジックを含む場合は純粋関数 に切り出して単体テスト 2. Containerの実装と各要素の単体テスト 3. アプリケーションへ繋ぎこみE2Eテスト Container ネットワーク処理 データの相互変換 複合コンポーネント(例:) Presentation UI UI関連の状態管理 ビジネスロジック レガシーコードとの接続

Slide 12

Slide 12 text

12 実践例:巨⼤なレガシーページのリアーキテクト 2.Storybook駆動開発を活⽤したフロントエンドリアーキテクト ● 複合コンポーネントごとにテストを実装しながら持続可能なコードベースへ再構築 ● ページ単位で丸ごと再構築 or 機能拡張の箇所から漸進的に始めることも技術スタック次第で可能 Container Presentation Container Presentation Container Presentation Container Presentation 巨⼤なレガシーページ ネットワーク処理 UI UI UI UI ビジネスロジック グローバルステート UI ‧‧‧ 複合コンポーネントA 複合コンポーネントB 複合コンポーネントC 複合コンポーネントN リアーキテクト後のページ

Slide 13

Slide 13 text

13 実践例:複合コンポーネントのStorybook(1/2) 2.Storybook駆動開発を活⽤したフロントエンドリアーキテクト ● 正常な⼊⼒で保存に成功したときの例 ● 保存ボタンを押すと最終的にダイアログが 閉じることをテストする UserProfileEditDialog(保存成功ケース)

Slide 14

Slide 14 text

14 実践例:複合コンポーネントのStorybook(2/2) 2.Storybook駆動開発を活⽤したフロントエンドリアーキテクト ● 保存時にエラーレスポンスが返ってきた例 ● モーダルが閉じずにアラートが表⽰される ことをテストする ● ほかにも次のようなStoryを作成する ○ バリデーションエラー ○ 読込中 UserProfileEditDialog(保存失敗ケース)

Slide 15

Slide 15 text

15 参考:私達のフロントエンドリアーキテクトの詳細 2.Storybook駆動開発を活⽤したフロントエンドリアーキテクト リアーキテクト要素 As-Is To-Be UIライブラリ Mithril (jsx) React (tsx) コンポーネント設計 ページ単位のデータフェッチ APIやビジネスロジックが密結合で テストが難しい構造 複合コンポーネント単位のデータフェッチ Container/Presentation分割によるテストしやすい構造 ステート管理 Reduxですべてのステートを管理 「複数画面の共通ステート」によって リグレッションしやすい構造 グローバル(Redux) フォーム(react-hook-form) 非同期(TanstackQuery) テスト Unit Test(Jest) E2E Test(MagicPod) Unit Test (Vitest) UI Test(Vitest, Storybook, React Testing Library) Visual Regression Test(regsuit, storycap) E2E Test(MagicPod) ページ/コンポーネント単位で、開発体験に優れた拡張‧保守しやすいコードベースへ再構築

Slide 16

Slide 16 text

16 Storybook駆動開発をリアーキテクトに活⽤した効果 良かったこと ● テストコードを同時に実装する⽂化が醸成できた ○ レビューが簡単になった ○ リファクタリングしやすくなった ● 複合コンポーネント単位での漸進的なリアーキテクトが可能になった ● Storybook(Vite)による爆速な開発環境の恩恵を最⼤限受けられる ⼤変だったこと ● Storybook駆動開発を軌道に乗せるために⾃分たちに合う実装⽅針‧コンポーネント設計を模索し た 2.Storybook駆動開発を活⽤したフロントエンドリアーキテクト

Slide 17

Slide 17 text

17 3. Storybook駆動開発を軌道に乗せる ためのアプローチ

Slide 18

Slide 18 text

18 これ、実はAPIモックツールを使っていません 3.Storybook駆動開発を軌道に乗せるためのアプローチ UserProfileEditDialog(保存成功ケース) UserProfileEditDialog(保存失敗ケース)

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

20 軽量なStorybook駆動開発 ● APIモックツールに依存しないことで軽量かつ安定なStorybookを構築する⼿法 ● 軽量なStorybookを始めたところStorybook駆動開発がチームに定着した 3.Storybook駆動開発を軌道に乗せるためのアプローチ https://zenn.dev/yuta_takahashi/articles/600e62c7ac7b3c

Slide 21

Slide 21 text

21 実装例:軽量なStorybook 3.Storybook駆動開発を軌道に乗せるためのアプローチ ● 取得処理のモックは結果をobjectで渡すだけ ● 更新処理のモックはResult型で返すだけ ● ライブラリに依存せず、最⼩限のコードでモッ クを実装できる

Slide 22

Slide 22 text

22 実装例:Container Component 3.Storybook駆動開発を軌道に乗せるためのアプローチ ● データの取得や更新処理を担当する ● API通信部分はResult型を返す⾮同期関数 としてPresentationに渡す ● API通信の結果、UIをどのように更新する かはすべてPresentationに任せる ● ネットワークレスポンス/リクエストの整形 は純粋関数のセレクタに切り出して単体テ ストする

Slide 23

Slide 23 text

23 実装例:Presentation Component 3.Storybook駆動開発を軌道に乗せるためのアプローチ ● Containerから受け取った⾮同期関数を イベント時に実⾏する ● Result型の結果に応じてステートの更新を ハンドリングする

Slide 24

Slide 24 text

24 軽量なStorybookのデモ(再) 3.Storybook駆動開発を軌道に乗せるためのアプローチ UserProfileEditDialog(保存成功ケース) UserProfileEditDialog(保存失敗ケース)

Slide 25

Slide 25 text

25 まとめ ● Storybook駆動開発は堅牢な開発とテストをサポートしてくれる強⼒な開発⼿法 ● 単⼀機能を責務とする複合コンポーネント単位のStorybook駆動開発を フロントエンドリアーキテクトに応⽤した事例を紹介した ● Storybook駆動開発を開発⽂化としてチームに定着するためには、⾃分たちの置かれている環境に 応じて周辺ツールを適切に使い分けることが重要 おわりに

Slide 26

Slide 26 text

26 参考 1. Storybook: Frontend workshop for UI development 2. Stories in unit tests 3. Portable stories in Jest - Docs 4. Portable stories in Playwright CT 5. Portable stories in Vitest 6. Storybook 駆動開発 @ CSF3.0 おわりに