Go + Vue.js + FirebaseUI で「少人数リモートチームのためのYWT振り返り用ツール」を試作した感想
これは 株式会社ピーアールオー(あったらいいな!を作ります) Advent Calendar 2020 2日目の記事です。昨日は pro_matuzaki さんの「アドベントカレンダーの各記事の投稿状況、いいね数などを簡単に確認したい(2020年版)」でした。
目次
はじめに
- リモートで YWT するのに最適だと思うツールが無かった。(※ YWT とは「やったこと・わかったこと・つぎやること」というフォーマットで振り返りを行うやり方です)
- フルスタックフレームワークでしか Web アプリを作ったことがないと言っても過言ではないので、本当に Web アプリを作る上で必要な知識を持てているのか不安だった。
- 仕事ではレガシーな環境の保守をしており、プライベートでの自学自習でモダンな開発を学ぶ必要がある。
上記の動機で Go + Vue.js + FirebaseUI で「少人数リモートチームのためのYWT振り返り用ツール」を試作しました。
本記事はその感想などを書きます。
使用技術
バックエンド:Go 1.14。Web フレームワークの Echo v4.1.16 を使用。ただし認証のみ FirebaseUI を使用。
フロントエンド:Vue.js 2.6.11
環境まわり:Docker Compose 使用。バックエンドとフロントエンドの間に Nginx をかませている。DB は MySQL 8.0(ただしユーザー情報のみ Firebase に保存される)。
以下長いので最初にまとめを書きます
動機に対するまとめは
- 自分が考えるリモート YWT に最適なツールをある程度形にできた。
- 薄いフレームワークを使ったことにより、特に基本的なセキュリティに関する理解が深まった。
- Go + Vue.js + FirebaseUI という私にとっては比較的モダンな環境で開発を行えた。
全体の感想としては、ある程度の学びは得られたものの十分ではなく、今後も仕事で使わないことについて自学自習していく必要があると思いました。
作ったものの概要
ソースコードは https://github.com/k1350/ywts-go にあります。
想定ユーザー
複数の拠点に所属する人から成り、物理的に一か所に集まって振り返り会を行うことが困難だが、YWT による振り返りをしたいと思っている少人数のチーム。
動作環境
社内ネットワーク上に Docker で VM を立てて動かすことを想定しています。(※ただし私は自分の PC 上での動作しか確認しておらず、実際に社内ネットワーク上に立てて期待通り動作するかは不明)
主な機能
このアプリでは一つの振り返りを一つのボードで管理します。トップページはボード一覧です。
自分が作ったボードはボード情報の編集・削除・参加用 URL のコピーができ、他人が作ったボードからは退出できます。
ボードの追加はトップページの+ボタンで行います。
トップページからボード名をクリックするとボードに遷移します。
ここにはボードの参加者が書いた YWT が並びます。自分の YWT のみ編集・削除できます。
YWT の追加はボード画面の+ボタンで行います。
ボードへの参加方法ですが、ボードの管理者がトップページで参加用 URL をコピーし、それを参加者に展開します。
参加者はログイン状態で参加用 URL を踏むとボード参加画面に遷移し、ボードに参加できます。
その他、上部メニューからユーザー名とメールアドレスを変更できます。パスワード変更はログイン画面のパスワードリセットからやれます。
学びと感想
JWT とセッションについて学んだ
フロントエンドの認証まわりに FirebaseUI を使っており、Firebase Authentication の JWT が発行されます。当初はこの JWT をフロント/バックエンド間の認証でも流用できないかなと考えていました。
しかしバックエンドとの通信に JWT を載せるならフロントエンドのどこか安全な場所に JWT を保管しておく必要があります。
JWT は localStorage に保存すればいいという記事も見たのですが、色々調べた結果、少なくとも私としてはフロンドエンドには JWT を保管できる安全な場所は無いという結論に至りました。
そのため結局フロントエンドとバックエンドの間には昔ながらのセッションを張ることにしました。
しかしセッションを張ることにしてからも楽勝ではありませんでした。
Laravel のようなフルスタックフレームワークでは、ログイン時にセッションを張る・ログアウト時に破棄する・CSRF 対策のトークンを発行するといった基本的なセキュリティ対策は勝手にやってくれます。
そのような点を今回は自力でやっていく必要がありました。
- そもそもセッションや Cookie とは何なのか
- セッションはどのようなときに危険にさらされるのか
- どうすればセッションの安全性を高められるのか(たとえばCSRF対策の実装など)
といった基本的なことについて(セッションを張る部分はパッケージは用いましたが)自力で実装したことで、読み物で読むよりもきちんと理解することができました。
Go 言語で一部理解に時間を要した
そもそも Go 言語を選んだ理由は静的型付言語が好きであることと、シンプルな言語が良かったからです。開発体験はとてもよかったです。
ただ自作パッケージの import 方法が当初は調べても理解できず、結局二か月ほど main パッケージだけで実装していました。
私が Go 言語で作成されたプロダクトを触ったことがないこと、いきなり Docker Compose で開発を始めるために参考記事をなぞって環境構築してしまったことにより、Go 言語で開発する上で理解すべき環境まわりを理解せず開発を始めたのが原因だと思います。
一度ローカル環境か単独の VM 上で自力で環境構築し、まず GOPATH などの概念をよく理解すべきでした。
その他、ディレクトリ構成のベストプラクティスや Echo でバリデーションのために作る構造体のうまい作り方などは今もまだよくわかっていません。構造体は本当にぐちゃぐちゃに乱立しています。
Go 言語自体は好きなので、今後も使いながら理解していきたいと思います。
FirebaseUI は趣味アプリならありだと思う
今回認証まわりは作りたいものの中心ではなかったので FirebaseUI を使いました。
画面遷移のパターンやURL、デザインなど一切こだわらなくていい趣味アプリで使うのはありだと思います。
ユーザー登録もパスワードリセットも自動で作ってくれて便利でしたし、やろうと思えば Google ログインや Facebook ログインもすぐ実装できるみたいです。
ログイン画面とユーザー登録画面を分けたい、画面タイトルを変えたいといったニーズには対応できないので、そのような場合は Firebase Authentication のほうを使うべきだと思います。
ただ私はプロダクトが大きくなるかどうかにかかわらず「月に〇〇アクセスまで」といった制限が気になるほうで、結局自分のDBにユーザー情報を持ちたくなったので、Firebase は不向きかもな……と思いました。
今回はユーザ名だけ MySQL に持つという構造にして、ログイン時とユーザー情報変更時以外は Firebase にアクセスしないようにしました。
JavaScript の書き方を理解するまでに時間を要した
私は仕事ではたまに JQuery を書く程度であり、プライベートでも Vue.js を何度か触ったことがある程度で、モダンな JavaScript にまったく追いつけていない自覚があります。
特に(JavaScript に限った話ではないのですが)非同期処理が苦手です。しかも JavaScript では非同期処理を直列化する方法にコールバック関数、Promise、async/await など色々あって難しく感じています。単に書き方が違うだけだというのはわかっているのですが……。
今回 FirebaseUI ではログイン後の処理としてコールバック関数を使用することを要求され、「コールバック関数がわからないから async で書こう」といったことはできませんでした。
そのため全然わからなくても理解しなければならず、相当苦戦しました。
今どき JavaScript もきちんと書けないのではかなり危ういので、仕事で使っていないことを言い訳にせず、今後も自主勉強が必要だと思いました。
今回実装できなかったことについて
下記は実装する前に開発をやめました。
- 本アプリを社内ネットワーク上で起動したとき社内のみんながアクセスできるかの確認、およびアクセスできなかったらアクセスできるようにする実装
- 本番環境で動かす想定の Docker Compose の設定
- ボード一覧や YWT 一覧のページング機能といった一部機能の実装
特に Docker Compose の本番環境用の設定はいつかチャレンジしたいと考えています。プライベートの開発でしか使ったことがなかったので、今まで開発に使っていたものをそのまま本番環境に持っていってポンと立てられるのかと思っていました……。
参考文献
アプリを作成するにあたり参考にした記事です。(記録していた分だけ。また最終的な仕様には使わなかったものもあります。)
- Go(Echo) + Vue.js + nginx の環境をDocker Composeで立てる。
- Docker volumeの削除
- Backup, restore, or migrate data volumes
- GoでMySQLを利用する
- golangでMySQLのTransactionを実装してみる
- Go言語でセッション管理
- Vue - check if you are on the last prop of a v-for loop
- Targeting last item in v-repeat with Vue JS
- 【レスポンシブ】CSSで作るtableデザイン&コーディング【コードあり】
- 現代開発者のためのCSS基礎技術
- 「Vue.js + Go言語 + Firebase 」で始める! Frontend & Backend API 両方で認証するセキュアなSPA開発ハンズオン!
- 2020年後半版Vue.jsを使ってる人には必ず知っていてほしいVue.jsの武器とドキュメントに書かれていないコンポーネントやメンテナンスの際に役立つTips
- Promiseとthenのメソッドチェーン(直列・並列・値の受け取り・引数)
- 【JWT】 入門
- JWT・Cookieそれぞれの認証方式のメリデメ比較
- JWTでセッション管理してはいけない
- セッション乗っ取り:#1 セッションIDとセッションID侵害手口
- 3分でわかるXSSとCSRFの違い
- ログイン時のCSRF対策は必要か
- とっても簡単なCSRF対策