読者です 読者をやめる 読者になる 読者になる

今、SPA/ReactNativeにとっての必要な PaaS を考える

当方ボーカル、フルスタックPaaS募集

ほしいもののコンセプト

  • SPA職人としてそこに全力を尽くしたいので、それ以外を全部やってほしい
  • とはいえストレージへのアクセスはAWS Lambda/Cloud Function等を介してちゃんとしたコントロールをしたい
  • プロトタイピング時は何も考えずにORMを叩いていたい
  • 運用フェーズでは金を払ってスケールしたい。とはいえボトルネックは常に監視したい。極端にやばいスケールサイズはどうせ人を雇うのでその先は考えなくていい。

より細かい要求

  • 認証はPaaS側が全部持ってほしい
  • JSONSchema でクライアント/サーバーサイドのアクセス制限を定義したい
  • サーバーはフルマネージド
  • Lambda/CloudFunction で関数単位でパフォーマンス監視/障害検知
  • ローカルで本番と同じ構成が建てられる
  • アセットは勝手にCDNに投げといてほしい
  • バックエンドストレージは、 BigQuery/Mongo風の列指向DBで、インデックスが貼れて、オートスケールしてほしい
    • 無停止でなくてもいいから任意なバックエンドに引っ越すのが簡単であってほしい
      • Google だったら Datastore で初めて、辛くなったらSpannerとか。
      • AWS だったら DynamoDB => Aurora とか
      • 結局SQLじゃんってのはわかるが、適切なActiveRecordみたいなのがあれば問題ないと思っている。
    • ちゃんとしたNodeのORMがほしい。joinの抽象は…必要かどうか悩む。非同期アクセッサはどうやってもNodeで表現しづらい。
    • ORMは型を書きやすいインターフェースでないとこの先ダメ
    • たとえ相手がNoSQLだろうがMigrationがないとダメ
    • MongoQuery風のクエリがほしい

妄想したAPI

const schema = {
  definitions: {
    todo: {
      required: ['title', 'done']
      properties: {
        id: {
          type: 'string',
          primary: true
        },
        ownerId: {
          type: 'string',
          index: true
        },
        title: {
          type: 'string',
        },
        done: {
          type: 'boolean'
        }
      }
    }
  }
}

const todoStore: Store<Todo> = new Store({
  storeName: 'todos',
  schema: schema.definitions.todo
})

const main = async () => {
  await todoStore.save({
    title: '朝食', done: false, ownerId: 'mizchi'
  })
  const todos = await todoStore.where({ownerId: 'mizchi'})
  console.log(todos)
}

main()

これが無限スケールしてほしい。いや、このAPIを再現するだけなら簡単だが、運用まで含めると考えることは無限にある。マイグレーションとか、実際 store.save 関数の中身がどこに飛んでるのか、とか。バッチアップデートはどうするんだ、認証は?

それらを全部クリアした上で、あとはフロントエンドとしてReact/ReactNativeに繋いで、終わり!って感じ。いや自分のメインの仕事はそこからはじまるんだけど。

現実の課題

これらを落とし込んだソリューションというか、「正解」なスタックというか、そういうのがない。みんな手探り。

実際今どうするのが正解か

AWS Lambda / Dynamo

調べると、Lambda が RDS とコネクションヒープが持てない関係で相性が悪く、スループットを出すにはDynamo を使え、という感じになっている(たしか公式ドキュメントにもそう書いてある)。Dynamo を使ってみたが、スループットのコントロールAPIでコントロールしたり、金で解決できるんだが、場合によっては取得を諦めたりするし、挙動が難しい。何も考えずに使えるものではない。返り値もなんか変で、毎回整形するのがめんどい。ラップすりゃいいんだが。

S3, API Gateway, Lambda, それらの複合を考えていくと、k8sやTerraform とか使うのが最近の流行りっぽいが、完全にAWS沼/コンテナ沼だと認識してるので、今は距離をおきたい。ビルドツールにDockerを使うのに抵抗はないが、デプロイされる環境まで自分はやる気がない。

Google Firebase

Firebase hosting という機能があって、元々はGoogleクラウドにSPA、というかindex.html をデプロイするだけの機能だったんだが、どんどん機能が増えて、最近 cloud function のインテグレーションがきた。Firebase Realtime Database はローカル制御の限界があったが、ストレージへの保存時の検証をクラウドでやれるようになったので、実質今までのサーバーと同じような運用ができる。

https://firebase.google.com/docs/functions/

とはいえ、Firebase Realtime Database はリアルタイムストリームに優れるけど、ストレージのサイズの料金とreadの料金が高いので、真面目に作ると他のバックエンドに接続する必要がある。しかしそれも cloud function 経由でできるから、もしかして怖いものはないのでは、それが RDS/Lambda みたいな問題がなければ、と思っている。

GCPの範囲内なら、実際の繋ぐ先は、ホビーユースなら Cloud Datastore 一択らしい。Google Spanner がいいらしいって雑な情報で値段を調べたけど、 1ノード1時間 $0.9 で何もしなくても軽い試算でも月7万円ほどかかる。これはない。けど、月7万も必要なサービスを回せるんだったら、売却含めてその時点で何かしらマネタイズできると思うので、まあ考えなくてよい。AWSエンジニアを月100万で雇うのと比べれば7万は誤差。

認証系も組み込まれて強力。アクセス解析やAdMobの組み込みがある。僕はAdMobは使ったことがないので不明だが。

というわけで、最近はFirebaseを掘っている。

Firebaseに足りないもの

GCP全体に言えるが、なんとなくどれもBeta版っぽくて、ベストソリューションもないから、これとこれとこれ!って選択ができなくて、Railsみたいな選択の迷いのなさが生む生産性には遠い。

Node視点だけで見ると、次のものが足りない。

  • Lambda/Cloud Function の抽象化レイヤー
  • バックエンドのアダプターが充実したORM
  • これらを実践した運用の体験談

たとえば、 Rails Tutorial 相当のことを、同じかそれ以下の分量で違和感なく記述するフレームワークがポンと提案されたら、みんなそれに乗ると思う。

自分がそれを作るから金をくれーといいたいのはある。いや、自分はGoogle技術の専門じゃないんで、GCP周りは専門にする他の人にはまだ劣ると思うが、実際にSPAと組み合わせて、オールインワンで諸々隠蔽した上での開発環境のスタックの構築は、自分のようなスキルセットの人間に強みがあると思うので、フリーランスの仕事の幅になるかなと思って勉強中。現状、半年分の仕事は埋まってるけどなんかあったら依頼をください。現場からは以上です。