usakoのV8 Runtime対応+疎結合化を行いました
概要
自粛期間中なのでプライベートで運用しているusakoをgithubに公開し、その勢いで結合度を下げ、V8 Runtime対応をしました。
自分的にはとても頑張ったのですが、仕事じゃない分誰かに見てもらうことは無く…でも頑張ったので見てほしく…。
そんな思いの丈をブログにしたためます。
前提知識
usakoとは
2016年頃からプライベートで運用しているLINEbotのことです。
2017年のものですが、以下に大雑把な概要と構成を書きました。
もはや懐かしい…
inside.dmm.com
ずっとソースを公開したかったのですがGASのためコピペ以外の公開の術がなく…。
別の言語にリプレイスしようと思いつつも、とはいえ普通のサーバーサイドの言語にするとサーバー費用がかかってしまうことが気になって、なかなかリプレイス作業が進んでいませんでした。
そんな中、以下の記事を発見しGASのまま公開に至ることができました(ありがたい〜〜〜)。
qiita.com
gitに載せる際に公開したくない情報を別で切り出していったのですが
流石に4年経ったコードで目に余り、勢いに乗って機能ごとにリポジトリを分けられるように改修を進めることにしました。
V8 Runtimeとは
GASではES6の構文が使えなかったのですが、V8 Runtimeの導入によって利用が可能になりました!
V8 Runtimeで動くようにすると動かなくなる構文もあったので、
リポジトリに切り出すついでにV8 Runtimeで動くように修正しました。
…とはいえ、最低限の対応しかしていないので変数宣言がほとんど var
のままだったりはありますが…
V8 Runtimeについては以下に記載があります。
developers.google.com
対応したこと
プロジェクトを細かく分断しました
usakoはこれまで、以下のような構成でした。
- メインのプロジェクト - LINEのwebhookに対応するため `doPost()` が書いてあるもの - 家事管理機能 - サマリ通知機能 - リマインド機能 - ログローテート機能 - 家計簿管理機能 - サマリ通知機能 - リマインド機能 - ゴミの日通知機能 - ランダムメッセージ返却機能 - LINE周りの処理をまとめたプロジェクト - 買い出しリスト周りのプロジェクト
これらを、以下のように分けました。
- メインのプロジェクト - LINEのwebhookに対応するため `doPost()` が書いてあるもの - 家事管理機能をまとめたプロジェクト - 家計簿管理機能をまとめたプロジェクト - メッセージ周りをまとめたプロジェクト - ゴミの日通知機能 - ランダムメッセージ返却機能 - ※各リマインドは各プロジェクト内に格納 - LINE周りの処理をまとめたプロジェクト - 買い出しリスト周りのプロジェクト - 横断で利用する処理をまとめたプロジェクト - 非公開情報を取得するためのプロジェクト
とにかくメインのプロジェクトが大きかったので、大変でした…。
usakoはスプレッドシートをDBのように利用しているのですが、 メインのプロジェクト
はそのスプレッドシートのスクリプトとして設定しているため、各リポジトリに分けるときにシートの取得方法も変えなくてはならず…。
1度わかれば後は大丈夫ですが、Activeなシートを編集したいときに SpreadSheetApp
クラス、 SpreadSheet
クラス、 Sheet
クラスの3段階を経ないといけないという部分はハマりました…。
// フォームと連携しているシートをアクティブにする const currentSpreadSheet = SpreadsheetApp.openByUrl(secret_obj.getMainSheet()); // スプレッドシートオブジェクトをActiveにしてからシートオブジェクトをActiveにしなければならない(GASの仕様っぽい) SpreadsheetApp.setActiveSpreadsheet(currentSpreadSheet); const currentSheet = currentSpreadSheet.getSheetByName('家事代_今月'); SpreadsheetApp.setActiveSheet(currentSheet); // 年月(YYYYMM)の名前でシートをアーカイブ const month = dt.getMonth() == 0 ? 12 : dt.getMonth(); const year = month == 12 ? dt.getFullYear() - 1: dt.getFullYear(); // 以下の dupulicateActiveSheet のためにActiveにしないといけない SpreadsheetApp.getActiveSpreadsheet().duplicateActiveSheet().setName('家事代_' + String(year) + String(("0"+(month)).slice(-2)));
このブログを書くために改めてリファレンスを読んでますが、もしかして copy()
ならActiveにしなくてもよかった…?
V8 Runtime対応
JSを十分に理解して書いているとは言えないレベルのコードなので、繰り返し処理一つとっても for()
for each()
array.forEach()
などバラバラ…。
今回の対応では主に、V8 Runtimeでは廃止になっている for each()
を for()
に変更するのがメインでした。
この他、たまーに紛れ込んでいる getYear()
を getFullYear()
に変更したり、 const
let
に置き換えられそうなところを置き換えたり…というようなことをやりました。
普段メインで書いてる言語はphpなので、 const
let
の使い分けを理解するいい機会になりました。
usakoは長文のメッセージを返却することが多いのでテンプレートリテラルについても取り入れていきたいですね。
月ごとの出費をグラフでも出力するように
もともと月次でいくら使ったか通知する仕組みはあったのですが、バグがありしばらく動いてませんでした(かわいそう)
これを機にバグを修正し、またこれまでほっといたことへの懺悔も込めて機能を追加しました。
スプレッドシートにはすでにグラフを公開する機能があります。
※なんとグラフに利用している数値が更新されたら、自動でグラフのほうも更新してくれます 👏
support.google.com
この機能を利用して、毎月直近12ヶ月のグラフ画像を更新する処理と、通知内容に公開したグラフのURLをつけるようにしました。
こんな感じで、グラフに利用する数値を毎月アップデートすることでグラフの画像を更新しています。
// グラフシート更新(全件削除→対象期間分記載) const targetTerm = 12; // 直近12ヶ月分 const targetData = summarySheet.getRange(1, summarySheet.getLastColumn() - targetTerm, summarySheet.getLastRow(), targetTerm).getValues(); for (var key in targetData) { targetData[key].unshift(indexes[key][0]); } graphSheet.getRange(1, 1, summarySheet.getLastRow(), targetTerm + 1).setValues(targetData);
はじめにグラフを手動で設定する必要はありますが、以降は何もせずともグラフを更新してくれるので助かりますね。
基本的にハマりどころはないですが、強いて言えば以下2点にご留意ください。
- 共有形式は
インタラクティブ
ではなく画像
を設定するのがおすすめです- LINEのアプリ上でURLをクリックしてグラフを表示するのですが、
インタラクティブ
だとうまく表示できないようです
- LINEのアプリ上でURLをクリックしてグラフを表示するのですが、
- スプレッドシートの該当範囲が更新されてから、公開したURLで表示される画像が更新されるまでにラグがあります
- 反映までにラグもあるし、何度もページを更新すると前の状態が一瞬出たりもしました
- ゆっくり落ち着いてデバッグしましょう
うちの環境では家賃以外をグラフの描画対象にしています。
LINEアプリの方でサムネイルも出してくれるとありがたいのですが、今のところは出ないようですね…。
今後のアップデートに期待です。
今後やりたいこと
CI構築
以下の記事を参考に、CI環境を構築してみたいです。 undersooon.hatenablog.com 今まではgit管理できていなかったのでそういう発想もありませんでしたが…
- GASのwebエディタから脱却
- ステージング環境を用意
の2点はぜひ取り組んでいきたいところです。
ただ個人のアプリケーションでLINEのアカウントを2つに分けてまでステージングが欲しいかというとそうでもないので
ステージング環境については構成を考え中です…。
claspを使えばエディタは自分の好きなものにできても実行環境はやはりGAS上にないと…ということらしいので、合わせて考え中です。
今はやりかたがわかってませんが、そのうち単体テストを流せるようになるといいな…。
コーディングスタイル統一
ある程度は統一したつもりなのですが、関数名・変数名ともにキャメルケースとスネークケースが混ざっており…。
phpであれば PSR
があるので、GASもしくはJSでそういうのがあるならそれに寄せていきたいなと思ってます。
なくても一定のルールは引いておきたいなあとは思いつつ、今回の対応では妥協してます。
スターターキット生成ツールの構築
usakoはスプレッドシートやGoogle Formなど必要なツールが地味に多く、また初見では理解しにくいものが多いと思っています。
でもせっかく公開したので興味を持ってもらえたら利用してもらえると嬉しいので、個人の設定を入れたら必要最低限のものについては自動で構築してくれるツールを公開したいなと…。
もとがGASだしどれもGoogleのツールなので、多分作れるだろうとは思ってますが詳細については考え中です。