技術選定 - シーシャアプリ
※単なるメモです。
toC向けシーシャアプリをリリースするにあたり、選択した技術スタックの解説です。
シーシャアプリ作成の経緯・前提条件・観点・理由など惜しみなく述べる。
アプリ作成の経緯
※ 個人的な話になるので、飛ばしたい人は飛ばしてください
主に5つの理由がある。
- 一気通貫してweb開発の全体像を把握したい
- 最新技術に触れてみたい(特にコード面で)
- 人に教えることで技術への理解を深めたい
- できれば、副収入がほしい
人間関係は良好だし、先輩は丁寧に教えてくれるし、新人にも関わらず大きな案件に参画させていただいている。
しかし、インフラ以外の面で使用している技術が古いため、より最新技術に触れてみたい。
インフラはAWSを触っているものの、プログラムはPHP(ZendFramwork)や素のJSを未だに使用している。
よって、最新技術を利用したアプリを作る。
その他の理由に関しては、そのままの理由なので割愛。
前提条件
toC向けシーシャアプリ作成における前提条件は以下。
・β版として最低限の機能を持ったアプリを3ヶ月以内にリリースするので、スピード感重視(モチベ維持のため
・toC向けサービスとしてリリースする
・参画人数は多くて3人
観点
① 解決したい課題は何か?
② 開発の発端(バックグランド)は?
③ シーシャ市場の動向は?
①解決したい課題は何か?
シーシャ市場はスタートアップ的に流行り出したことから、地域に根を張っているマイナーなシーシャや個人経営のシーシャが多い。そのため、そもそも店舗の情報がGoogle MapやWebサイトに掲載されていないことが多い。
また、掲載されていても時間あたりの料金やテーブルチャージなど不明瞭な情報が多い。
シンプルに情報がわかりやすく伝えられていないという現状がある。正確な
・地図情報(シーシャがある場所
・店舗情報(料金・時間・営業時間・混雑具合・フレーバー
を伝えられるようにしたい。
また、そこから広がってシーシャ店のDX化(予約や広報)などもできるようにすれば、シーシャを利用しやすくなるだろう。
・予約機能(食べログのようにシーシャアプリから全てのシーシャ屋を予約できる
・ログイン機能(予約のために必要
・決済機能(予約のために必要
・広報機能(各シーシャ屋が独自のフォーマットを入力したら、それがシーシャアプリに反映されるなど。CMSに近い
加えて、気に入ったシーシャ屋さんや店員さんにオススメされたフレーバーなどを記録できるとなお良い。
すぐにフレーバーのミックスを忘れてしまいがちなのは私だけだろうか、、
あと、シーシャに関する知識を店員さんから聞いたら、それをもとに個人用シーシャなどもすぐに購入できると良い。
・お気に入り機能
・ECサイトとしての機能(シーシャ関連のアイテムを集める
※ とりあえずブレインストーミング形式で出しているだけなので、悪しからず
②開発の発端は?
まず、上記の通り、自分がシーシャをリサーチするときに感じた不便を解消したいという気持ちが大きい。また、転職のポートフォリオとして利用するという意図もある。そのため、以下項目を満たす技術スタックを選定する
・①であげた課題を解決する技術
・モダンな会社が使用している技術
また、お金をもらわない個人開発という形であるため、モチベ維持のために短期間での開発をするべき。
そして、自分はインフラエンジニアとしてのキャリアは考えていないため、なるべくインフラsaasサービスを利用したい。しかし、追加したい機能は多くあるため、可用性のあるクラウドインフラを採用
・短期間で仕上げる(3ヶ月でβ版までリリース
・可用性のあるクラウドインフラ
③ シーシャ市場の動向・傾向は?
※ 以下、肌間のみで考えているため、間違いがある可能性は高い。
C向けサービスを開発するので、ここではC向けで考える。
そもそも、シーシャは2020年代に急速に流行り出したモノであり、そこから流行を感じ取った企業や個人経営者が開店した経緯がある。
そのため、企業がこぞって経営をしているというより、個人経営でひっそりやっている店舗が多い。
ただし、一般ユーザーにとっては障壁が高い(そもそもカフェや飲食などより入店ハードルが高い)ため、利用ユーザーは固定される傾向にある。
新規ユーザーを獲得できれば、その店舗に根付く傾向にあるため、各店舗はLTVの向上よりも新規ユーザーの獲得に躍起?(SNS・昼割など
一般ユーザーの傾向としては
年齢:20から35歳。40代以降は極端に少なくなる
性別:わからない(定量的データがないし想像できないが、タバコよりも女性比率は高いイメージがある
混む時間帯:22:00以降から増えてく
また、考えられる利用シーンとしてはアーバンだとデート・飲み会帰り・ホストやキャバのアフターなどが多いイメージ。
ローカルやマイナー店舗になると純粋に吸うのが好きな人や常連が多い気がする。
そのため、シーシャアプリの利用は既にシーシャを利用しているユーザーが多くなり(ハードルが高いため)、常連は既存店舗にしか興味がないのでみないから、以下のようなペルソナが考えられる?
年齢:20から20代後半
シーシャ歴:数回ぐらい
利用シーン:デートや飲み会帰りでシーシャを決めたい
利用者数としては、シーシャユーザーの5から8割程度だろうか。
SNS歴の長い若い人が利用すると思われるため、冗長なテキストベースよりもわかりやすくシンプルなUI・UXが好まれるだろう。
デザインはとにかくわかりやすくみやすいモノを重視でいい。
まとめ
つまり、以下のような結論が出てきた。
・なるべく最新技術を利用する(サポート終了とかは論外。今後も利用することを考えて、廃れにくい技術を選択する
・スピード感のある開発をしたい
↓↓↓
(関数型言語などマイナーで技術的難易度の高いモノを選択しない。
(デバッグしやすいような言語
(ドキュメントが充実している
・スピード感のある開発をするため、仕様書を厳密に書かない。ソースにコメントを残していきたいため、型定義がしやすいもの。特に今回は初心者も参画するため適度な静的型付けである必要がある
言語が望ましい。
・画像や地図を利用するため、APIコールしやすい技術。Google Map APIの利用を視野
・C向けなので、利用ユーザーが増えるときは一気に増えるので、可用性のある技術
・将来的にはログイン・決済機能を付与するため、セキュリティ的になるべく厳格な技術。最初はスピード感を重視するが、プロダクトが成熟してくると品質を重視せざるを得なくなる。結局、品質重視の技術選定になる
・シーシャアプリとしてAPI機能を提供する可能性がある(シーシャの地図を呼び出すなど)ため、それを考慮した技術
【結論】使用技術スタック
フロントエンド
NextJs(React)+ TypeScript + Tailwind CSS
ReactとTypeScriptはフロントエンドにおいてデファクトスタンダードになってしまったため、これは確定事項と言っていいだろう。
SSR/ISR対応によるSEO最適化
シーシャアプリはC向けサービスであり、新規ユーザー獲得が重要。
Google検索経由での流入を増やすため、サーバーサイドレンダリング(SSR) や インクリメンタル静的生成(ISR) を活用できる Next.js は最適。
CSR(クライアントサイドレンダリング)ではSEOが弱くなるため、SPA単体はNG。
開発スピードが早く、エコシステムが充実
React ベースなのでコンポーネント開発がしやすく、再利用性が高い。
ドキュメントや学習リソースが豊富で、エラー対応も容易。
それに、個人的な話だが、html&CSS&JSのままだと、フロントの処理がどこで行われているのかデバッグしづらいというのも大きい。コンポーネントベースだと、画面ごとの処理を分割できるので、初心者でもデバッグしやすいなお感じた。
TypeScript の採用(型安全 & 保守性向上)
APIとのデータのやりとり(予約情報・決済データ・ユーザー情報)を厳密に管理できる。
「型定義が厳密すぎず、それでいてバグを防ぐ適度な静的型付け」 という要件に合致。
UI開発のスピードを向上させる Tailwind CSS
デザインシステムを統一しやすく、変更が容易。
クラスベースの設計により、スタイルの適用を直感的に行える(SCSSなどより開発スピードが速い)。
地図・画像を扱うためのAPIコールがしやすい
Google Maps API や Mapbox との統合が容易。
画像アップロードは Cloudinary などと組み合わせて高速に処理。
バックエンド
Go
本気でC向けサービスをグロースさせるなら、Goが最も良い選択になると結論づけた。
「エンジニア歴2年目で作れるモノなんてどうせ大したことないので、ぶっちゃけなんでもいい」のだが、個人的に最も大切なのは開発モチベなのでほぼ決め打ち。
それに、未経験のメンバーも参加させてコードレビューしていきたいので、明確に静的型付けのある言語の方が意思疎通しやすい。
開発スピードが圧倒的に速い(特にToC向けサービスでは重要)
Node.jsの強み:
JavaScript/TypeScriptをそのまま使えるため、フロントエンドと共通化できる
豊富なライブラリ・フレームワーク(NestJS, Expressなど)があり、素早く開発できる
動的型付けも選択でき、プロトタイピングが容易
他言語との比較:
Node.js が第一候補だったが、パフォーマンス視点で排除。また、
PHP フレームワーク(Laravelなど)があるが、API開発ではNode.jsとかGoのほうが柔軟である
Go 静的型付けで学習コストが高めだが、これは頑張ればいい。
Python 簡単だが、並行処理が苦手。静的でない。
Ruby Railsは開発スピード速いが、パフォーマンスが弱点。静的でないので、不安
→ API開発のしやすさやフロントエンドとの統一を考えると、Node.jsが最適
1. 高い並行処理性能(Goroutines & チャンネル)
GoのGoroutinesは、軽量スレッドのように動作し、大量の並行処理が可能。Node.jsの非同期処理(Event Loop + Promise)よりもスケーラブルで、負荷が高くなったときの安定性が高い。
【実例】
シーシャの混雑状況をリアルタイムで取得するAPIを作るとき、各店舗の情報を複数のデータソースから並行取得する必要がある。Node.jsでもPromise.allで非同期処理はできるけど、GoのGoroutinesのほうがオーバーヘッドが小さく、同時に数百〜数千リクエストを投げるときのスケール感が違う。
2. 高速なパフォーマンス
Goはコンパイル言語で、実行速度がNode.js(V8エンジン経由のJavaScript)より速い。特にCPUをガッツリ使う処理では、Node.jsはV8のJITコンパイルを経由するぶん、Goのほうが有利。
【実例】
店舗検索API(位置情報をもとに近くの店舗を検索)を作る場合、Goならクエリのパースや距離計算が速い。Node.jsでもできるけど、パフォーマンスチューニングが必要になる場面が多い。
3. 型安全 & シンプルなコード
Goは静的型付けなので、エンジニアのスキルレベルに関係なくコードの品質を担保しやすい。Node.jsの場合、TypeScriptを使わないと型安全性が弱くなる。
【実例】
フレーバー管理機能を実装するとき、Goなら「型が合わないからエラーになる」というミスがビルド時に発覚する。Node.jsだと、型のミスに気づかず、運用後に「undefined is not a function」みたいなエラーが出ることもある。
4. メモリ管理が優秀
GoはGC(ガベージコレクション)があるけど、Node.jsのV8よりもメモリ使用効率がいい。特に大量のリクエストをさばくAPIを作るとき、メモリリークの発生しづらさが違う。
【実例】
予約管理システムを作る場合、同時に大量のユーザーがアクセスすることになる。Node.jsだとメモリリークのリスクがあり、メモリ監視をしながら運用する必要があるけど、Goはそこまで気にしなくていい。
5. 単体バイナリでデプロイしやすい
Goはコンパイルすると単体のバイナリになるので、デプロイがシンプル。Node.jsだと node_modules が膨れ上がり、Dockerイメージが大きくなりがち。
【実例】
ECS + Docker環境でGoアプリを動かす場合、Goなら「実行ファイルだけをコンテナに入れて、起動時間を短縮」できる。Node.jsだと node_modules を含めるため、イメージサイズが数百MB〜1GB超えすることもある。
コンテナ・認証方式・キャッシュ選定
ECS
C向けサービスのため「OAuth + Cognito」を採用
用途に応じて「Redis + CloudFrontのハイブリッド運用」
コンテナ選定(ECS / Fargate or Kubernetes)
1. ECS(特にFargate)ならインフラ管理不要(Kubernetesはクラスタ管理が必要で運用コストが高い)
シンプルな構成でデプロイ可能(手軽にスケールアウトできる)
フルマネージドでAWSと相性が良い
2. ALB(Application Load Balancer)と簡単に連携
Auto Scaling(負荷に応じたスケール)も設定しやすい
Fargateならサーバーレスな運用が可能
3. EC2ベースのECSだとサーバー管理が必要だが、Fargateならコンテナ単位でデプロイできる
例えば、「昼はアクセスが多い → 自動でスケール」「深夜はアクセスが減る → スケールダウン」といった運用が可能
認証方式選定(JWT / OAuth / AWSの認証サービス)
1. OAuthの方が「Googleログイン」などの外部認証と相性が良い
JWTはAPI認証には向いているが、C向けサービスならOAuthを使ってGoogleやLINEなどのソーシャルログインを提供する方が便利
2. AWS Cognitoと連携すれば、認証基盤を簡単に構築可能
CognitoはOAuthに対応しており、Google・Apple・Facebookログインがすぐ実装可能
認証情報の管理(ユーザーデータのセキュリティ)をAWSが担ってくれる
3. JWTを使った認証も、Cognitoと連携すれば可能
Cognitoを使って、認証後にJWTトークンを発行し、APIアクセスを制御することも可能
キャッシュ選定(Redis or CloudFront)
(1) CloudFront:静的コンテンツのキャッシュ(Next.js用)
Next.jsのページや画像などの静的コンテンツはCloudFrontを活用
検索結果のレスポンス高速化(SSGページのキャッシュ)
Google Mapsのデータや画像をキャッシュしてCDN経由で配信
(2) Redis:予約機能やAPIレスポンスのキャッシュ(Go用)
予約のリアルタイム反映(セッション管理)にはRedisを使用
Google Maps APIのレスポンスをRedisにキャッシュ(APIコスト削減)
頻繁に検索されるシーシャ店データをキャッシュし、Goバックエンドの負荷を軽減