swchrm logs

妄想技術録

【Firebase】Firestoreについて自分なりにまとめてみる(随時更新)

迷いも含めて記述していきます。

設計

種類

冗長型と参照型がある。

speakerdeck.com

設計時に迷うことは、ユーザーに紐づく情報を別のトップレベルのコレクションとして生成して参照させるか、それとも、あくまでユーザーに紐づく情報だからユーザー内に収めるか。問題となるのはユーザーに紐づくけども、それ単体でも集計を行いたい情報Aがあるとき。これはコレクションを新たに一つ設けてユーザー参照をもたせるほうが良いかと思う。

情報の切り方によって変える、と表現すればいいだろうか。例えば高校を舞台として生徒(以下studend)の科目の成績(score)をつけるアプリを開発したいとする。このときに「生徒別の成績」を確認したいだけなら、studentにscoreを紐付ければいいと思う。しかし、score別(例えば国語、数学、英語、世界史、日本史…といった具合)に誰がどの位置にいるのかなどを算出したい場合は、別途scoreをトップレベルのDocumentに持ってきたほうが都合が良さそう。パフォーマンスの実測などはしていないが考えやすいと感じる。

あとはマスタデータとトランザクションデータという観点で考えてみても面白そうだけどまだ明確になっていない。

Documentの名前を乱数にするかどうかは、トランザクションデータなんかは乱数で良いと思っていて、あとは予め名称が一意になることが決められていれば乱数にしなくてもいいと思う。例えば人名やハンドルネームは被る可能性があるので乱数でDocumentを作成する。しかし先程の例えで言うところの科目名は被らないので名前をそのままDocumentに適用しても問題なさそう。ただし、システム全体で統一性をもたせたいのならばDocumentはすべて乱数の自動採番にしてサブコレクションにname: hogeみたいなことをすればいいと思う。

Authentication UIDとFirestoreのDocument IDを一致させる方法

別途記事を書きます。

お金の話

なにをどうしたら、どのタイミングでお金がかかってくるのか。

基本的には読み取り回数に対してお金がかかる。日に5万回読み取りがあればお金がかかる。企業のtoCプロダクションが2.5万/日なら個人開発アプリなら大丈夫でしょう。。

苦手なこと

集計

GROUP BYなどが使えない。となるとやるとしたらクライアント側での処理、もしくはCloud Functionを介して集計・計算となる。

speakerdeck.com

なぜDBアクセスにAsync / Awaitを使う必要があるのか

背景

Firestoreへのアクセスでasyncが使われているのを見たが、そういえばなぜ必要だったか不明確だったので整理したかった。また今回のお話はJavaScriptベースのお話。

正解/不正解に関わらず現在の理解での仮説を書いてみる

非同期通信を実現する技術の一つであるAsync / Awaitを利用することで、ユーザーが同期処理のために操作を中断して通信を行わずに済み、ユーザー体験を向上させることができるため。また非同期通信を実現する別の技術であるPromiseやjQueryのDefferdなどもあるが、そちらに比べて新しい技術であるAsync / Awaitは簡潔に記述が容易なため。

Async / Awaitはどういった技術か

非同期通信を実現する技術の一つ。非同期通信とは、サーバーからの応答(レスポンス)を待っている間にもクライアントの操作を可能にする通信技術のこと。いいかえると、同期通信では「処理待ち」が発生する。非同期通信では「処理待ち」を裏で行っている。具体例ではGoogle Mapがある。 使えるのはES2016(ES7)から。

記述について理解する

MDN公式より引用。

function resolveAfter2Seconds() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved');
    }, 2000);
  });
}

async function asyncCall() {
  console.log('calling');
  var result = await resolveAfter2Seconds();
  console.log(result);
  // expected output: 'resolved'
}

asyncCall();

awaitを付与されたメソッドが、「この処理を待ちます」という意味をもち、await以下の処理が実行されない。awaitを使えるのはasyncを付与した関数内。

Async / Awaitを使わない場合どうなるのか

非同期通信が実現できない、というとPromiseなどがあるので語弊があるが、例えばPromiseを使う場合は記述がややこしくなり、言い換えるとAsync / Awaitを利用することでPromiseを簡潔に書ける。

Async / Awaitを含む非同期通信を使わなかった場合の通信実現方法

同期通信を行う。

常に必要なのか

常に必要な通信方式ではない。 非同期通信を行いたいときに必要になる。つまり、なんらかの通信を行っている間にクライアントで操作もしたいときに必要になる。

結論

非同期通信を実現したいときはAsync / Awaitを使う。

考察

Promiseを理解するとより理解が深まる。

また、Promiseより簡潔に書けるため、基本的にはAsync / Awaitで書けばいいのではないか。

感想

なんとなーくわかった。

今後の課題

PromiseやDefferdとの使い分けを具体的に理解できればいいが、これはまたいつか時間ができたら。

参考にした情報

qiita.com

http://www.wakayama-u.ac.jp/~manda/webprg/webprg9.pdf

developer.mozilla.org

ossforum.jp

実践『実践Expo』 〜第二章 かんそうと知識整理〜

Snackを触る。

f:id:swchrm:20190322114228p:plain
Snackを開いて「タップして〜」のボタンをタップした後

中心になるjsファイルの名前はApp.jsっぽい。main.jsとかApp.jsとかindex.jsとかどれが何だよ、何が違うんだよみたいなのがまだあるがとりあえずReact NativeだとApp.jsになるということで覚えた。

他には、react-native-paperがある。これはpackage.jsonで読み込まれていて、なんだという話としては、 Google’s Material Design guidelinesに基づいたReact Native用のコンポーネント集(公式より)。

callstack.github.io

ブラウザ上で動作させたい場合はこれに登録したほうがよさげ。登録した。

appetize.io

styled-componentsに関しての記事はこれをみた。JSでstyleを指定するようにできるライブラリと捉えた。

qiita.com

const tagName = style(View) `
  text-align: center;
`;

みたいな感じに書く。この変数名のtagNameが、Componentの要素に対応する形になる。

謎が出た。AppクラスまでExportしてる。どこに…?多分見えないけどどこかにmain.jsやindex.jsがあって、そこでApp.jsをインポートしているんだろう。これは不明。

renderメソッドはComponentの描画に必要、つまり必須のメソッドになる。これがないとComponentが描画されない、つまり画面に反映されない。

stateはComponentが状態を持つときには必須だと思われるが、状態を持たないときは必要ない。とはいいつつも、実際になにかApplicationを作成する場合に状態がないなんてことはないと思うので、実質必須となる。Reduxを採用しない場合、書くComponentにstateをもつことになる。しかしながらこれは中規模以上のアプリになると苦しくなってくるらしい。Reduxは、アプリのすべての状態をrootStateオブジェクトというもので管理しているらしい。で、Reduxを採用する場合は、Reduxを介してしか状態の変更ができないようになる。もう少し細かくいえば、Reducer関数だけしか更新できない。Stateの値を直接変更しようとしても、変更できないとのこと。しっかりしている。

あとはdipatchだのなんだのある。ruducerとStoreだけじゃだめなのか。というかrootStateとStoreの違いは…?getStateの解説に「StoreからrootStateを取得する」とあるから、StoreはrootStateを含む他のなにかを包摂なんでそんなに変更を検知したりeventを送るメソッドや関数が必要なのかよくわからない。これは再度下記の記事とかで学習し直す。

qiita.com

Reducerはもとの値とActionを引数に受け取り、増加・減少されるなどした新しい更新された値を返す。action.typeごとに処理を条件分岐するとのことなので、これはtypeはなんの処理をするかの識別子的な捉え方を一旦しておく。

rootStateが大きくなってくるとReducerもそれに伴い大きくなってくることの対策は、rootStateのプロパティごとにReducerを切り分けるということだが、どのようになるのかは気になる…。プロパティごとというのは例えばとある状態「foo」を操作する関数はひとまとめにする、ということだろうか。カウントだったら増減でひとまとめ、みたいな。

counterのサンプルコードをGitHubからcloneしてきてExpoアプリで表示しようとしたがクラッシュした。理由はわからないが、Expoのバージョン等をあわせていないので、そこらへんが悪いと思う。ここは実行できなくても致命的ではないのでソースだけ読んでつぎへ。

3/23追記

Snackはちょっとしたコードを試すのにちょうどいいもので、実際に開発するのは向いてないのではないかと思った。自分は実際の開発はVSCodeで行う。