技術のトレンドと開発テクニックの知見を、無料で公開します!
技術のトレンドと開発テクニックの知見を、無料で公開します!
いかに無駄な努力をせず、効果的にトレンドに沿ったアプリ開発ができるかを研究してきました。
この記事は、定期的にトレンドに沿って更新していこうと思います。
自分が一番知見のある、フロントエンドの分野中心に見解を述べたいと思います。
結論から言うと、
React, Next.js, Typescript, Tailwind, react-query, prettier, Stylelint, auth0, tRPC, Prisma, playwright, vscode, github actions, PostgreSQL, Terraform, Flutter
これらの技術スタックが今後ますます流行り、開発体験の良いものになると思います。
https://reactjs.org/
最初にReactから述べます。数年前は、React vs Vueの論争がありましたが、Reactが勝者に落ち着いたかと思います。
これは、Google Trends や npm trends、その他エコシステムの充実度とその加速度から見て明らかだと思います。近年ますます、型をちゃんとあてて、堅牢に作っていく重要性が見直されてきていますが、ReactはVueと比べ、Typescriptの相性が良いのも大きな理由の一つです。
また、VueはコミュニティベースのOSSであるため、開発の進捗が悪かったり、そもそも開発のインセンティブや組織が弱いです。また、コミット履歴見ると、Vue(Nuxt.jsもそうだが)は少数の天才に依存している状態であると思います。
いけている先進的なライブラリも、Reactファーストに作られていることも大きな理由の一つです。エコシステムの大きさと質が段違いであると思います。
Google Trends で検索すると、Reactは英語圏中心に圧倒的人気である一方、Vueは中国メインで、あとは、日本みたいな人気状況です。
Reactは、今後IT人材が爆発的に増えるインドでもインタレストが高いことからも、今後の人気も決定づけるでしょう。何より、アメリカで人気であると言うことは、絶大な影響力があります。
https://nextjs.org/
Next.jsNext.js vs Nuxt.js の論争も数年前までありましたが、
これも、企業がバックにいるかいないかがとても大きく、Nuxt.jsの開発進捗に比べ、Next.jsの開発スピードが早く、機能や品質のアドバンテージが多いです。
また、ホスティング先にVercelを用いることで、デプロイが簡単に出来たり、画像の配信の最適化が出来ます。VercelとGithubを連携させることで、PRのコードごとに自動的にデプロイし、プレビューリンクを生成することができます。これによって、local環境でBuildしなくとも、PRのレビューができます。
そのプレビュー環境では、デザイナー含む開発メンバーから、コメントでフィードバックをもらうことができるので、開発体験が上がります。
また、Buildが非常に速いです。
さらに、Rustで書かれた、Turbopack( https://turbo.build/pack )でさらにBuildの高速化されます。
これもVercelのプロジェクトであり、技術力の高さが伺えます。
viteやcreate-react-appなどもありますが、あえてそれらを使用する理由はなく、Next.jsだけ見てれば良いと思います。
Next.jsはもはやSSRのためのツールではなく、多くのフロントエンドの開発体験を上げることに貢献します。
Typescript
型安全を強く意識した方が良いです。
コードが肥大化すればするほど、型があることによって、エラーを未然に防ぐことができます。
めんどくさいし、学習コストもあるかもしれないが、型の素晴らしさに感動する瞬間が来ると思います。
anyの型を許容しないくらいのスタンスで良くて、かけたコストに対して十分メリットを享受できます。
https://tailwindcss.com/
TailwindReactやVueなどのコンポーネント指向のUIライブラリの登場で、美しくコンポーネントを作ろうとするとCSSがコンポーネントに依存するため、CSS設計はより重要ではなくなってきています。
何より、Tailwindは視認性が良いです。templateを見るだけで、どの要素にどんなstyleがあたっているか、レスポンシブ対応も含め直感的に分かります。
これが今までのようにCSSと分離されていると、ファイルを何度も往復する必要があったり、また、直感的なCSSのクラス名を考えるコストが生じます。
Tailwindを使うと、ほぼCSS設計しなくて良いので、それらのコストを削減でき、CSSが属人化するという問題も避けることができます。
Tailwindを使わない場合、PostCSSを推奨します。
近年人気のTailwindやその他UIフレームワークなども多くがPostCSSを採用していることからも、信頼性がありますし、導入コストが非常に低いためです。
https://tanstack.com/query/latest
react-query(TanStack Queryに名前が変わりました。)TanStack Queryを使うと、ステートマネージメントと、ローディングの処理、エラーハンドリングが驚くほど簡単になります。
https://prettier.io/
PrettierESLintだけでなく、Prettierも併用して入れた方が良いです。
eslint --fixだけでもformatの修正は行われますが、
それに対応していないところをprettierがformatをかけてくれます。
eslint-config-prettierを用いると、format修正でPrettierとESLintとの間でコンフリクト起きている箇所を解消してくれます。
https://stylelint.io/
StylelintCSSのLinterです。次世代CSS構文やAltCSSの解析も可能です。
CSS構文エラーやコーディングスタイル違反の発見、スタイルの自動修正が可能です。
https://auth0.com/
auth0今はユーザー認証に、cookieではなくて、JWT使うのが当たり前になってきていると思います。
また、セキュリティが関わってくる大事な認証部分は、基本自前で立てるべきではないと考えています。
auth0かfirebase auth、cognitoが候補になりますが、auth0が柔軟性とリッチさが頭一つ分以上に違うと思います。
対応しているプロバイダーの数や、2段階認証、そしてその2段階認証先の選択数などアドバンテージが多いです。
https://trpc.io/
tRPCtRPCは素晴らしいです。Web開発で、Nest.js, apollo-server, Express.jsで迷っているのであれば、tRPCを推奨します。
tRPCは、GraphQLなどを使わず、スキーマやコード生成なしに、完全にタイプセーフなAPIを簡単に構築し、利用することを可能にします。
これで、ますます、TSでフロントエンドとバックエンドを書いていくプロジェクトが増えていくと思います。
こういった最新のツールも、ReactやNext.jsファーストでDocumentやサンプルコードが作られていることが多いので、ますますそれらライブラリを使用する動機は高まると思います。 https://trpc.io/docs/nextjs
https://www.prisma.io/
PrismaSequelize、TypeORMなどのSQLクエリビルダなど従来のORMの代替するものです。
他のORMと比べ、より型安全に書けますし、ドキュメントが豊富です。
また、カスタマイズ可能なSQLデータベースマイグレーションを自動的に生成し、移行ファイルを生成せずにデータベースに変更を加えることができます。
https://www.postgresql.org/
PostgreSQLAurora対抗のGoogle Cloud新サービス AlloyDB for PostgreSQLがリリースされたのも大きな理由です。
ちょっと前に流行っていたFirestoreは、多対多のリレーションが増えるほど、データを複製するなどして管理しきれなく詰んで行くので、中規模以上のプロダクトにおいては、メインDBとしては使わない方が良いです。仮に、データを複製しない方法でそれができてるように見えても、セキュリティに問題を抱えています。(多対多のリレーションだけでなくとも、セキュリティを意識すると、それ相応のセキュリティルールを書く必要があるため、実装コストはたいして変わらないです。)
仮にFirestoreを使うのであれば、階層構造を意識し一対多のリレーションを作ると良いです。もともとそういう風に設計されているので、クエリーが簡素になりますし、セキュリティルールも当てやすくなります。
なんだかんだ、普通のRDBの偉大さに気づきます。
PostgreSQLはMySQLより、より柔軟で、速いです。
NoSQLは単調なデータでクエリー速度が大事なものにのみ使用するくらいのスタンスで良いと思います。
https://playwright.dev/
PlaywrightE2Eテストは、競合のCypressよりPlaywrightを推奨します。
Playwrightでは、ユーザー操作を記録し、そのコードを自動生成する機能があります。
何より、microsoftのossであることが強いです。
CypressはCIで回すと、よくタイムアウト問題が生じ、体験が良くなかったです。
https://code.visualstudio.com/
vscodeエディタはvscodeを推奨します。なぜならextensionが豊富で、質の良いものが多いためです。
terminalもgitの管理もこれ一つで出来ます。
https://docs.github.com/en/actions
github actionsCIはgithub actionsを推奨します。
新規でCircleCIをあえて使う理由はないと思います。
https://www.terraform.io/
Terraformクラウドのインフラを、コードで記述することにより自動で構築できます。Terraformを利用することでオペレーションミスが無くなるほか、複数環境でコードを再利用することで効率化を図ることが出来ます。
https://flutter.dev/
FlutterほとんどのネイティブアプリはFlutterで良いと思います。React Nativeはサードパーティの集合体で、meta(facebook)がちゃんと管理しきっているわけではなく、不毛なエラーで消耗することが多いと思います。
一方、FlutterはGoogleがちゃんと組織的に運営しており、必要なウィジェット(コンポーネントに相当)の品質も高く、種類も非常に豊富です。コミュニティの規模も大きく、アクティビィも非常に高いです。
次に、フロントエンドを中心に開発の細かいテクニックを紹介します。
-
Testing Trophyを意識して、フロントエンドのテストを書きましょう
https://kentcdodds.com/blog/the-testing-trophy-and-testing-classifications
この画像は、reactで一番よく使われているtestライブラリ react-testing-library の作者であるKent C. Dodds氏によって作成されました。
彼は、バックエンドと同じ文脈でフロントエンドでもunitテストに重きを置かれている現状を嘆き、このTesting Trophyを作りました。
各テストの書くべき総量を、画像のようにトロフィーの体積の比率で表しています。体積の大きい箇所ほど、より多くのテストを書くべきと言う考えを表現しています。
フロントエンドのテストはコンポーネント単体の動作保証よりかは、コンポーネント同士の相互作用、すなわちソフトウェアとして動作が保証されているかと言う観点がとても大事です。
より多くのintegraitonテストを書くことによって、よりソフトウェアとしての動作を保証することができます。
今は、APIサーバーを立てなくとも、Mock Service Workerというライブラリがあり、サービスワーカーの機能を使って、超簡単にモックAPIが作れます。 https://mswjs.io
Kent氏も、react-testing-libraryとmock Service Workerを使って、より多くのintegraitonテストを書くことを強く推奨しています。
CIでテストする際も、フロントエンドで完結するため、バックエンドを意識するコストが低減します。
フロントエンドのテスト方針を理想で言うと、ベースの型定義をしっかり書いて、unitテストはjestを用いて、再利用が想定された共通関数のようなモジュールのみに絞り、integraitonテストはreact-testing-libraryを用いてちゃんと書いて、E2Eテストは、playwright用いて、抽象度高く、より少ないテストコードでより多く網羅できるテストを意識し、ゆるく書いていく、で良いと思います。 -
コンポーネント設計について
基本的に、メジャーなUIフレームワークのコンポーネントの設計を参考にしながら、コンポーネントを作ると良いです。
それらのコンポーネントの引数や粒度とかを参考にすると、必然的に、汎用化はしやすくなります。
Reactで一番人気のある、Ant Designはかなり使いやすいので、Ant Designのコンポーネントインターフェースがおすすめです。
https://ant.design/components/overview/ -
Atomic Designに関して
基本的に、否定派です。
Google Trendや海外の記事やOSS見ても、日本くらいでしか流行っていない印象です。
実際に、著名なUIフレームワークのコンポーネントのコードを見ても、Atomic Designで構築していないことから、海外の一流のフロントエンジニアはそういった粒度で考えていないことがわかります。
Atomic Designだと、5層になるので、例えば、SSRで一番上のpageのファイルからデータを流すのであれば、バケツリレーが長くなり、冗長すぎて実装コストが増大します。
基本的に以下の三層構造で十分だと考えます。
・親(layoutや権限チェック、data fetchの層)
・子(孫のコンポーネントを束ねて機能として意味を持たせる層。データフローが冗長であれば、この層でdata fetchして状態を持っても良い。)
・孫(UIフレームワークでいう、modal, tag, paginationなどのコンポーネントの層。) -
データのフェッチのテクニック
データのフェッチでは、POSTやUPDATEでデータの更新があった場合、再度、データをフェッチするみたいなロジックを描いているケースもありますが、コンポーネントとステートの性質を生かして、リクエストの結果が200okであれば、再度フェッチして更新するのではなく、POST / UPDATE した値でstateを更新して、再レンダーしましょう。
そうすることによって、余計なAPIリクエストしなくて済んで、APIの負荷が下がりますし、ユーザーに対して、レンダーの速度も早くなります。 -
多言語化のテクニック
文章をkeyにすると、templateの視認性が上がります。多言語化のkeyをドット繋がりの変数にしていると、今どこのtemplateを編集しているかと困惑することが多いと思います。
英語や日本語の文章をkeyにすることで、多言語対応していない時と同等に近い開発体験が得られます。変数名が文章になるので、わかりやすい変数名を考えるコストも削減できます。 -
ブランチの切り方
ブランチの切り方は、main -> staging -> develop -> feature or hotfix が一般的でベターだと思います。 -
技術的負債に対して
技術的負債をリストアップし、優先度つけてFixすることは大事です。 -
コード規約に関して
コード規約をreadmeなどに書いて、PR化することによって、チームの合意形成のもと、コードの設計の認識の統一や、気軽に技術的な品質を向上させる環境を作ることができます。
メンバー全員からPRのAprroveを貰ったら、それが規約になって、今後のPRレビューの対象になるという世界観です。新しく開発メンバーに加わる方も、その規約に見ることで、スムーズに開発にコミットすることが可能になります。 -
状態管理に関して
基本的には、TanStack Queryで状態管理するのが良いですが、もしReactでVuexみたいにライトに状態管理したいのであれば、Zustandを推奨します。
Reactのcontextを使ったパターンでは、状態に更新があったときに、再レンダーする必要がありパフォーマンスが落ちるため、大規模な状態管理には向いてないです。 -
バリデーションに関して
バリデーションはTypescriptファーストのzodを推奨します。https://github.com/colinhacks/zod
バックエンドにtRPCを採用するのであれば、フロントエンドのformと同じzodのバリデーションを利用することができます。 -
Buildしたコードのdeploy先に関して
Hostingサービスを積極的に使うことを推奨します。著名なものであれば、NetlifyやFirebase Hostng, Vercelがあります。
簡単にホスティング出来ますし、CDNやPRのプレビューリンクの機能などが備わっています。
Next.jsを使うのであれば、Vercelで良いと思います。 -
Storybook使い方
Storybookは、UIフレームワークのDocumentのように意識して作ると良いと思います。
そうすることによって、エンジニアがどういった引数で、どういった挙動になるかが把握しやすく、開発効率が高まります。何でもかんでもコンポーネントをStorybookに載せれば良いと言うわけではなく、例えば以下リンク
https://ant.design/components/overview/
のサイドバーにあるような粒度でコンポーネントを作ることで、UIフレームワークのDocumentようなstorybookを作成することができます。ですので、StorybookのDocumentの美しさと、コンポーネント設計の美しさは表裏一体の関係です。
そもそもそういった意図でStorybookが作られたのでは、とも思っています。 -
チーム開発のメンタリティ
誠実さと思いやりを持って開発に取り組むことが、チームとして貢献できることにつながると考えています。 -
コンポーネントのデータフローに関して
汎用化したコンポーネントなどを束ねてページを構成するコンポーネントでデータフェッチして、それら子のコンポーネントにデータを流すで良いと思います。(あるいは、pageディレクトリのファイルからデータフェッチしても良いが、SSRできるメリット以外は、冗長になるだけです。)
汎用化したコンポーネント内で、データフェッチしたり、グローバルステートからデータを読み取ったりするなどの構成もありますが、やはり、引数でそれらを受け取った方が、綺麗にコンポーネントを汎用化でき、データの依存関係なく設計できます。 -
moment.jsではなく、軽量なday.jsを使いましょう https://github.com/iamkun/dayjs
少なくとも、date系のモジュールをスクラッチして車輪の再発明はしないようにしましょう。
ドキュメントも充実しているので、積極的に、day.jsを使いましょう。 -
ChatGPTを利用しましょう https://openai.com/blog/chatgpt/
かなり専門性の高い箇所でない限り、有益なサンプルコードを提供してくれます。
しかもそれは、検索しても出てこないような、codeのアイディアであることも多いです。 -
React Hook Formを使いましょう https://react-hook-form.com/
Formのハンドリングがしやすくなります。 -
nullかundefinedか
undefinedが自動的に設定されることを考慮すると、原則undefinedに寄せる方がルールの統一がしやすくなると思います。
ただし、DOM系のAPIではnullが使用されることもあるので、その場合は柔軟に対応しましょう。
公式のwikiに書かれてある、TypeScript開発チームのコーディングガイドでは、nullでなく、undefinedが推奨されています。
https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines#null-and-undefined -
react-useを利用しましょう https://github.com/streamich/react-use
react-useに存在するのHooksであれば、車輪の再発明してHooksを作るよりかは、積極的にreact-useを使いましょう。使い方もわかりやすく書かれてますし、そもそもの品質と信頼性が高いです。 -
CIの対象とタイミング
developブランチへのマージのPRでは、lintとformatのチェックをするCIを回しましょう。
ちゃんとBuildが通っているかもCIでチェックしましょう。(Pushの時に、hookでチェックするパターンもありますが、冗長なので、CIの方でチェックできてれば良いです。) -
エラー通知の仕込みと、そのテクニック
Sentryでエラー通知がslackやemailで来るようにしましょう。
また、リロード時や認証時に、uidを仕込むようにしよう。
そうすることによって、より、バグの特定がしやすくなります。
環境tag(production, staging, development)も仕込むことで、通知されるslackのチャンネルを分けることができたり、sentry側のdashboardでフィルタリングすることが出来ます。
基本的に例外エラーが通知されるので、try-catchでエラーハンドリングしている箇所で、そのエラーを通知したい場合は、catch内で throw new Error() すると良いです。 -
SPAかSSRかの基準
TwitterなどのSNSで商品の画像も表示させたいのであれば、SSRしましょう。
それ以外は、初期の表示速度が重要であれば、SSRする理由になるでしょう。 -
質の高い情報を集める方法
Googleの検索は英語で検索するだけでなく、ロケーションの設定をUSにして検索した方が、情報の質が違います。
USに本社があるから、USの検索エンジンが最新のものであるのは至極当然です。
以下リンクでus版で検索することができます。
https://www.google.com/?gl=us&hl=en&pws=0&gws_rd=cr -
if文でネストが深くなる
早期リターンを意識しましょう。 -
開発のトレンドを把握する方法
npm trendsでダウンロード数を比較したり、githubのstarの数で人気度を確認することができます。また、githubのPRやissueの数で、開発のアクティビティが図れます。githubのコミット履歴を見て、開発が今でも盛んか、止まっているかなど把握することが出来ます。開発が今でも続いているかは重要な要素で、バグが起きた際に、対応されなくなって、困るからです。 -
APIリクエストのテクニック
APIリクエストの順番が大事な箇所以外は、Promise.allでAPIリクエストを並列処理して、速度の向上を目指しましょう。 -
Google Tag Manager(以下GTM)を仕込みましょう
これまでのGoogle Analyticsでは、収集したいイベントがあれば、ソースコードに編集を加える必要があったり、その数が多ければ、コードの見通しが悪くなったりする問題がありました。
GTMを使うことで、それらはGTM側で制御することが可能になります。
GTMで収集したログを、Google Analyticsを見て、デザインを改善の提案が出来るエンジニアは価値が高まります。 -
JWTのトークンのハンドリングに関して
最初の認証時にGETしたJWTのトークンをlocalstorageに保存し、そのトークンのプロパティに期限を扱うexpirationのようなものがあるので、APIリクエスト時にそれの期限が切れていれば、再度tokenを取りに行くという処理を書けば、上手くハンドリング出来ます。 -
interfaceとtypeどちらを使うべきか
interfaceで出来ることはほぼtypeで表現できますし、interfaceだと知らないうちに型が拡張されていたということが生じるため、ほとんどのケースはtypeで良いです。
今後のエンジニアリングに関して
今後の世界はますますAI駆動になっていくので、AIを必ず意識した方が良いです。
人々はより多様化し、コミュニティが複数でき、web3によって、よりこの動きが解放されていくだろうと思っています。
プログラミング言語で言うと、
TypescriptとRustとPythonに注力すると良いです。
Typescritpは、今回述べた内容からは自明であると思います。
RustはCやC++の低レイヤーな言語を代替可能で、より開発体験をよくするものです。
ブロックチェーンでも、技術力があって、注目されているプロジェクトでは、近年ますますRustで書かれていることが多いです。
最近では、低レイヤーなパフォーマンスが重要な処理だけでなく、通常のAPIとしても採用されているケースが増えてきているように思います。
PythonはAIやビッグデータ処理の需要で、人気を維持していくと思います。
最後に
良かったと思ったら、いいね❤️していただけると嬉しいです!
Discussion
有益な記事、ありがとうございます!