GAミント至上主義

Web Monomaniacal Developer.

新規サービスのNestJS + Nuxt3のFull TypeScript環境とセカンドシステム症候群について

2022/8/15にシニアジョブで新規サービスをリリースしました。忘れないうちに振り返りとかをメモ。

まだ想定してる3割ぐらいの機能しかできておらず、これからやること山積みですが、とりあえず動きはするのでWEBサービスのリリースとして許容範囲かなと。

8/30追記: サービス自体については下記社長ブログを参照。 drome5.hatenablog.com

開発から1年を振り返る

新規WEBサービス開発は何度もやってますが、後述の初期要件の大きさもあり、間違いなくコードを人生で一番たくさん書いて学んだ1年間になりました(そのおかげで個人プロジェクトは停滞気味)。

GitHubのプルリクベースで開発しているので改めて振り返ってみると執筆時点の2022/8/25(以下の数字などはこの時点の)でちょうど一年経っている事に気づきました。

件数はマージしなかったのも少しはあるけど1,000超え。

スプレッドシートベースで求人情報とかユーザーとかの項目(≒DBのテーブルとカラム)の要件定義があったのでそこから始めたなぁと思い出しました。

コミット数だと7,887、

私個人に限ると3353コミットでした。

草はきれいに土日祝お休みしてるのがわかります

メンバー

エンジニアは私ともう一人(TypeScriptがっつりは初めて)の計2人、

デザインは最初外注したものの、2022/6にデザイナーさんにジョイン(一瞬で未経験のVue、Nuxt3やTailwindCSSを理解)いただいて1人。

あとSEO担当の方(肩書をなんと呼んでいいか分からない。全知全能)にもコミットしてもらっています。

その他プロマネ的なものは資本的にもプロダクトオーナーでもある社長。

技術選定について

基本的に私が使いたいのを社内メンバーに共有して、いいよってことで使ってる気がします。

いわゆる技術スタックで書くと下記のような感じ。

  • Nuxt3
  • NestJS
  • GraphQL (公開情報のqueryのみ)
  • TypeScript
  • TypeORM
  • PostgreSQL
  • Google Cloud (Cloud Run, Cloud SQL等)
  • Firebase (Google Cloudに含まれそうだけど、でかいので分ける)
  • Elasticsearch (Elastic Cloud)
  • TailwindCSS (PluginとしてTailwind Elementsと管理画面daisyUIを利用)

全部は無理なので大きな下記3つだけ書こうと思います

  • Nuxt3
  • NestJS
  • Firebase

Nuxt3について

私が入社する前から既存のシニアジョブはPHPのLarabel + Vueで、 senior-job.co.jp

自社メディアではNuxt.js(2 + Composition API

を使っていたという前提があり、また私もVueは前前職から仕事で使っていたので フロントエンドにVue系を使用するのは慣れと流れが大きいです。

そして、ちょうど開発当初10月にNuxt3がパブリックベータとなりました。

Nuxt - Introducing Nuxt 3 Beta

正直いつリリースされるかも分からないものを使うのはかなり怖かったんですが、

  • TypeScriptとの相性バツグン(Nuxt.js 2とComposition APIもいろいろストレス)
  • Viteだし早いし開発体験めっちゃいい、auto Importやばっ
  • 開発メンバー優秀すぎる・・・しかもantfuさんまで参加してるし絶対大丈夫
  • まあ、なんかあったら自分でなんとかすればいいや

ってことで勢いでいって、ここまで来てます。

今となっては2を選んでいたらこんな楽しく開発はできてないし、 Nuxt3の機能不足やバグと戦いながらできあがっていくのを眺められて良かったなぁと思ってます。

特にメイン開発者のpi0さんとdanielroeさんの2人強すぎ。

お世話になっているので僅かながらお小遣いの範囲で毎月Nuxtにスポンサーしたりもしました。

問題としてはまだ正式リリースされてないことぐらい。

セキュリティ上の設計として、認証はユーザーとサーバーで直接FirebaseのJWTを使って行うだけにしており、Nuxt3には認証キー的な機密情報は持たせないようにはしています。

その他、Nuxt3に関しては、内部で使っているWEBサーバーNitroやライブラリも、unjsプロジェクトとして開発、公開してたり、2からの移行をサポートするBridgeも同時開発してたり書きたいことはたくさんあるんですがまた今度。

NestJSについて

NestJSはサーバーサイドJavaScriptフレームワークです。もちろんTypeScript対応。 nestjs.com

同じサーバーサイドフレームワークといいつつも、LarabelやRailsDjangoとは全然違い Express(デフォルトのWebサーバー、Fastifyもあり)や TypeORM(ORM、もちろんMongoDB用とか他の選択肢もたくさんもあり)や Appolo(GraphQL)など 既存の有名Nodeライブラリをいい感じにまとめて使いやすくしてくれるフレームワークです。 あとドキュメントがめっちゃいい。

最初の経緯としてはpotato4dさんとお話をしたときに名前は聞いたことがあり、 qiita.com 当然LINEや engineering.linecorp.com メルカリも使ってるし、 メルカリ Shops での NestJS を使った GraphQL Server の実装 | メルカリエンジニアリング 日本の実績もあるんですが、 一番の目的はフロントエンドとサーバーサイドで言語をTypeScript揃えたい!でした。

一度Larabel でAPI、Nuxt.js v2でサイト作ったんですが、どちらも一人でやると脳内の切り替えがつらすぎる・・・。

特にTypeScriptに慣れているのもあり、いろいろ便利(...とか?とか??とかJSONとの相性とか)なのでPHP側がつらすぎでした。

また当然ながらTypeScriptの型を共有できるので、VSCodeの補完やバグの少なさなど開発速度にも影響します。

特にGraphQLがよかった。これについては詳しいのを別で書こうと思っています。

開発人数も大きな理由になります。基本2人しかいないので、サーバー、フロント両方やらざるを得ないので上記メリットが大きくなります。

大きな会社でフロントとサーバーをそれぞれ複数人チームで分けれられる体制ならデメリットにもなりうる(情報の少なさ、採用とか)気がします。

Firebase

認証とストレージ、ホスティングに使用しています。

firebase.google.com firebase.google.com

認証は自社専用管理画面はドメイン制限したGoogle認証、他はメールアドレス、パスワードを使ってます。

ハッシュ化するとはいえ自分でパスワード周りのロジック書きたくないし、保守もしたくない、考えたくもない。 とくにJWTとかどうすりゃいいんだっていう悩みを解決してくれました。

CookieにJWT保存とか絶対やりたくないので、毎回Firebaseのライブラリの処理でリクエストのたびにtokenを取得しています

StorageはまあCloud Storageのただのラッパーなんですが、同じライブラリで使えるので便利です。

ホスティングですが、Nuxt3がFireabse Functionsに早い段階で対応しており、試してみたら全く問題なく動いたのでそのまま管理画面に使っています。 Nuxt 3 - Firebase Hosting

料金もCloud Runより安いはずなのでクソ安いはず。

Functionsだと機能不足や初回起動の遅さとか、謎にエラーが出て動かないときがあったり、いろいろCloud Runに比べると劣ってしまうわけですが、 自社管理画面のような用途であればほぼ困ることはなさそうです。

セカンドシステム症候群との戦い

もう一つの主題はこれ。

今回の新規サービスはシニアジョブにおいて、まさに2つ目の同じようなシステム(要件的にもビジネス的にもいろいろ違うけど長くなるので今回は割愛)です。 senior-job.co.jp

恥ずかしながら名著でもある「人月の神話」をまだ読んだことがなく、ブログなどで断片的に知っているだけでした。

セカンドシステム症候群もたしかTwitterかなんかで見かけて、↓こういう記事で詳しく知って、今の状況まさにこれじゃん・・となりました。 もしかしたら以前も読んだけど課題を抱えてる状態の今だから頭に入ってきただけの説もあり。 人月の神話 | blog.tai2.net

端的に引用するならばこれ

一般的に、二度目のシステムはデザインし過ぎる傾向がある。このとき、最初のシステムデザインでは注意深く外したアイデアと装飾を使う。結果はオビディウスの言ったように(ちりも積もれば*)「山」となる。 第11回:慣れてくると、やりすぎるのが人の常|本気で読み解く”人月の神話”(第5章「セカンドシステム症候群」) - GiXo Ltd.

システム開発に限らず創作とかにもありがちかなぁ事象かなぁと改めて思う。

株式会社シニアジョブは人材紹介、人材派遣を2016年から上記システムとともに歩んできたわけなので、 掲載企業からしたらこういう情報が必要とか、シニアの求職者はこういう情報絶対聞いてくるとかビジネス知見が大量にあるわけです。

で、そんな状態で2つ目を作ろうとしたので、開発前からDBのテーブルやカラムとなる要件定義がスプレッドシートですごいことになり、 当然DBの構築やそれに伴う保存、読み出しコードもすごい量になり、DB周りの準備だけでだいぶ時間を使ってしまいました。

今となっては、要件定義済みのDB全部をつくらず、どこかに絞ってDB ー サーバー ー フロント側までの一連の流れを、まずは一つでも早急に完成させるべきだったと思っています。

が、言い訳として開発初期にはまだNuxt3が公開されてなかった公開直後であったということや、そもそも初めてのNestJSやTypeORMにも不慣れでその習熟期間にもなってたということもあります。

環境に慣れてきた3,4ヶ月後ぐらいには、ある程度の雑さが許される自社用の管理画面で一連の流れを作ることができ、そこからやるべきこともはっきり見えてきて開発スピードが上がっていったような印象があります。

ハードウェアやミドルウェア構成的な面ではなるべく使わないようにして、未だに最低限のDB(PostgreSQL)とElasticsearchのみで、 タスクキュー周りやキャッシュ周り(Redisとか)は使わずになんとか動かしています

まずはどんな小さくてもいろいろ足りなくてもいいから動いて触れるようにする、大事。