プロダクトにNext.jsとGoを採用した理由と背景

はじめに

こんにちは!エンジニアの柿森です。新規プロジェクトを担当しております。
ANDPADではマイクロサービス開発を推進しており、新規プロジェクトは個別に技術選定を行い、既存システムとAPI経由で連携します。
また、マイクロサービス基盤はk8sで構築されており、死活監視やログ収集もよしなにやってくれる環境が整っております。
新規プロジェクトを立ち上げで、k8s上に乗せることを前提に技術選定を行いました。
技術選定を行うにあたって検討したポイントと、採用した技術について話していきたいと思います。(あくまで筆者個人の考えです。)

採用した技術スタックの概要

フロントエンドはBlitz-jsを参考にNext.jsを採用。
バックエンドはGo + gRPCを採用。

技術選定の方針

大きな方針としては一般的な考えを踏襲しています。

  • ドキュメントがしっかりしており、GitHubのStarがそれなりにある
  • メンテが継続されている
  • 使っていてワクワクするもの

Starの数は言語や分野によって異なるので、絶対値で判断できませんが、類似ツールと比較して突出して少ないものは避けるようにしています。 ドキュメントも同様です。少ないものは避けています。
メンテに関しては言語の最新バージョンに対応していない、IssueやPRが放置されている、mainブランチの最終更新が1年以上行われていないものは避けています。
Star数が多くても最近更新されていないツールなどもありますので要注意です。一方で、成熟しきって変更が減っているものもあるので、判断が難しいです。

一方で、社内ですでに使われているかどうかは、重要視していません。
自分が本当に良い技術だと信じていれば、社内勉強会を開催して社内の利用者を増やせば良いですし、学んでいく意思を持っている組織だと思っています。

採用した技術スタック

Next.js + TypeScript

最終的にはNext.jsを使うことに決定しましたが、当初はBlitz-jsというフルスタックなフレームワークに着目しておりました。
Blitz-jsはNext.jsを中心としたOSSスタックであり、TypeScript版Railsのようなもので、DBアクセスからフロントまでサポートしています。 とても良くできており、ドキュメントも非常に親切です。

しかし、Blitz-jsはbetaであること、Next.jsをforkし、別の道を歩むことが懸念です。
このような背景で、Blitz-jsの技術スタックを参考にしつつ、Next.jsを採用することにしました。

Next.jsをBFF兼html配信サーバとして使う

Next.jsは大きく分けて2つの使い方があります。

  • Next.jsをサーバとして動かして使う
  • Next.jsを使ってhtmlファイル + jsを生成し、S3やAmplify、Firebaseに配置する

Blitz-jsではNext.jsをサーバとして起動し、DBアクセスからWebAPI提供、html配信まで行います。
本プロジェクトでは、BFF兼htlm配信サーバとしてNext.jsを使うことにしました。
一方で、DBアクセスはGo言語で別サーバとして実装することにしました。理由は後述します。

BFFとhtml配信サーバを兼ねることで、さまざまなメリットが得られます。

  • BFFをフロントエンド開発者が実装でき、フロントjsで欲しいAPIを自身で実装できる
  • BFFとhtmlで同じ言語・モデルクラスを使用できる

その代わりデメリットもあります。

  • サーバとして動かすので障害点や監視対象が増える
  • htmlの配信とBFFを同じサーバが担うので、負荷が集中する可能性がある

フロントjsとBFFはWebAPIで通信するので、負荷などの課題が出てきたら切り離せます。よって、想定のデメリットは回避できると判断し、同じサーバに担わせることにしました。

プロダクトが成長し、負荷が課題になったら分離します。このように、いつでも分離できるのもこの構成の良いところです。

SSR?SSG?

Next.jsといえば、サーバサイドレンダリング(SSR)みたいな風潮がありますが、最近は静的サイト生成(SSG)のサポートが手厚くなっています。 それぞれの簡単な説明は以下の通りです。

  • SSRはアクセスが来るとサーバでページを生成して返却する仕組み
  • SSGはNext.jsのビルド時にページを生成しておく仕組み

SSGの方がサーバへの負荷も軽いし、レスポンスも早いのですが、ANDPADのような業務アプリケーションだと話が変わってきます。
例えば、プロフィール情報はユーザによって表示内容が異なるため、SSGのようにあらかじめプロフィールページを作成しておくことはできません。 (全ユーザのプロフィールページを生成しておけば可能です。が、現実的ではないですね。)

Next.jsは、ページごとにSSRを使うのかSSGを使うのか選べますので、ビルド時に表示内容が決定しているページはSSGを、アクセス時に表示内容が決まるページにはSSRを採用することにしました。

Goをバックエンドに採用したわけ

ANDPADではサービス間通信の一部にgRPCが取り入れられています。
このプロジェクトでもgRPC-APIを用意しておきたかったので、Next.jsとバックエンドを分離しました。

gRPCは言語に限らないものなので、対応言語であればなんでもOKですが、今回Goを選択した理由は以下になります。

  • gRPCでstream処理を行う時に、goroutineで簡単に並列処理を実装できる
  • コンテナと非常に相性が良い。バイナリが生成されるのでコンテナサイズが小さくなる
  • 自身の含めて社内に知見者が多い上に、心強いアドバイザーがいらっしゃる

まとめ

今回は筆者が入社してから技術選定で選んだ言語やフレームワークの紹介と、なぜ選択したかの背景についてまとめてみました。
言語とフレームワークを選定した後も、APIクライアント、ORM、CI、Linterなど、技術選定は続いていきます。
全ての選定において、一番初めに述べた3つを心に留めて選定しています。

  • ドキュメントがしっかりしており、GitHubのStarがそれなりにある
  • メンテが継続されている
  • 使っていてワクワクするもの

最後に

ここまで読んでいただいて察したかと思いますが、本プロジェクトに居るアンドパッドエンジニアは私一人です...
私を助ける気持ちでカジュアル面談や採用へのエントリーをしていただけると泣いて喜びます!よろしくお願いしまぁぁす!

engineer.andpad.co.jp