$30 off During Our Annual Pro Sale. View Details »

フロントエンドの複雑さに耐えるため実践したこと / readyfor-nextjs-first

Takepepe
February 05, 2021

フロントエンドの複雑さに耐えるため実践したこと / readyfor-nextjs-first

【READYFOR】実践!フロントエンド分離戦略::発表資料
https://readyfor.connpass.com/event/198730/

Takepepe

February 05, 2021
Tweet

More Decks by Takepepe

Other Decks in Technology

Transcript

  1. READYFOR x Next.js
    フロントエンドの複雑さに耐えるため実践したこと

    @ Takepepe


    View Slide

  2. READYFOR フロントエンド分離のゴール

    ■ BE/FE の責務をわけ、疎結合とすること

    ■ 時代に即したベストプラクティスを追求できること


    #readyfor_meetup


    View Slide

  3. READYFOR フロントエンド分離のゴール
    これまでモノリスだった RoR の

    アプリケーションサーバーは APIサーバーへ。

    View はJS(TS)だけで完結する姿へ…


    #readyfor_meetup


    View Slide

  4. READYFOR フロントエンド分離のゴール
    Next.js はこういった背景のプロダクトで選ばれる、

    筆頭の選択肢となりました。

    静的キャッシュ恩恵・ゼロコンフィグ、

    SSR ハイブリッドなど、要件に合わせやすいです。

    #readyfor_meetup


    View Slide

  5. 参画の経緯と当時の状況

    READYFOR からお誘いをうけ

    委託参画したのが昨年4月。

    この10ヶ月間で2つの Next.js 案件

    立ち上げをお手伝いしました。


    #readyfor_meetup


    View Slide

  6. 参画の経緯と当時の状況

    すでに分離戦略が敷かれていたため、

    わたしの担当は明確でした。

    デザインシステム(READYFOR Elements)を利用

    して、Next.js App を構築することです。

    #readyfor_meetup


    View Slide

  7. 参画の経緯と当時の状況

    ■ RoR アプリケーション一部に、react_on_rails

    ■ READYFOR Elements が仕上がっていた

    ■ Next.js 製の PoC があった 

    #readyfor_meetup


    View Slide

  8. 参画の経緯と当時の状況
    Next.js / SPA 化にともない、フロントエンドが抱える

    表示ロジックが複雑になることが想定されました。

    その複雑さを乗り越える設計・実装を

    どの様に行ったのかを、本日お話します。


    #readyfor_meetup


    View Slide

  9. Redux
    の参照秩序


    View Slide

  10. はじめに手掛けた「実行者SPA」は、

    細かな UI の部分再描画が頻出する要件でした。

    状態管理ライブラリに Redux を選定しました。

    Redux を選んだ理由

    #readyfor_meetup


    View Slide

  11. Redux を選んだ理由

    ■ 算出値のメモ化と、部分再描画に優れている

    ■ devtools が他ソリューションと比較し充実している

    ■ integration test が実施しやすい

    #readyfor_meetup


    View Slide

  12. Redux は「秩序が生まれやすい」と定評がありますが、

    使い方次第では「無秩序」になりやすいものです。

    採用の際には、ガイドラインが必要です。

    Redux の懸念点

    #readyfor_meetup


    View Slide

  13. 参照秩序 のガイドライン
    ファイル構成は

    Re-ducks パターンとしました。

    関心範囲を境界とし、

    Module 毎で管理。

    ├── redux

    ├── A

    ├── B

    ├── C

    ├── D

    ├── index.ts

    ├── reducers.ts

    └── store.ts

    #readyfor_meetup


    View Slide

  14. 参照秩序 のガイドライン
    ├── redux

    ├── A

    ├── B

    ├── C

    ├── D

    ├── index.ts

    ├── reducers.ts

    └── store.ts

    ファイル構成は

    Re-ducks パターンとしました。

    関心範囲を境界とし、

    Module 毎で管理。

    Module
    #readyfor_meetup


    View Slide

  15. 参照秩序 のガイドライン
    ├── redux

    ├── A

    ├── B

    ├── C

    ├── D

    ├── index.ts

    ├── reducers.ts

    └── store.ts

    Module の内訳は以下のとおり。

    State を軸とした定義を保有します。

    state.ts / reducer.ts / actions.ts

    selectors.ts / thunks.ts

    #readyfor_meetup


    View Slide

  16. 参照秩序 のガイドライン
    ├── redux

    ├── A

    ├── B

    ├── C

    ├── D

    ├── index.ts

    ├── reducers.ts

    └── store.ts

    この Module 同士は、

    参照関係をもつことができます。

    #readyfor_meetup


    View Slide

  17. 参照秩序 のガイドライン
    ├── redux

    ├── A

    ├── B

    ├── C

    ├── D

    ├── index.ts

    ├── reducers.ts

    └── store.ts

    例えば「A」で発行された

    「A」のための Action を、

    「C・B」でも購読する、

    という参照関係です。

    #readyfor_meetup


    View Slide

  18. 参照秩序 のガイドライン
    ├── redux

    ├── A

    ├── B

    ├── C

    ├── D

    ├── index.ts

    ├── reducers.ts

    └── store.ts

    この参照秩序が保たれなければ、

    スパゲティコードが生まれます。

    Reducer と Selector で、

    この参照捻れは発生し得ます。

    #readyfor_meetup


    View Slide

  19. 参照秩序 のガイドライン
    参照秩序は公式ガイドの

    Basic State Shape を参考に、

    「Module prefix」で明文化しました。

    https://redux.js.org/recipes/structuring-reducers/basic-reducer-structure#basic-state-shape

    #readyfor_meetup


    View Slide

  20. Module prefix ?

    View Slide

  21. 参照秩序 のガイドライン

    Api** App** UI** Page**
    Module prefix を4つに区分。

    prefix により、参照権限が異なります。


    View Slide

  22. 参照秩序 のガイドライン(prefix: Api***)
    Api** App** UI** Page**
    API レスポンスを「取得・保持」するのみ。

    API path と1対1で設け「別 Module は参照しない」


    View Slide

  23. 参照秩序 のガイドライン(prefix: App***)

    App** UI** Page**
    アプリケーションで横断的に利用する値を管理。

    また「API・App」Module しか参照できない。

    Api**

    View Slide

  24. 参照秩序 のガイドライン(prefix: UI***)

    UI** Page**
    Global UI に関連する状態しか持たない。

    また「API・App・UI」しか参照できない。

    Api** App**

    View Slide

  25. 参照秩序 のガイドライン(prefix: Page***)

    Page**
    全ての値と Action を参照できる。

    Page Component と1対1。

    Api** App** UI**

    View Slide

  26. 参照秩序 のガイドライン(prefix: Page***)

    「下流 Module が上流 Module を参照する」という、

    シンプルな命名規則による参照秩序を設けました。

    Api** App** UI** Page**
    上流 下流

    View Slide

  27. このガイドラインの目的は、

    参照権限を限定することで、

    責務の所在を明確にすることです。


    参照秩序 のガイドライン

    #readyfor_meetup


    View Slide

  28. 責務の所在地が明確であれば、

    設計の属人化が最小限になります。

    そして、必要な責務のみが下流に降りてきます。

    参照秩序 のガイドライン

    #readyfor_meetup


    View Slide

  29. 参照秩序 のガイドライン

    Page**
    この関係とすることで、特定ページ専用の「Page**」Module は、

    特定ページの処理のみに、専念することができます。

    Api** App** UI**

    View Slide

  30. 参照秩序 のガイドライン

    ■ 実装中に異常な参照捻れに気付ける

    ■ コンテキスト理解が容易くレビュー負荷も下がる


    命名規則だけで、開発体験はよりよくなる!

    #readyfor_meetup


    View Slide

  31. Cypress
    実践 BDD


    View Slide

  32. Cypress で実践する BDD

    表示分岐ロジックが複雑になることが想定されたため、

    integration テストは不可欠としていました。

    そのため、後発の Prj は立ち上げ初期から

    BDD を採用しました。

    #readyfor_meetup


    View Slide

  33. Cypress で実践する BDD

    これから作成しようとするプログラムに

    期待される「振る舞い」や「制約条件」、

    つまり「要求仕様」に近い形で、

    自然言語を併記しながらテストコードを記述する。

    引用:https://ja.wikipedia.org/wiki/ビヘイビア駆動開発
    #readyfor_meetup


    View Slide

  34. Cypress で実践する BDD

    実践にあたり採用したのが Cypress です。

    Cypress は動作が軽快で BDD に適した

    テストフレームワークです。


    #readyfor_meetup


    View Slide

  35. Cypress で実践する BDD

    Redux と Cypress は相性がよく、

    Action dispatch で特定条件の再現が可能です。

    こういった場面で、Redux の特性が活きてきます。

    #readyfor_meetup


    View Slide

  36. Cypress で実践する BDD

    混み入った分岐条件でのみ現れる画面も、

    どの「状態・Action」があれば再現できるのか?

    が、テストコードに落ちてきます。

    #readyfor_meetup


    View Slide

  37. Cypress で実践する BDD

    特定制約時を再現するの事が容易なため、

    テストファイルを細分化できます。

    表示を即座に確認できるため、

    ドキュメントとしても役立ちます。

    #readyfor_meetup


    View Slide

  38. View Slide

  39. Cypress で実践する BDD

    また、OpenAPI 定義によるMock サーバーを、

    Cypress integration テストにも

    活用しました。

    #readyfor_meetup


    View Slide

  40. Cypress で実践する BDD

    「テストを書きやすい」環境は、

    ライブラリ・ツール選択で明らかに

    差が出てきます。

    #readyfor_meetup


    View Slide

  41. Cypress で実践する BDD

    また、ワークフローの工夫も大切です。 

    タスク分解の段階で「書きやすさ」は変わります。

    タスクを細分化し、十分小さくすることです。

    #readyfor_meetup


    View Slide

  42. Cypress で実践する BDD

    チケットを発行し、チケット番号とともに

    要求仕様の「空テスト」をコミット。 

    describe("「支払い方法」そのものが表示されない条件 ", () => {
    xit("最終確認ページから「リターンを変更する」ために戻ってきた場合 ", () => {
    // TODO: #567
    });
    });

    View Slide

  43. Cypress で実践する BDD

    PR とともに実装内容がテストに記されているため、

    PR 概要を詳に書かずとも概要が伝わる状態が理想です。


    describe("「支払い方法」そのものが表示されない条件 ", () => {
    - xit("最終確認ページから「リターンを変更する」ために戻ってきた場合 ", () => {
    + it("最終確認ページから「リターンを変更する」ために戻ってきた場合 ", () => {
    });
    });

    View Slide

  44. Cypress で実践する BDD

    ライブラリ側もテストツール群も、

    得意・不得意(オーバースペック)があります。 

    ライブラリ選定の際には「テスト観点」も含め、

    バランスをとりながら選ぶ必要があります。


    #readyfor_meetup


    View Slide

  45. 振り返りと
    今後


    View Slide

  46. 制御・非制御 Component の I/F

    READYFOR Elements の再利用は

    とても上手くいきました。

    しかし、一部検討余地がありました。



    #readyfor_meetup


    View Slide

  47. 制御・非制御 Component の I/F

    たとえば、非制御 Component + Form

    前提の props 設計が紛れていた事。

    Form 都合の props を剥がすリファクタリングに

    想定以上の工数がかかりました。


    #readyfor_meetup


    View Slide

  48. 制御・非制御 Component の I/F

    また、制御 Component と比べると、

    非制御 Component は Redux と

    相性がよくありません。

    #readyfor_meetup


    View Slide

  49. 制御・非制御 Component の I/F

    React on Rails で利用していた箇所としては、

    非制御 Component がベストだった背景がそこに。

    移行に必要なコストに違いないものです。


    #readyfor_meetup


    View Slide

  50. 制御・非制御 Component の I/F

    READYFOR Elements の様な横断的な

    デザインシステムを構築するのなら、

    制御・非制御 Component を選択できる様な

    I/F を初期設計から盛り込むべきです。


    #readyfor_meetup


    View Slide

  51. これからも Redux を使いつづけるか?

    useContextSelector など、

    Redux(useSelector) の代替となる様な

    React 公式 API の検討も始まっており、

    状態管理ライブラリ選定はやはり悩みどころです。

    #readyfor_meetup


    View Slide

  52. これからも Redux を使いつづけるか?

    これからも Redux を使いつづけるか?

    というと「都度検討」だと思います。

    readyfor は機能単位で Next.js を分割しているため、

    状態管理も機能要件にあわせて選択できます。


    #readyfor_meetup


    View Slide

  53. これからも Redux を使いつづけるか?

    Redux のテスト優位性をあげたとおり、

    フロントに複雑な表示ロジックを置く場合は、

    導入メリットが多いです。


    #readyfor_meetup


    View Slide

  54. これからも Redux を使いつづけるか?

    表示ロジックがフロントに寄る場合は採用、

    表示ロジックがサーバーに寄る場合は不採用、

    という切り分けをすると思います。

    #readyfor_meetup


    View Slide

  55. READYFOR の

    フロントエンドの分離戦略は

    スタートを切ったばかりです。

    #readyfor_meetup


    View Slide

  56. またいつか、

    この続きを共有できる事を

    楽しみにしています。

    #readyfor_meetup


    View Slide

  57. READYFOR x Next.js
    ご清聴ありがとうございました!


    View Slide