development
Database
Swift
Firebase
FirebaseRealtimeDatabase

Firebaseでアプリを開発するならClient Side Joinを前提にすること

More than 1 year has passed since last update.

Firebaseでアプリを開発する

みなさん、癖のあるデータベースであるFirebaseにもそろそろ慣れてきた頃でしょうか。
私は、Cookpadに入って4ヶ月が経ちました。幸せなことにCookpadでもFirebaseを使ってアプリの開発を行っています。
勉強会でもFirebaseの発表を多く見かけるようになって、嬉しい限りですもっといろんな方にFirebaseの魅力を届けるため、新しい記事を書くことにしました。
※この記事では特にRealtime DatabaseのことをさしてFirebaseと呼んでいます。

開発の鉄板 クライアントサーバーモデル

クライアントサーバーモデルとはクライアントサーバーに機能を分離したソフトウエアの総称です。
2017年現在、モバイルで動作するほとんどのアプリはクライアントサーバーモデルを採用し開発されたものと考えて間違いないでしょう。ところが、Firebaseの登場によってクライアントサーバーモデルに変革が起こっていると思っています。

この変革をサーバーレスアーキテクチャの時代と呼ぶ方がいますが、私はFirebaseがもたらしたのは、さらに一歩先の革新だと考えています。サーバーレスアーキテクチャの立役者はAWSのLambdaと行っても過言じゃないでしょう。Lambdaの機能はシンプルですがとても強力で、あらゆる恩恵をアプリ開発に与えてくれました。
しかし、やはり大部分の開発をクライアントサーバーモデルから離れることができないのが現実です。

Firebaseがアプリ開発にもたらした革新

私はFirebaseの革新を次のように考えています。開発するアプリによって差はありますが大半のアプリではFirebaseの恩恵を受けられるはずです。しかし、Firebaseには欠点があります。残念ながらFirebaseは万能ではありません。欠点を含めFirebaseがもたらした革新を説明していきます。

  • RESTを廃した
  • RDBを廃した
  • Queryを廃した

RESTを廃した

Firebaseで開発を行って、一番よかったことはここです。開発において一番のボトルネックはクライアントサーバーモデルであることです。現代においてREST APIの開発コストは高すぎます。

クライアントが行う開発

  • 認証の開発
  • 通信APIの開発
  • データモデルの開発
  • データマッピングの開発(Codableで少し楽になった)
  • エラー処理

サーバーが行う開発

  • 認証の開発
  • エンドポイントの設置
  • データベースの設置
  • クエリー
  • ビジネス要件の処理
  • エラー処理

他にもあると思いますが、エンドポイントの数に比例して開発コストは増大して行きます。

RDBを廃した

RDBは、そもそもデータベースの特性自体がモバイル開発にミスマッチです。ほとんどのエンジニアは慣例的にMySQLを使っているにすぎません。
データベースの特性を見直せばなぜミスマッチなのか理解できると思います。「?」となった方はこちらをどうぞ

Queryを廃した

Queryに関しては、もう少し機能拡張が欲しいの正直なところですが、Queryを廃したことによって今までのアプリ開発には新しい概念を導入する気づきになりました。Client Side Joinを開発に取り入れたことです。RDBでは当然のリレーションですが、Firebaseでは勝手が違いJOINがありません。そこでFirebaseではデータ同士の関係性はクライアントで解決します。
Client Side Joinは、開発速度にも大きな影響を与えています。ネストの深いJSONをサーバーから受けクライアントで扱えるようにマッピングしていましたが。その作業は無くなります。
Firebaseでは通信にWebSocketが使われているため、一般のAPIを書くよりシンプルにClient Side Joinを実現できます。

例えば以下のような書き方ができます。

// iOSでTableViewを書いた例
// データソースには、たくさんのデータが入っていたのが普通だったがデータソースにはデータのIDしか保持していない。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.datasource?.count ?? 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: TableViewCell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
    configure(cell, atIndexPath: indexPath)
    return cell
}

func configure(_ cell: TableViewCell, atIndexPath indexPath: IndexPath) {
    // ここに注目
    // cellのconfigureのタイミングで値を取得しています。
    cell.disposer = self.datasource?.observeObject(at: indexPath.item, block: { (user) in
        cell.imageView?.contentMode = .scaleAspectFill
        cell.textLabel?.text = user?.name
    })
}

詳しく見たい方はこちらへ https://github.com/1amageek/Salada

サーバーサイドで今まで当たり前のようにJOINして取得して、クライアントで展開していたがもうそんなに頑張らなくていいんです。

Firebaseができないこと

  • Search機能がない
  • インフラの細かいコントロールができない

Search機能がない

上にも書いた通りFirebaseはQueryは非常に弱いです。
例えばタイムラインの機能を作ろうとする場合、フォローしたユーザーの投稿を表示するという仕様を考えるでしょう。しかしFirebaseでは特定のユーザーの投稿だけを取得しアプリで表示させることはできません。
私が作るシステムではQueryをElasticSearchに任せています。
RDBであってもElasticSearchは使うと思うのでそもそもRDBに求める機能とはもはやなに?

インフラの細かいコントロールができない。

Googleについて行くしかないですね。でも世界一のインフラをもつGoogleがオートスケールしてくれるので問題ないでしょう。

さぁFirebaseで開発を始めましょう。