Next.js + NestJS で新サービスを作った話

はじめに

はじめまして、ユーフォリア開発部エンジニアの山本未知彦です!

このたび、ユーフォリアではJRFU(日本ラグビーフットボール協会)協力のもと、ラグビー選手の育成・強化のためのフィジカルデータベースシステムSCOTのリリースを行いました。(詳しくはこちらのプレスリリースをご覧下さい)

本記事では、SCOTのWebアプリケーション部分のアーキテクチャ紹介について、その技術選定理由と実際に開発してみて感じた良い点・気になった点をご紹介したいと思います。

SCOTのアーキテクチャ選定

まず技術選定の話をするに際して前提となるユーフォリア開発部の体制を説明します。当時、開発部にはエンジニアが2名しか在籍しておらず、SCOT開発に際しては業務委託の方々に協力いただいての開発となりました。そのため、技術選定においてはコードのレビューのしやすさと、仮にプロジェクト途中で人員の入れ替えが発生した場合のキャッチアップのしやすさといった点を特に重視したものとなっています。

フロントエンド

まずフロントエンドはNext.jsを用いたSSG(Static Site Generate)となっています。Next.jsはReactをベースにしたWebフロントエンドフレームワークです。今回利用しようと思っていたTypeScriptもサポートされていますし、利用はしていないですがSSRも容易に導入できたりします。現状、Reactをベースとしたフレームワークとしては一番勢いがあると思います。

とはいえ、Next.jsを利用した本質的な理由はこれらフレームワーク自体の恩恵というよりは、記法やファイル構成がフレームワーク側の制約によりある程度制限されることでした。業務委託の方にお任せするにあたって、誰が書いても記法が混沌とすることなく、また新たにジョインされた方でもNext.jsのドキュメントを追いさえすればキャッチアップの期間が短縮できることを期待しています。技術を選定するにあたって、実はフロントエンドについてほとんど悩むことなく決定しました。ReactでいくかVueにするかさえ決めてしまえば、現状Reactベースのフレームワークを使いたければNext.js一択で良いと思います。

Next.js選定の理由

  • 誰が書いても記法やファイル構成が混沌としにくい
  • ドキュメントや情報の充実
  • Reactベースのフレームワークとして一番勢いがある

バックエンド

一方のバックエンドですが、NestJSによるRESTfulAPIとなっています。NestJSはTypeScriptネイティブなサーバサイドフレームワークで、TypeScriptのデコレータ記法を用いた見通しの良さとDIコンテナの依存性解決による拡張性の高さが特徴です。さらにTypeORMというORMを併せて利用することにより、Entityからのマイグレーションファイル自動生成ができたりと何かと便利です。(余談ですが、個人的にはデコレータとDIにTypeScriptの型宣言も相まって、ちょうどSpringBootを書いている感覚に近いように思いました。)

この選定によりフロントエンドとバックエンドが共にTypeScriptで完結するというAll TypeScriptな環境を実現することができました。もちろん、ただTypeScriptを使いたいというだけであればExpressでも問題ないのですが、良くも悪くもExpressは非常に柔軟なフレームワークであるため、プロダクトごとに記法からファイル構成にいたるまで異なったものになりますし、油断すればプロダクト内でも記法ブレが発生することも危惧されます。そこで規約がしっかりしていて、なおかつ拡張性もあるNestJSに白羽の矢が立ちました。さらに付け加えるならば、NestJSもまたドキュメントが整っているのでフレームワーク自体を理解することも容易でした。

バックエンドの技術選定についてはかなり悩みました。Kotlin+SpringBootやGolangなど、TypeScriptに拘らずいくつかプロトタイプを作って検討しましたが、最終的にはフロントエンドと共通のTypeScriptであることに加えフレームワークの規約やエンジニア市場における人員確保のしやすさなどを考慮に入れた上でNestJSに決定しました。

NestJS選定の理由

  • TypeScriptネイティブなフレームワーク
  • ドキュメントが充実している
  • TypeORMを利用したDB操作の便利さ
  • 規約がExpressよりしっかりした上で拡張性もある

アーキテクチャ全体像

以上により決定したSCOTのアーキテクチャは以下のようになりました。

アーキテクチャとしては単純な構成となっていますが、フロントエンドとバックエンドは全てTypeScriptにと統一されていたり、加えてNext.jsとNestJSという比較的新しめのフレームワークを選定しているため、それらの点はちょっと攻めた構成になっているのではないかと思います。

また今回は詳しい説明は省きますが、インフラはECS Fargateにホストしており、CICD環境もコード三兄弟を使ったAWS全部乗せのような環境となっています。インフラ側の紹介もいつかしようと思いますのでお楽しみに。

実際に開発してみて

実際に開発をすすめてみて、良かった点・気になった点がありましたので、それらをご紹介したいと思います。

良かった点

  • サーバサイドTypeScriptが想像以上に良かった
  • All TypeScriptが開発チームにハマった

サーバサイドTypeScriptが想像以上に良かった

サーバサイドにおけるTypeScriptの相性が思った以上に良かったです。ある程度TypeScriptの型の重要性を期待していの選定でしたが、それがズバリと当たりました。実は実装中盤でパフォーマンス上の問題が発生し、一部のコアなロジックをインターフェースを保ったまま書き直すという作業が発生しました。その際に素のJSで書いていたらもっと苦労していたであろうことは想像に難くありません。型定義の煩わしさは所々で感じましたが、それを推してでもTypeScriptで書いて良かったと思っています。

All TypeScriptが開発チームにハマった

もともと開発はフロントエンドとサーバサイドをそれぞれ別のエンジニアが分担するスタイルで開始され、GitHubのリポジトリもフロントエンドとバックエンドでそれぞれ分けていました。それが開発が進むにつれ、徐々にお互いの開発チケットをとるようになりフロントエンドとバックエンドの垣根なく開発が進むようになりました。最終的にはリポジトリもマージされ、画面実装とAPI繋ぎこみまで一貫したPull Requestが作られたりするようになりました。このことによりフロントエンドとバックエンドのタスクの偏りが回避できたり、互いに共通の知識ベースで相談し合うことができるようになったりと、非常に柔軟な開発チームになることができました。

正直なところAll TypeScript環境を選定した時点で、ここまで柔軟な開発スタイルになると想定していたわけではありませんでした。こういった柔軟なスタイルで開発が進められている要因として、共通の言語を利用することによって気軽に互いのコードレビューをすることかできることや、Next.jsとNestJSの使いやすさによるところも大きく影響していると感じています。ただ、一番の要因として開発チームの協力が不可欠であり、単にこの構成にしたからといって必ずしも柔軟なチームになるということではないと考えています。その点、挑戦してくれたSCOT開発チームには感謝しています。

気になった点

  • TypeScriptはやはり記述量多い
  • TypeORMの届かない範囲があった
  • N〇〇t.jsフレームワークが多すぎる問題

TypeScriptはやはり記述量多い

どうしてもTypeScriptを使う以上は素のJavaScriptに慣れてしまっていると、多少冗長に感じてしまうことは避けられないと思います。もちろん、それを差し引いても、今回についてはTypeScriptを選択して良かったのですが、全ての場合にTypeScriptの方が優れているということではなく、特に少人数で規模が小さかったりリリースを最優先にしたい場合などはJavaScriptも十分選択肢に入るように思います。

TypeORMの届かない範囲があった

SCOTのプロダクト特性によるところも大きいとは思うのですが、ところどころでTypeORMでは解決しきれずにSQLを書く機会がありました。いくつかのテーブルをJOINしたり集計したりする際にはQueryBuilderというてもあるのですが、大抵はSQL書いていました。ただ、普通にORMapperとして使う分には申し分ないですし、マイグレーション周りの機能も良い感じなので、これが故にTypeORMを避けるといったことはありませんでした。

N〇〇t.jsフレームワークが多すぎる問題

これが冗談のようでいて、割と深刻な問題なのですがN〇〇t.jsフレームワークがとにかく多いです。今回、フロントエンドとバックエンドで名前がにすぎているため、エンジニア間で話していてもどちらの話をしているのかゴチャゴチャになりました。

さらに問題なのがGoogle検索で、”nestjs”と検索しても「もしかしてNext.js」と余計な心配をしてくれます。これ以外にも、Nuxt.jsもよく似ている上、日本語の情報が多いので紛れてしまって検索結果に紛れ込んでしまうこともありました。ここ最近はそれぞれのフレームワークがそれぞれに市民権を得てきたらしく”もしかして”を見ることは減ってきましたが、これ以上、N〇〇t.jsが増えないことを心から願って止みません。

おわりに

ここまでSCOTのWebアプリケーションのアーキテクチャを説明してきました。技術選定をした当初はAll TypeScriptに踏み切るのに躊躇い、他の選択もあったのではないかと考えることもありました。しかし、振り返ってみれば開発チームとの相性もよく、結果としてフロントエンドとバックエンドの垣根を越えて開発が進められる柔軟なチームとなることができました。今後はこのNext.js+NestJSによるAll TypeScript環境を新規プロダクト開発時の標準的な技術スタックとしていきたいと考えています。

この記事をお読みいただいた皆様も是非採用を検討されてはいかがでしょうか。

ユーフォリアは一緒に働く仲間を募集しています

ユーフォリアではスポーツを通して社会に役立ちたいと考えているエンジニアを募集しています。ご興味のある方はこちらまでご連絡おまちしております!

https://recruit.eu-phoria.jp/