2019-06-14に更新

shallweの技術部分について

f:id:katonobo:20190612074834p:plain

先日リリースしたshallweの技術的な説明です。

以前の記事はこちら

https://crieit.net/posts/shallwe

技術的構成

shallweはフロントエンドに「Vue.js」

f:id:katonobo:20190613073814p:plain

Vue.js

 

 

バックエンドに「Firebase」を使用しています。

f:id:katonobo:20190613073910p:plain

Firebase

 

 

今回は「Buefy」も使いました。BuefyはVue.js用のUIフレームワークで、v-modelなどと組み合わせてリッチな見栄えを簡単に実現できます。Bootstrapみたいなものです。

f:id:katonobo:20190613074005p:plain

Buefy: lightweight UI components for Vue.js based on Bulma | Buefy

 

なぜこの技術的な組み合わせか?

Vue.jsのSPA(シングル・ページ・アプリケーション)はフロントエンドの高速な開発を可能にします。個人開発では素早く完成してなんぼなので、開発が高速でできるSPAは重宝します。

Firebaseは、ホスティング、データベース、ストレージ、Functions、などがパッケージングされているので、全部詰めで各連携がとても楽です。また、無料枠が設定されているので、流行るかどうかわからないサービスも何も恐れずにリリースできます。

後、個人的に嬉しいのは、グーグルドメインとの連携も簡単な点です。

Vue.jsとFirebaseの組み合わせは、個人開発に非常にマッチしていると考えています。様々な調整が必要な企業のプロジェクトなどは別ですが、技術の選定と把握を全部自分でできる個人開発にはVue.jsとFirebaseはオススメです。この二つを組み合わせると素早く簡単にサービスを作成、リリースすることができます。これから何かウェブサービスを作ろうと考えているプログラミング初心者の方も検討しても良いと思います。

 

また、今回のアプリでは、リアルタイムチャット機能が必須だったので、FirebaseのFirestoreを使いました。

 

shallweの構成について

shallweは、「今日この後」に特化したイベント作成と応募のプラットフォームですが、現在実現している機能はまんまマッチングアプリです。

 

募集ユーザーは、イベントを作成し、マッチング候補(応募)を待ちます。
イベントの応募ユーザーは、イベントを探し、気に入った募集に申し込みをします。
リクエストを受けた募集ユーザーが、マッチを許可した場合、二人のチャットルームが作成されます。
最後にマッチした二人でチャットルームで待ち合わせの約束をしてもらう。

という流れです。

f:id:katonobo:20190613083907p:plain

 

 

Firebaseでは、「Hosting」「Firestore」「Cloud storage」「Functions」を使っています。

(当初、SEOとOGP画像のことを考えて、NuxtとGAE(グーグル・アップ・エンジン)の組み合わせも検討しましたが、以前作成したSPAアプリでグーグルサーチコンソールでちゃんとデータが取得されていたこと、OGP対策はfirebase functionsを使えばSPAでも生成できることがわかり、SSR(サーバーサイドレンダリング)のコストの高さからVue.jsとFirebaseを選択しました。SPAのOGP画像については後述します)

 

技術的な特徴

shallweで特徴的な機能は、SNSシェア用なOGP画像の機能と、リアルタイムチャット機能です。

OGP画像の設定

めちゃくちゃ便利なSPAですが、唯一ちょっと不便だなと感じるのがこのOGP画像の設定です。ツイッターなどSNSの拡散を意識する場合、キャッチーな画像(OGP画像)を使いたいところです。

よくツイッターで目撃する「質問箱」や「bosyu」というアプリは画像に様々な文字が書かれていて、とても目につきます。

このようなOGP機能をSPAで動的に変更するのは難しく、普通はサーバーサイドでの処理が必要になります。

なぜならSPAは一つのページを動的に変えてコンテンツを作成するため、それぞれのページにあったOGP画像を設定することはできません。このOGP画像の対策のためにサーバーサイドレンダリングが可能であるNuxtを選択する例も見たことがあります。

解決策:Cloud FunctionとStorageを利用する

ただ、この問題を解決する素晴らしい方法があります。Cloud Functionsを使って、SNSのクローラーが判断するページとユーザーがみるページを分けると言う方法です。この三つの記事は大変参考にさせていただきました。

SNS映えするWebアプリを...!FirebaseとVue.jsでSPAのOGP画像の動的生成をやってみたら案外楽だった - Qiita

Vue.jsとFirebaseでOGP画像生成系のサービスを爆速で作ろう - Qiita

Nuxt.js + FirebaseでOGPの仕組みを完全に理解した 〜俳句をSVGで描画するサービスをリリースした話〜 - Qiita

ポイントは3点です。

  • SNSのクローラーがシェア用URLにアクセスすると、Hostingの設定でFunctionsが起動します。
  • FunctionからSNSシェア用のデータがクローラーに送られ、そのデータがツイッターなどのタイムラインには表示されます。
  • ユーザーがページにアクセスするとクローラーとは違うページに飛ぶ。

と言う仕組みです。

この仕組みを使うことでSPAでも動的にシェア画像を作成できます。

shallweでは、募集画面にツイッター用シェアボタンがついており、そこからOGP画像が生成されます。

リアルタイムチャット機能

firebaseの入門者向けサンプルアプリの代名詞とも言えるチャット機能ですが、実際に実用レベルまで高めるのは実は奥深いことがわかりました。

shallweで必要とした大きな機能は

  • それぞれ独立したチャットルームを作成する
  • リアルタイム更新
  • 既読機能

です。

ここまで本格的なチャット機能になるとネットでも情報がないので苦戦しました。

今回は同じような実装をするときに他の人も困るであろう、チャットのメッセージデータの取り扱いについて書いておきます。

メッセージデータを扱い方について

LINEをイメージしてもらえるとわかりやすいと思いますが、ユーザーがコメントを送信すると、自分のメッセージと相手のメッセージを判別して時系列で表示します。この機能自体は簡単ですが、問題はデータをどのようにFirestoreに入れるか?です。

私は二つの方法を検討しました。

サブコレクション

https://www.katonobo.com/entry/firebase-chat-data

以前の記事にも書きましたが、FirestoreはNoSQLと言うデータベースです。コレクションの中にはドキュメントがあり、そこにデータを格納します。

コレクションは、イメージ的には、病院のカルテがわかりやすいでしょう。病院のカルテだと、クリアファイルに必要な情報がまとめて入っていますよね?そのまとまっているクリアファイルがコレクションで、その中にドキュメントとして各情報が整理されて入っています。

サブコレクションは、クリアファイルの中にさらにクリアファイルを入れておけるといったイメージです。このクリアファイルにはメッセージに関する情報を入れちゃいましょうということです。

この方法はFirebaseの公式ドキュメントでも例として説明されていますし、チャットアプリのメッセージデータの管理としては王道的な方法だと思われます。

Cloud Firestore データモデル  |  Firebase

 

また、既読機能について書かれた実践的な記事がありましたがそちらもこの手法です。

チャット機能を部分的にレベルアップさせる - Qiita

 

 

 ただ、懸念点が一つあります。それは、各メッセージごとにサブコレクションのドキュメントを作っていたら、データの読み込み回数が膨大になるのではないか?ということです。

もしチャットルームでメッセージのやりとりが100回されたら、一つのチャットルームの読み取りだけで100×2で200回です。

Firestoreにはキャッシュ機能がありますが、このような膨大なドキュメントがまたふただび呼び出されるようなことが頻繁にあれば、即座に無料枠はなくなるでしょう。

Firestoreの読み取りは50,000/日は無料なので普通ならよっぽどじゃないとオーバーしないはずですが、このチャット機能の実装は少ないユーザーで簡単に無料枠をオーバーされてしまう可能性があります。

 

配列を利用する

今回は採用したのは、配列を利用する方法です。

チャットルームに、「messages」と言うフィールドを作り、そこに配列として各メッセージを格納していくという方法です。この方法なら、サブコレクションを作成する方法と比べて、メッセージの書き込み回数は変わらないですが、後々の読み込み件数は大きく抑えることができます。

実はFirestoreは以前だと配列の扱いは不便だったのですが、今は配列の検索や追加などが簡単にできるようになってきており、その方法を使えばメッセージを配列の一つとして扱うことも簡単になっています。

https://www.katonobo.com/entry/firestore-array-tip

 もちろんこちらの方法ではドキュメントのデータが増えますし、プログラミング的観点で見るとNoSQLのデータの管理の仕方としてはあまり上手くないですが、今回は読み込み件数を抑えるメリットの方を選択しました。

 

最後に

この他にも色々な工夫はありますが、長くなってしまうので省きます。

もしさらに興味がある人はshallweを使って私に会いにきてください。今後、shallweでカフェでのもくもく会(プログラミング勉強会)をしょっちゅう企画していく予定です。

隠すことは何もないので、このアプリを作るに当たって私が得た知見は全部お伝えできます。

もちろん、これからプログラミングを始めたいという初心者の方も大歓迎です!

 

 

ということで、shallweを何卒よろしくお願いします!

長文お読みいただきありがとうございました!

終わり

Originally published at www.katonobo.com

かとのぼ

ビビッドなアーキテクチャが強みのウェブサービス開発者。運営ブログ→かとのぼのマイコード・マイライフ(https://t.co/wJxW04hvIh) 運営サイト→みんなの推しコイン(https://t.co/WRDFpEPXxh)当日プラットフォームShallwe(https://t.co/crA6ooX5kh)

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

関連記事

コメント