GAミント至上主義

Web Monomaniacal Developer.

このブログについて(先頭固定)

【お約束】 投稿内容は個人の見解であり、所属する(していた)組織の公式見解ではありません。

名前:uyamazak(昔いた会社で上司が開発用Linuxサーバーのユーザー名に「yuyamazaki」が長いので勝手に作ってくれた。読み方わからないけどウヤマザク)

高校あたりからWEBサイトをやったり趣味の延長でWEB系を仕事にした感じの人間。

2020年1月から株式会社シニアジョブにジョイン。
まだ開発者の社員は2人、これからの会社なのでインフラからきれいな設計をしたい

アズールレーン@竹敷でモバイルのUI、UX研究中(初嫁ジャベリン)

GitHub: https://github.com/uyamazak/

これまでの主なプロジェクト

続きを読む

Mac OSでFirebaseローカルエミュレータを動かす。Javaが必要

Firebaseのローカル開発環境で、Pub/Subだけ動かしてなかったので、最近リリースさればばかりのUIとともに試してみることにしました。
Mac OSのバージョンは10.15.4。

firebase.googleblog.com

CLIのバージョンが8.4.0以上なのを確認

$ firebase --version
8.4.0

起動しようとしたところ、Javaがうんたらのポップアップともに下記のエラー。nodeのバージョンは気にしない。

firebase emulators:start                     
i  emulators: Starting emulators: functions, hosting, pubsub
⚠  Your requested "node" version "10" doesn't match your global version "14"
i  hosting: Serving hosting files from: public
✔  hosting: Local server: http://localhost:5000
i  pubsub: Pub/Sub Emulator logging to pubsub-debug.log

Error: pubsub: Pub/Sub Emulator has exited with code: 1

ログには

No Java runtime present, requesting install.

検索したところ、下記の要件に
エミュレータを使用したローカルでのアプリのテスト  |  Cloud Pub/Sub ドキュメント  |  Google Cloud

Java JRE(バージョン 7 以降)がインストールされている。

とあったのでまずはJREをインストール。

無料Javaソフトウェアをダウンロード


なんか設定で許可するのが必要だったけど無事インストール。

しかし、もう一度叩いてみても同じエラーでした。
どうやらコマンドラインから使うにはJDKも必要なもよう。


こちらからJDKのバージョン8をインストールしました。

java.com


これで無事先程のコマンドのエラーもなくなり、UIの機能をダウンロードし、サーバーが起動しました。

firebase emulators:start

http://localhost:4000/をブラウザで開くとこんな感じ。
f:id:uyamazak:20200527114740p:plain

まだ開発始めたばかりで使う機能は限られているけどFirestoreとか捗りそう。

まずはこれでFunctionsへのリクエストのテストを書きたいけどどうすんだろ。

ユーザーの閲覧履歴をRedisのSorted Setを使って保存&表示する

ユーザーの閲覧履歴をDB(MySQL)からBigQueryに移すにあたり、既存のDBを使っている「最近見たお仕事」を表示する機能も変更が必要になりました。

「最近見たお仕事」は文言は異なるものの、よくECなどでも「最近チェックした商品」、不動産系では「最近見た物件」などと表示されてるやつです。

BigQueryに入っている履歴を使うのも考えましたが大きく以下の3点から別の実装を検討しました。

  • スキャン料金を抑えたい
  • クエリに時間がかかる
  • タイムラグがあるためさっき見たページが表示されない可能性がある

セッションも考えたけど、同じくDBに入ってしまうので、負荷がかかるのでいまいち。

そこで考えたのがRedis。ずっと残しておく必要も無いデータなのでちょうど良さそう。

ハッシュ型でもできそうですが、いろいろ使える型を見ているとSorted Setが今回の用途にぴったりでした。

RedisのSorted Setとは

一つのキーに対してスコアを持った複数の値(メンバーと呼ばれる)を保存でき、常にスコア順に入っているのでスコア順で高速に取得ができます。
またSetなので、重複は入りません。最近みたページには丁度いい

その特徴からよくランキングに使われています。
qiita.com

今回はスコアにタイムスタンプ値を使うことで「最近見たお仕事」を実装しました。

保存する処理

ZADDコマンドを使います。

使用する言語、ライブラリなどにより異なりますが、生のRedisコマンドで書くとこんな感じ。

redis> ZADD recenrtyview:{ユーザーID}  タイムスタンプ値 "{ページID}"

適当なprefix (上記だとrecenrtyview)とユーザーIDをキーとして、事前に出しておいたタイムスタンプ値と、ページのIDを入れておきます。
この処理をページを見たときの処理に入れておけばOK。

有効期限を設定する

今回はさらにその追加した値に有効期限を付けて、ゴミが溜まらないようにしました。

下記を参考に念のため、MULTIを使ってトランザクションもしておきます。
qiita.com

EXPIREは秒で指定するため、今回は30日、 60*60*24*30 = 2592000を使います。

redis> MULTI
redis> ZADD recenrtyview:{ユーザーID}  タイムスタンプ値 "{ページID}"
redis> EXPIRE recenrtyview:{ユーザーID}  2592000
redis> EXEC

もし同じページIDを見た場合はスコアのタイムスタンプ値と、有効期限の両方が更新されます。

取得する処理

今回は新しい順、タイムスタンプ値が大きい順に取得したいので、ZRANGEの逆版、ZREVRANGEを使います。

ZREVRANGE – Redis

redis> ZREVRANGE recenrtyview:{ユーザーID} {start} {stop}

start, stopのindexは0始まりなので、最新10件であれば下記のような感じ。

redis> ZREVRANGE recenrtyview:{ユーザーID} 0 9

これで、保存されたページIDが欲しい順番で返ってくるので、それぞれの情報を取得して、表示すれば完了です。

今回実装したのは下記のサイトのそれぞれのお仕事詳細ページの下の方で使われています。
シニア・中高年の求人・仕事探しなら【シニアジョブ】
f:id:uyamazak:20200526164000p:plain
情報の入れ替わりが激しいのでぼかしといた


ということで、ランキング以外にもSorted Setが使うのがぴったりな用途を見つけたので記事にしました。
RedisのSorted Setを使うことで、高速で、かつ構造もシンプルでバグも少ない実装が出来た気がします。



IEで起こるJavaScriptエラーをpolyfill.ioを使ってなんとかする

シニアジョブでは、まだまだ古いPCを使っているシニアの方が多いのか、令和になったこの頃でも、残念ながらIEのアクセス数が無視できない程度に健在です。

JavaScriptのエラーが起きてしまうとその後の処理が止まってしまったり影響が多いため、なんとかしたいところ。

でもVueなども使っており、全部をIEでも動くコードに書き換えることは現実的ではないので、ポリフィルを使った対応を行っています。

ポリフィルとは

IEなど古いブラウザにない機能を追加するコードのこと。詳しくは下記。
Polyfill (ポリフィル) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN

polyfill.ioとは

選択したポリフィルをブラウザーに合わせて、必要なだけ配信してくれるサービスです。
生成したURLをscriptタグで読み込むだけで使用できます。

Chromeなどでアクセスするとコメントだけのファイルが返ってくるのが確認できます。

polyfill.io

それぞれの機能ではなく、es5などのセットもありますが、余計なコードを読み込ませるのを防ぐため今回はエラーを見て一つずつ追加しました。

今の所こんな感じ

    <script src="https://polyfill.io/v3/polyfill.min.js?features=Element.prototype.classList%2CPromise%2CIntersectionObserver%2CObject.entries%2CObject.keys%2CArray.prototype.forEach%2CNodeList.prototype.forEach"></script>

ポリフィルでは対応できないエラー

文法エラー(Syntax Error)は残念ながらポリフィルでは対応できません。
主にconst, letと、アロー関数があるので、それは書き換えが必要です。

const hensu = 1;
# var hensu = 1; に変更

アロー関数はthisが変わるのでちょっと注意が必要かも。

BabelやTypeScriptを使ってる場合はビルドオプションでなんとかできるはず。

動作確認の方法

Windowsがあれば、IE11と互換モードでIE9までテストできますがシニアジョブでは基本的にMacなのでそうは行きません。

今回はVirtualBoxとMS公式のVMを使いました。Windows10とIE11が動かせます。重い。
Virtual Machines - Microsoft Edge Developer

どうやって必要な機能を選ぶか

IEで該当のページを開きF12などで開発者ツールを開き、その「Console」タブを開きます。
こんな感じでエラーが出ると思います。

f:id:uyamazak:20200519104436p:plain
f:id:uyamazak:20200519103627p:plain

IEのコンソールのエラーはまじクソで該当の箇所を示してくれず、MS社員がどうやってDebugしてたのか謎の機能なので、行数と文章でなんとかあたりをつけます。
私が使いこなせてないだけかもしれませんが、使いこなす日はこないでしょう。

あたりを付けた機能を下記ページで選択してURLを発行して読み込ませます。
https://polyfill.io/v3/url-builder/

今回のエラーだとnowはおそらくDate.nowだろってことで追加したらエラー消えました。
forEachは、Array.forEachだろと思いましたがNodeListの方だったっぽい。でも両方使う機会が多いので追加しておきました。
Syntax Errorは上記のconst でした。


Polyfillを使った対応は最善では無いですが、IEも減ってきて、最新のJS機能を使いたいこの頃では、現実的な解決方法だと思います。