【Vue.js×Firebase】3日で位置共有WEBサービスを作った話【個人開発】

> この記事はQiitaのトレンドランキングで1位を獲得しました

# この記事で伝えられること
0. 「WEBサービスってどうやってつくるの？」への回答例
1. 新人WEBエンジニアの方が素早く・簡単にWEBサービスを開発できる技術アセット・開発例
2. WEBサービスの開発・公開までに必要そうな一連の手順例

※ この記事は、実務経験の乏しいWEB開発未経験者〜新人WEBエンジニアに向けて書かれています。
※ ソースコードレベルの話はほぼ出てきません。
※ 個人開発のWEBサービスの公開までに必要な手順例として、4日間でやったことを紹介しています。

# 1. つくったもの
ワンクリックで位置を共有できるWEBサービス。その名も「いまここ」。
https://imakoko.tokyo
https://twitter.com/imakoko17

ごくちいさいサーバーレスSPAです。
着手から公開までを約4日間（人日換算）で行いました。

<img width="1440" alt="スクリーンショット 2019-07-30 15.35.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469846/559c0237-b25a-9655-b841-bcbb1ec901a6.png">

<img width="1130" alt="スクリーンショット 2019-07-30 15.43.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469846/63e33560-6c28-f20c-2e1c-18cfa0aba4c5.png">

↑ワンクリックで生成されるURLを共有するだけで全員の位置を1つの地図上にリアルタイムに反映できます。

# 2. 提供価値を考える
まずは提供したい価値を言語化して明確化するところから始めます。
※ 以下技術的な話でないですが背景として。興味がなければ読み飛ばしてくださいませ。
## 2-1. コンセプト
- ワンクリックで現在地共有URLを発行できる
- 位置情報追跡は一時的にのみ可能なので安心
- 登録不要にして位置共有までのコストを最小化

## 2-2. 背景
- 東京の待ち合わせグダる
- 「お前どこや！」
- 「東口で集合ね！」　← 東口が広すぎて結局落ち合えない

## 2-3. 提案
- ブラウザから位置情報取得して、位置情報プロットした地図を表示できるURLを生成しよう
- （最近NewsPicksでみた）JKの間で流行っているらしいZenlyの大人ver
- 「"今"居場所を共有したいのであって、"常に"共有した訳じゃないんだよなぁ」な大人のニーズにマッチ(Zenlyは常時位置情報を公開するコンセプトらしい)
- ブラウザ開いて「位置を共有する」ボタン押して、生成されたURLをLineで送る。スマートに位置共有。
- ブラウザベースなので「両方がアプリを持ってないと使えません」という不都合なことがない利点
- URLを踏んだユーザーのリアルタイム位置情報も、同じ地図上で共有

## 2-4. 顧客は誰か
- 「今」いる位置情報を「誰かに」「スマートに」共有したいニーズをもつすべてのひと

## 2-5. ビジネスモデル図・ポジショニングマップ・価値連鎖図をつくる
事業に取り組む前に、「ビジネスモデル」や「市場における立ち位置」或いは「価値の流れ(Value-Chain)」を明確にするために、価値とお金の流れを図に落とし込んでみましょう。

この過程が「本当にこのモデルは有効なのか」「このビジネスドメインの優位性は何か」「顧客は本当にこの価値を求めているのか（或いは求めるべきなのか）」を深める第一歩となります。

今回はお金が「全く」絡まないので、シンプルにシステムイメージ図になりました。
![imacoco.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469846/6f6a71a4-e4fc-03bf-c9eb-ed207b4178fa.png)

図の作成はdraw.ioだけあればいいです。実務でもどうぞ。
https://www.draw.io/

# 3. 使ったもの
- Vue.js
- Firebase（auth/firestore/hosting）
- bulma.css（CSSフレームワーク）
- Sass(SCSS)

【採用理由】(開発が)はやい・(開発コストが)安い・うまい(書いてて心地よい)。

Nuxt.jsも実務経験あるのですが、個人的にあまり好きでないので今回は不採用。

---
【補足】 Firebaseってつまりなに？
最近ではすっかり有名になりましたが、数年前までは名前も聞いたことないよーって人も多かったと思います。
（今現在でも、製品での採用事例はそこまでは多くなく、いまいまでみても挑戦的な選択肢だと思います）

来歴としては、もともと米国のスタートアップが作っていたのをGoogleが買収して今に至っています。
（最近はあんまり聞かない用語な気もしますが）「mBaas」という部類に入るクラウドサービスです。mは「Mobile」のｍですが、firebaseはWEB開発でも利用できます。
https://mbaas.nifcloud.com/about.htm

すごくざっくり説明すると、GCPをフロントエンドから直接叩けるようにした感じのもので、普段Servletとかで古き良きWEBサービスを書いている人が急に触ると常識が通じなさすぎて脳震盪を起こすかもしれません。

(個人開発での)作業レベルでいうと、サーバーサイドの環境構築および機能実装が不要になり、もっというとホスティング環境の構築も不要です。
極論すると、node.jsでフロント書いて、`firebase deploy`でWEBサービスの開発が終わります。

もう、毎度毎度書いている「認証フロー」や「ゲッターセッターの羅列」や「コネクションプールの管理」や「select文発行するだけのメソッド」や「$.ajaxでの煩雑なデータのやり取り」や「ファイルアップロード処理」などを見ずに済みます。
有料アカウントさえとっておけばサーバー負荷でダウンするとか基本考える必要がなく、夜は安らかに眠れます。
https://news.livedoor.com/article/detail/15105748/

...という開発のパラダイムシフトが起こっている場所がFirebaseなのです。

プロダクションで採用するのは色々あるのでちゃんとPOC回すとかしないと破綻のリスクもあると思いますが、価値先行型の個人開発であれば、十二分に採用の価値のあるプラットフォームだと思います。

--- 補足ここまで ---

# 4. 技術調査
まず、頭の中で大まかなシステム設計をし、必要そうなライブラリ・API類を調査します。
あとで頓挫したり、手戻りが発生しないように、あらかじめ各APIの公式ドキュメントでやりたいことが実現可能か確認しておくとよいでしょう。

今回コアとなるのは「地図API」と「データのリアルタイム反映」です。

## 4-1. 地図API
候補に上がったのはGoogle Maps APIとYahooの地図APIです。
調べてみるとGoogleの方はいつのまにかGCPに統合され、お金もかかってきそうなので、今回はYahooのAPIを採用しました。

https://developers.google.com/maps/documentation/javascript/tutorial?hl=ja
https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/js/

## 4-2 データのリアルタイム反映
こちらはFirebase(realtimeDB/firestore)の得意分野ですから、普通に組んでいれば実現できます。Firebaseなしだと手でAjaxかWebsocketでゴリゴリやる必要があるので結構大変です。

## 4-3 位置情報の取得
HTML5のGeolocationAPIを使います。
スマートフォン含めて多くのブラウザで利用できるようなので問題なさそうです。
https://developer.mozilla.org/ja/docs/Web/API/Geolocation/Using_geolocation

# 5. 画面デザイン&CSS設計
エンジニアにとっての鬼門だったりしますが、画面デザインを考えてみます。
今回はごく小さいサービスなので使いませんでしたが、普段はAdobeXDを用いて画面デザインを固めます。
https://www.adobe.com/jp/products/xd/details.html

後で`<span style="font-size:12px !important">`とかカオスなことにならないようにデザインのガイドラインを用意して具象値を変数化しておくとよいでしょう。↓変数化の例。
https://bulma.io/documentation/customize/variables/

今回はスマホで使ってもらうことを前提としているので、そのことを念頭においてデザインします。

ロゴもWEB上で作れたりします。
(細かいデザインは後回しで兎も角MVP!という方はロゴの色をメインカラーにつかっておくのが便利です。)
https://www.777logos.com/

画像やアイコンはフリーで提供しているサイトがあります。クレジットは忘れずにいれておきましょう。
https://unsplash.com/
https://fontawesome.com/
https://icons8.com/icons

CSSフレームワークとしてはオキニのbulmaを採用しました。
https://bulma.io/

bootstrapがオワコン化して久しく、生CSSも育っていてCSSフレームワーク界はコモディティ化してますので、何を使っても、或いは使わなくても、あまり大差は無いので好みで決めましょう。

一方、フレームワークを利用すると、簡単なデザインであればSassの変数値を独自の値に差し替えていけばCSSの基盤が完成するので、あとはドキュメントのサンプルコードをペタペタするとそれっぽい見た目が出来上がります。

今回は兎も角楽をしたいのでbulmaを採用しました。

# 6. 開発手順
## 6-1. gitリポジトリを作る
なにはともあれリポジトリを作るところからです。
私はMicrosoftによる買収のタイミングで(何となく)gitlabに移ったのでそちらにリモートレポジトリを立てます。

CIとか頑張ってもいいですが、大抵の個人開発レベルでは頑張るほどではないです。
https://www.gitlab.jp/comparison/gitlab-vs-jenkins.html

## 6-2. Vue-cliでVueプロジェクトを立ち上げる
Vueプロジェクトを起こします。
用意されたコマンドを叩いてあげるとテンプレートが生成されます。
https://cli.vuejs.org/guide/creating-a-project.html#vue-create

## 6-3. ライブラリをインストールする
適宜利用するライブラリを`npm install`したり設定ファイル作ったりします。
Vue関連のライブラリ導入の際には`src/main.js`をいじることが多いので各ライブラリのドキュメントを参照しましょう。

ESLint・Prettierあたりはとりあえず入れておく派です(エディタ連携の設定もしておきましょう)。
コード整形のコスト減少・品質向上の分開発速度が上がると思います。開発現場でもしばしば使われます。https://qiita.com/soarflat/items/06377f3b96964964a65d

## 6-4. Firebaseを初期化する
Firebaseの初期化手順は慣れるまで少し手こずります。
詳細手順はQiita上の良記事や公式ドキュメントに譲りますが、概要は以下です。

1. WEB上のfirebaseのconsoleでプロジェクトを作っておく(初期化時にプロジェクト新規作成はできるのですが、GUI上で先に作っておいた方がわかりやすいと思います。)https://console.firebase.google.com/u/0/
2. firebase-cli経由でグーグルログイン`firebase login`（ユーザー認証）
3. プロジェクトの初期化`firebase init`(firebaseで利用する機能を選択します)

尚、`firebase init`の際に聞かれるhostingの公開ディレクトリを`dist`にしておくとよいでしょう。(`npm run build`で`dist`ができます)

## 6-5. モジュール構成を決めてクラス等枠を実装
個人的に、モジュールファイルの構成(共通化の構造)をある程度決めてクラス等ざっくり組んでから中身のコードを書き始めます。
今回はVue-cliでテンプレができているので適当にfirebaseアクセス用のクラスとかを適宜どこかに作っておきます。

## 6-6. 画面コーディング
ここから本格的にコーディングに入ります。各人のスタイルによると思いますが、私は一連の画面実装から始めます。
DB設計・詳細設計等も書きながら考えます。（実務ではさすがにちゃんと設計組んでから書き始めますが..）

VueやReactにおいては「コンポーネント設計」もこの作業に含まれます。
UI要素としてのコンポーネント設計はもちろんのこと、利用するAPIやfirestore特有のDB設計など、「どのコンポーネントにどの責務を持たせてどのように値を連携するのが綺麗か・効率的か」も考えながら実装することになります。

また、今回はスマホで使ってもらうことが前提のため、レスポンシブに書いていきます。
ひと昔前に比べればずっと楽にはなりましたが、いまだにブラウザごとの差分とか全く考えないと思わぬ画面崩れとかがあるので可能な限り実機検証等もしておきましょう。
（今回はPCとスマホで両立するミニマムなデザインにしたのでブレークポイントごとの設定とかは特にしていません。）

## 6-7. firestoreつなぎこみ
firestore（データベース）関連のコードを実装し、いよいよ画面の動きとDBの動きを繋げます。
firestoreとVueやReactとの相性はよく、基本的には「変数間のマッピング」(ORマッパ的なイメージ)を行うというイメージです。あとは正しく動けばデータがあっちこっちにリアクティブに反映されていきます。

LAMP環境とかで作業されている方はこれが初めて動いた際には感動すると思います。
C言語は出た当時「自動プログラミング！」とか言われていたそうですが、正にそんなイメージです。値のマッピングを書いておくと「勝手に」あっちこっちに反映されます。

## 6-8. テスト
強いエンジニアの方はテストから書き始めたり色々方法論があります。今回は小さいですし、個人開発ですし、でテストコードは特に書いていません。
ただし、WEBフレームワークDjangoでは次のようなことばがささやかれます
"Code without tests is broken by design."

# 7. 公開
## 7-1. ビルド
今回はシンプルにSinglePageApplicationを生成するので`npm run build`を叩くだけでOKです。
良い感じにビルドされた`dist/`が出来上がります。

## 7-2. ホスティング
firebase-hostingの初期化が済んでいれば`firebase deploy --only hosting`とすると勝手にデプロイしてくれます。

私はこんな簡単なコマンドもすぐ忘れちゃうので↓を`deploy.sh`に書いておいています。

``` sh
npm run build && firebase deploy --only hosting
```

【追記】 `package.json`に以下のように記述しておくと良いとアドバイスいただきました！

``` json
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "deploy": "npm run build && firebase deploy --only hosting" // ← 追加
  }
```


## 7-3. ドメインの取得
ドメインを取得しましょう。
お名前.comとかでぽちぽちするとドメインを取得できます。
https://www.onamae.com/

## 7-4. ドメインの接続
ドメイン鯖側にレコードを追加し、firebase-consoleのホスティングタブの「ドメインを接続」ボタンを押してドメインを接続します。
初めてやる時微妙にハマりがちなので、インターネット上の記事を漁りましょう。
https://firebase.google.com/docs/hosting/custom-domain?hl=ja

大まかな流れはドメインを取得したサイトのDNS設定のページを開き
1. 「テキストレコード」を設定して認証
2. firebase-console上に表示されるAレコードをDNS設定に書き込む
だけですので焦らずにやれば大丈夫です。
（DNSレコードの反映には数分かかるのでのんびりやりましょう）

慣れるまでちょっと面倒ですが、インフラの人でも無い限りなかなかDNSなんて触らないでしょうから、勉強の機会にはなりますね！

## 7-5. ページの軽量化
表示速度も重要です。
表示速度を解析してくれるGoogleのChrome拡張やWEBサービスがあります。
https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=ja
https://developers.google.com/speed/pagespeed/insights/

闇雲に（特にSPAで)高得点をもらおうとすると泥沼に陥るので、妥協点を探しながら、解析結果を参考に高速化を目指しましょう。
画像・WEBフォント周りは何も考えないで突っ込んでいるとボトルネックになりがちです。
画像の圧縮、読み込むweightの制限・読み込みの遅延化は定跡ですので色々調べてみましょう。

見逃しがちですが、firebaseのhostingでは、firebase.jsonという設定ファイルを触ることでレスポンスのHTTPヘッダをいじることができます。
ここで設定できる「Cache-Control」(ファイルをキャッシュする期間の定義)はこのスコアに大きく寄与するので確認しておきましょう。
https://firebase.google.com/docs/hosting/url-redirects-rewrites?hl=ja#section-headers

<img width="1440" alt="スクリーンショット 2019-08-02 17.42.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469846/7c160233-f56c-6b7f-9cd8-1f7cd8d7100b.png">
叩くたびに結果が微妙に違うので色々試してみましょう。

## 7-6. SEO対策
「検索エンジン最適化」の対策を施します。

![61onVbx1WEL._SX386_BO1,204,203,200_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469846/f2443385-581b-ae56-4e96-c56903e7458c.jpeg)
↑ これ読みました。網羅的にSEOについて書いてるのでSEO初学者におすすめです。

## 7-7 Google Analytics導入
サービスにどれくらいの人が流入しているか確認するためにGoogle Analyticsも導入しておきましょう。
https://developers.google.com/analytics/?hl=ja

SPAの場合、ページ遷移しないので、ルーティングにバインドして逐一ビーコンを打たないとSPA内でのページ遷移の情報が取得できません。

vue-analyticsというライブラリを導入するとビーコンの送信を自動化してくれるので便利です。
https://github.com/MatteoGabriele/vue-analytics

<img width="1440" alt="スクリーンショット 2019-08-02 17.40.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469846/69224ec2-0c75-29a7-1045-e17403d787c9.png">

## 7-8 ヒートマップの導入
ユーザーがページのどの部分をみているのか。どこをクリックしているのか。
を可視化してくれるヒートマップサービスを導入してみます。

今回はメールアドレスで登録後、表示されるHTMLタグをHEADタグ内に挿入するだけでヒートマップを取得できるuserheatというサービスを導入してみました。
https://userheat.com/

一定のPVが溜まってきたら、ヒートマップを分析してページのUIを改善していきましょう。

# 8. その他
## 8-1. タスク管理
自身の開発スタイルに合わせて、お手軽に使えるタスク管理ツールを見つけておくとよいでしょう。

個人的にはTrelloが好きです。
https://trello.com/ja

↓別で少し長くやっている個人開発のボード
<img width="1440" alt="スクリーンショット 2019-07-30 15.50.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469846/786cbd19-969d-69dd-fa46-11e5d900c04b.png">



## 8-1. 利用規約・法務
私も法律関係に強くないので細々としたことはわからないですが、兎にも角にも利用規約は用意しておきましょう。

収益性が無く、サービスの性質上、外部への影響の少ない小さなWEBサービスであれば利用規約のテンプレートを作成・管理してくれている法人様があるのでそちらをカスタマイズしていけばひとまず大丈夫でしょう。
https://kiyaku.jp/index.html

お金が発生したり、出会い系が絡む場合は法律事務所に相談したほうがいいかと思います。最悪しょっ引かれます。

また、当サービスでは取得していませんが、個人情報を取得する場合には、プライバシーポリシーの設計も必要になります。

## 8-2. ドキュメンテーション
お気に入りのドキュメントサービスをみつけて、マークダウン等で簡易なドキュメントを作成しておくと良いでしょう。

システムコンセプトから設計方針、APIの調査内容や、画像・アイコンの参照元など逐次明文化しておくと忘れた時に役に立ちます。

この記事も開発時に書いたドキュメントから記憶が復元されています。

## 8-3. Firestoreとセキュリティ
Firestoreは原則としてWEBから直接アクセスされるものであるため、最低限のセキュリティ担保のため、ある程度手を打っておく必要があります。

最も一般的な手法としては、firebaseにある「ユーザー認証によってデータごとのアクセス可能者の設定を行う」機能を利用することです。

今回のサービスでは特定の個人を認証・区別する必要がないため、firebaseの認証機能のうちの一つ「匿名認証」という機能が利用されています。

また、firestoreへの直接の読み込み・書き込みを禁止し、firebase-functions(AWS Lambda的なやつです)を経由してアクセスすることでリスクを低減させる手法もあります。

## 8-4. Firestoreとバッチ処理
データの定期集計などのバッチ処理はfirebase-functionsにfirestore内のデータを巡回するコードを書き、これを外部からcron的に叩きに行く手法がお手軽です。

ただし、functionsはどこからでも叩けてしまうため、手でAPIキー認証的なものを実装する必要があるでしょう。

## 8-5 Firestoreとタスクキュー
WEBサービスのフロントからサーバーサイドの重い処理を呼び出す際には「タスクキューを用いた非同期処理」という方法をよく用います。

Firestoreを利用したタスクキューの実現方法としては、特定のコレクションの変更を監視(onSnapshotというコレクションの常時監視関数があります)し、タスク追加時にワーカープロセス(要するに処理関数)を起動する、という流れになります。

調べたら公式のライブラリがありましたのでこちらを利用するとよいでしょう。（node.js等サーバーが必要です）
https://github.com/FirebaseExtended/firebase-queue


# 課題
- ビル街だとGPSがずれがちなのでそもそもの価値提案として破綻している説（そもそも論）
- お金がないので無料枠を超えたらサービスがダウンする

# あとがき
いかがでしたでしょうか。プログラミング初学者の方に「なんか色々やることあるけど、これらのステップを踏めば一応のサービスの形になるんだなー」というイメージを掴んでいけたのなら冥利つきます。