2024.10.10
将来は卵1パックの価格が2倍に? 多くの日本人が知らない世界の新潮流、「動物福祉」とは
Next.jsの採用、アーキテクチャ関連(全1記事)
リンクをコピー
記事をブックマーク
吉井健文氏(以下、吉井):Takepepeです。「フロントエンドの複雑に耐えるために実践したこと」というタイトルで、本日発表します。Reactの地続きとして、READYFORのアプリケーションがNext.js化していくところをお話しします。
分離戦略のゴールです。バックエンドとフロントエンドの責務をきちんと分けて、疎結合すること。フロントエンドの部分ですね。時代に即したベストプラクティスが、いろいろ出てきているので、そういったところを追求できるところがゴールです。
これまでモノリスだったRailsのアプリケーションですが、そこのアプリケーションサーバーはAPIサーバーへ、Viewの部分はJS(TypeScript)だけで完結する。そういった姿を目指します。
Next.jsはこのような背景で選ばれるプロダクトとして、筆頭の選択肢となっているんじゃないかと思っています。静的なキャッシュの恩恵であったり、ゼロコンフィグであったり。また、SSRのハイブリッドができたり、けっこう要件に合わせやすいフレームワークです。
私は今はちょっと業務委託のようなかたちでお手伝いしていて。お誘いを受けたのが2020年の4月ですね。かれこれ10ヶ月ぐらい経ちますが、この期間に2つのNext.jsの立ち上げをお手伝いしました。この2つ目が、来週にリリースぐらいのところに差し掛かっている状況です。
すでに分離戦略が敷かれていたので、私に求められたことは本当に明確で。しっかり作られたREADYFOR Elements。これを利用して、Next.js Appを構築していく。本当にかなりしっかりしたデザインシステムがあったので、本当にもうパパっと組めちゃうような。そういった状況ができているのかと所感で思っていました。
Railsアプリケーションの上に、react_on_railsというかたちでReactのコンポーネントが乗っている。Elementsが仕上がっていて、すでにちょっとNext.js製のPoCがあり、「こういうふうにしたら実現できそうだよね」みたいなところまで見えていたところからスタートしました。
単純にSPA化するといっても、フロントが抱える部分の表示ロジックがかなり複雑になっていて。ソースを見て、これけっこうやばいな、分岐がすげえなと思って。そういったところの複雑さをどうやって乗り越えたか。設計や実装などをメインにお話ししたいと思います。
今回Next.jsに対して、Reduxを使っています。一番はじめに手がけた、実行者SPAです。要は、クラウドファンディングで募るほうのSPAですが、細かいUIがけっこう組み合わさっていて。部分の再描画が頻出そうな要件がけっこうあったため、状態管理ライブラリはしっかりしたものを選びたいというのがあり、迷わずReduxを選びました。
Reduxのよいところですが、算出の値のメモ化が、このReactノードの外側でできる。そういったところで、引っ張られないような再描画に優れています。devtoolsは、ほかのソリューションと比べたら、かなり充実しています。あと最後に、今日この話もちょっとしますが、integration testが実施しやすい。そういったところもあります。
Reduxは使い込んでいない人からすると「秩序が生まれやすいライブラリだよね」という、ふわっとしたイメージがあるかと思います。しかし、使い方次第で無秩序になりやすいものです。採用の際には、けっこうちゃんとしたガイドラインが必要です。
ファイル構成です。“Re-ducksパターン”とググるとけっこう出てくると思うので、知っている方もいるかと思いますが、これを採用しています。関心の範囲を境界として、Moduleごとに管理しています。Moduleと呼んでいるのは、ここの部分です。このreduxディレクトリの中にある、ここの1つの単位です。
Moduleの内訳は、こういったかたちです。中にstateのファイルがあり、それを軸にしてreducerとaction、selectorとredux-thunkのファイルがある。
このModule同士ですが、Reduxの1つの強みとして、こういった参照の関係をもてます。
どういうことかというと、例えば「A」で発行された「A」のためのAction。そういったActionであっても、「C」や「B」でも購読できる、そういった参照の関係です。
ただ、この参照関係、しっかり秩序を保たないとスパゲティコードが簡単に生まれてしまいます。ReducerやSelectorなどで参照のねじれは、けっこう頻繁に発生してしまいます。
この参照秩序は公式のガイドラインがいろいろありますが、その中でも「Basic State Shape」という項目があり、そこの「Module prefix」を参考にして明文化しました。
「Module prefixとはいったい何なのでしょう?」というところですが、けっこう簡単な話です。Module単位で区切っていますが、接頭辞をつけると。頭に「Api**」「App**」「UI**」というような、接頭辞をつけることです。このprefixがあることによって「参照権限をこうします」というルールをはじめに敷きました。
この「Api」Moduleですが、APIのレスポンスを取得したり保持したりするだけです。そのため、「Api」以外のところのModuleで、非同期の処理が発生しない状況です。APIのpathと1対1で設けて、そのほかのModule同士の参照は発生しないガイドラインを敷きました。
その下に「App」という接頭辞がついたModuleがきます。アプリケーションで横断的に利用するものの、「Api」と「App」のModuleしか参照できない値を「App」で管理します。
「UI」は、上でしか参照できない。「UI」というのは、よくあるヘッダーやモーダルなど、横断的に利用するModuleを指しています。
最後に「Page」です。上で練り上げられたActionなどを参照できます。PageのComponentと対になるようなModuleです。
こういった、下流のModuleが上流のModuleを参照するような命名規則による法則です。こういった参照秩序を設けました。
このガイドラインの目的ですが、参照権限を限定することで、責務の所在を明確にします。
責務の所在地が明確であれば、設計の属人化が最小限になります。また、必要な責務のみが下流に降りてきます。先ほども言ったように、「これ、横断的な値ですよね?」と話になったときには、PageのところからAppにマイグレーションしたり、APIの話がほかに降りてこないような。そういったことです。
特定ページ専用のこういったModuleですが、このページの処理のみに専念できる。そのため、やはり一番複雑になるのは、ここのModuleです。
このガイドラインのよいところは、実装中に異常な参照のねじれにすぐに気づけること。また、コンテキストの理解がたやすくて、レビューの負荷が下がります。この命名規則だけでけっこう開発体験がよくなるので、検討するといいかなと思っています。
では次に、実践BDD(ビヘイビア駆動開発)というところで、Cypressについてお話しします。
冒頭でお話ししたとおり、表示分岐のロジックがかなり複雑になることが想定されていたため、この部分のintegrationテストは不可欠だと感じていました。そのため、後発のプロジェクトに関しては、立ち上げの初期からこのBDDを採用しました。
BDDっていったい何だというところで、ちょっとWikipediaを引用します。「これから作成しようとするプログラムに対して期待される『振る舞い』と『制約の条件』、つまり『要求仕様』に近いかたちで、自然言語を併記しながらテストコードを記述する」と。
実践あたって採用したのがCypressです。Cypressは動作が軽快でBDDに適したフレームワークです。
ReduxとCypressは相性がよく、Action dispatchで特定の条件の再現が可能です。こういったところで、Reduxの特性がけっこう活きます。
例えば、込み入った分岐条件でのみ現れる画面など。「どの状態やActionがあれば、この画面って再現できるんだっけ?」というところが、すぐにテストコードに落ちてきます。
特定制約時の再現が容易なため、テストファイルを細分化できます。表示を即座に確認できるため、ドキュメントとしても役に立つことがあります。この書きやすさが、ファイルを分割するところでかなり役立ってくるところがあって。それは普通のModuleも同じようなことです。
OpenAPI定義によるMockサーバーを、Cypressのintegrationテストにも活用しました。テストの書きやすい環境は、ライブラリやツール選択で明らかに差が出てきます。
また、これはあまり聞かない話かと思いますが、ワークフローの工夫もけっこう大切かなと思っています。タスク分解の段階で、書きやすいものがけっこう出てくるかなと思っています。タスクを本当に小さく細分化することで、テストはけっこう書きやすくなると思っています。
具体的な話で言うと、チケットを発行して、そのチケットの番号とともに要求仕様の空のテストを、一緒にコミットしてしまう。
あとから実装したときに、その仕様を満たしているときにスキップを外して。テストも書く。そういったことです。プルリクに概要を詳らかに書かなくても、どういった内容の機能が追加されたのかが伝わる状態が理想かと思っています。
ライブラリ側もテストツール群も、けっこう不得意や得意なところ、オーバースペックがあると思います。そのため、ライブラリの選択の際は、テスト観点を含め、バランスをとりながら選ぶ必要があります。
振り返りと今後についてです。READYFOR Elementsの再利用のところは、本当にうまくいっていました。もともと造りがしっかりしていたため、スタイルを書くようなこともありませんでした。しかし、一部検討余地があったところを紹介したいと思います。
例えば、この非制御Component+Formの前提です。そういったpropsの設計が、READYFOR Elementsの中に紛れていました。Form都合のpropsを剥がす、そういったリファクタリングに、想定以上の工数がかかりました。
また、制御Componentと比べると、非制御ComponentってReduxとちょっと相性がよくないんです。
とはいえ、こういった段階を踏んでいるため、ReactOnRailsで利用していた箇所としては非制御Componentのほうがベストでした。こういった背景があるので、移行に必要なコストで間違いありません。
READYFOR Elementsのような横断的なデザインシステムを構築するのであれば、制御Componentか非制御Componentかを選択できるようなI/Fを、初期設定からComponentに盛り込む余地があったんじゃないかとはちょっと思っています。
このReduxをこれからも使い続けるかです。公式にuseContextSelectorのようなAPIが入ろうとしているところですが、このReduxの代替となるものもけっこう出てきているので、状態管理ライブラリの選定ってけっこう悩みどころです。
これからReduxを使い続けるかは、都度検討かと思っています。READYFORは機能単位でNext.jsを分割しているため、状態管理も機能要件に合わせて選択できるのかなと思っています。
Reduxのテストの優位性は挙げたとおりですが、フロントに複雑な表示ロジックを置く場合は、導入のメリットがかなり多いかと思っています。
表示ロジックがフロントに寄る場合は採用するし、サーバーに寄る場合は不採用。それがいい切り分けかと思っています。
READYFORのフロントエンドの分離戦略は、スタートを切ったばかりです。またいつか、この続きを共有できることを楽しみにしていますということで、私の発表は以上です。ご清聴ありがとうございました。
関連タグ:
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.12
自分の人生にプラスに働く「イライラ」は才能 自分の強みや才能につながる“良いイライラ”を見分けるポイント
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.11
気づいたら借金、倒産して身ぐるみを剥がされる経営者 起業に「立派な動機」を求められる恐ろしさ
2024.11.11
「退職代行」を使われた管理職の本音と葛藤 メディアで話題、利用者が右肩上がり…企業が置かれている現状とは
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.12
先週まで元気だったのに、突然辞める「びっくり退職」 退職代行サービスの影響も?上司と部下の“すれ違い”が起きる原因
2024.11.14
よってたかってハイリスクのビジネスモデルに仕立て上げるステークホルダー 「社会的理由」が求められる時代の起業戦略