下林明正のブログ

個人的かつ雑多なブログです。

ReactとNext.jsのチュートリアルをやって、高級AIに質問しながら簡単なライフカウンターをつくった

以前の

shimobayashi.hatenablog.com

からほとんど何もやってなかったので全部忘れた。 せっかく正月休みを取ったので再度勉強しようと思って、とりあえずKindle本のハイライトだけ読んだ上で新しくなったReactのチュートリアルをやった。

ja.react.dev

真面目に自分でコードを書きながらやったら数時間くらいかかった気がする。

その後、Create React Appがもう推奨されなくなったことだけは知ってたけど、何かしらのフレームワークを使えという圧をめっちゃドキュメントから感じたので、せっかくなので業務などでも知識が活きそうなNext.jsのチュートリアルもやることにした。

nextjs.org

別にしょぼいコードをちょっと書いてみたいだけなんだが……と思いつつ、がんばってチュートリアルをやった。これは結構時間がかかって、日を跨いだ。

その時の残骸がこれ。

github.com

正直、自分がつくりたいサービスよりも圧倒的に複雑なものをチュートリアルでつくったと思う。

チュートリアルでやったあれ何だっけ?と自分のリポジトリ見ながら記憶を辿れるのは良いと思う。 けど、今はPages RouterってやつとApp Routerってやつの過渡期らしく、チュートリアルで覚えたのはApp Routerだけどちょっと古いコードとかは基本Pages Routerっぽいので、どれくらい知識が活きるのか、という話はありそう。

今更Vercelもはじめて触ったけど確かにこれは楽そう。herokuを初めて触ったころを思い出した。 Next.js自体もなんかクライアントサイドとサーバーサイドのロジックを割とシームレスに書ける感じで次世代開発体験って感じがした。これもRails 2を初めて触ったころを思い出した。

とりあえずこれで自分で何かコードを書いて動かせる状態にはなった。


この間にオンライン飲み会を挟んで、酒に酔った勢いでOpen AIに金を払って高級AIを利用できるようにした。 毎月$20もかかるので、Spotifyの3倍以上のうれしさが欲しい。

ので、せっかくだからChatGPTになるべくコードを書かせてMtGで使うライフカウンターを実装をしてみた。

github.com

life-counter-app.vercel.app

多分ちゃんと動いてるはず。

ライフカウンターという題材を選んだのは、思いついたネタの中では比較的継続的にメンテする可能性がありそうな気がしたから。 別に、通常は既存のアプリを使ったら良いとは思う。

ChatGPTは思ったよりも割とちゃんとコードを書いてくれたけど、手直ししながらじゃないと厳しい感じはした。 サボってあんまりちゃんとドキュメントも確認してないので、もしかしたら変なコードがたくさん入ってるかも知れない。

逆に、デザイン的な作業はあんまりうまくやってくれなかった。 まあもしかしたら、これは自分のスキルの問題もあるかも知れない。

でも全体的には、結構役立ってたと思う。結構待ち時間が長かったりもするので、自分のChatGPTの使い方がこなれてくるともっと役立てられそうな気はする。


技術的な勉強もできたし、ChatGPTの使い方もちょっと分かってきた気がするので、有意義だった気がする(他にも、Wizardry風のゲームをつくるとしたら仮置きのモンスターグラフィックをつくらせてみたいな、とか妄想して画像を吐き出させて遊んだりもしてた)。 なんか全体的に時代の進歩を感じたので、普段取り残されているのだと思う。

気が向いたら以下のようなこともやってみたい

  • ChatGPTにテストも書かせる
  • ChatGPTにコードコメントも書かせる
  • 何らかの方法で背景画像に任意の画像を指定できるようにする
  • 何か良い感じの背景画像をDALL-Eに描かせる

SPAの時代になってきてちょっとしたスクレイピングも面倒な感じになってきてしまった

github.com

  • 現状では名前に反して特定のサイトを特定の方法でスクレイピングすることしかできず、特定のサービスにしか投稿できないので、特に汎用性は無い
  • 特定のサイトを特定の方法でスクレイピング→将来的にはYAMLかなんかでXPathなどを書き連ねて定義できるようにすると、汎用性が上がって良さそう
    • 似たような事情でスクレイピングしたい対象が出てきたら対応を検討すると良さそう
  • 特定のサービスにしか投稿できない→なんかヘッドレスCMSってやつに投稿できるようにしたり、プラガブルな構造にすると良さそう
    • ヘッドレスCMSのことは何も知らない。でもおそらくは自前でつくったGitHub - shimobayashi/vimagemore: AWSでサーバーレスってやつで画像をアップロードしてフィードを吐き出してくれるやつ。程度のことは当然できそう。問題があるとしたらコスト最適なソリューションがあるのかどうかというところにありそう
      • 自前でつくったやつはとにかくコストを抑えることを第一につくったので、月額100円もかかっていないしまあまあ快適(そしてBillingを見たらAWS SAAの勉強のときに消し忘れたリソースがあることに気づいたので消した)
    • プラガブルな構造にしても自分は投稿先は1つしか無いのであまりうれしさは無い気はする

世知辛いですね。

CO2濃度の監視をCO2-miniとMackerelとRaspberry Piで実現する方法

CO2濃度が高まると衛生管理上よろしくないとされています。 リモートワークがしばらく続きそうなので自室のCO2濃度を監視することにしました。

できあがったグラフ

f:id:shimobayashi:20200418123150p:plain

こういう感じでグラフにできました。平気で1000ppmを超えていることが多いですね。換気扇を回すとCO2濃度が下がっていることがわかります。

しきい値は一旦1000ppmでwarning, 1500ppmでcriticalとしてみました。 このあたりはこれから運用しながら調整する予定です。

必要なもの

  • CO2-mini
    • CO2濃度を測れるUSBデバイス。マニュアルに記載は無いけどホストマシンから値を取得できます
    • 自分が調べた時点ではモノタロウで買うのが一番安かったです。日曜日に調べていたら土日限定の5%クーポンというのがあったので更に安くなりました
  • Mackerel
    • 数値を送るとグラフにしてくれたり、しきい値を越えるとLINEへ通知してくれたりします
    • 好みの監視ソリューションを使えばいいと思いますが、後述の自分が書いたコードはMackerelにしか対応していません
  • Raspberry Pi
    • さしてスペックは必要ないので、古いRaspberry Piでも十分です。自宅にはRaspberry Pi 2 B+が余っていたのでそれを使うことにしました
    • 別にRaspberry Piじゃなくても24時間つけっぱなしのネットワークにつながるマシンなら何でも良いと思います
  • GitHub - shimobayashi/co2-mini-to-mackerel: CO2-miniで取得できる数値をMackerelへ投げるだけのスクリプト
    • これらをつなぐソフトウェアです
    • 手頃なものが無さそうだったので今回自作しました。nodeで動いて、systemdでデーモン化できます
    • 使い方はREADMEを読んでください

感想

思ったよりも自室のCO2濃度が高かったことが分かりました。たしかに換気するとさわやかな感じがする。 一方で、あんまり換気していると室温的には問題なくても体感温度が寒いような感じもしました。 あと、寝ている間に換気扇を回しっぱなしにしていると騒音が気になるのか眠りが浅い気がするという問題もある。 このあたりはいい塩梅を見つけていこうと思います。

投資は自分の場合8000円+作業時間で済んだので、これで健康になれたり生産性が上がる可能性があるなら良いんじゃないか、という印象です。 可視化されたことで気にしすぎて気を病む、みたいなこともありそうなのでほどほどでいきたい。

換気扇のON/OFFをする運用になったら、次はSwitchBotとかで換気扇の操作を自動化したいです。 Mackerelのダウンタイムと組み合わせれば寝ている間は換気しない、ということもいい感じにできるかもですね。

作業記録

  • CO2監視ソリューションを調べる。Netatomoは高いし手持ちのNature Remoと役割が結構被っている。CO2-miniってやつをRaspberry Piにつないでうまいことやってる人たちがたくさんいたので、その方向性で進める
  • Raspberry Piはせっかくなので最新っぽいNOOBSでクリーンインストール
  • CO2-miniを読むやつは色々あるみたいだったけど、なんとなくお手軽そうに見えた GitHub - maddindeiss/co2-monitor: Measure CO2 and temperature in nodejs with the TFA-Dostmann AirControl Mini を試すことにする
  • 以下のような手順で動かせた
sudo apt-get update
sudo apt-get install libusb-dev # usbモジュールのビルドに必要だった
npm install
sudo node example.js # sudoしないとUSBデバイスに触れなかった。udev ruleとかいうやつをがんばって書けば要らなくなるかも知れない
  • 自分のコードからこのモジュールを使ってMackerelへ投稿できた
  • Raspberry Piはなんだかんだで再起動することが多いので、マシンの起動とともに勝手に動いてほしい。そのためにデーモン化してみる
    • 有名所ではforeverというnpmモジュールがあるようだけど用途が違うように見えた
    • 普通にLinuxの世界でなんとかするか、という気分になった。最近はsystemdってやつでこういうことするイメージなので軽く調べてみたところ、普通にやったらできそうだった
    • 適当にやったら意外とサクッとできた github.com
  • 完成

AWSで動く画像アップローダーへGithub Actionsから投稿できた

気づいたら2ヶ月くらいちまちまこれらをやっていた。

AWSで動く画像アップローダー

github.com

例のごとくSAMってやつでつくった。 画像をアップロードするエンドポイントを提供しつつ、指定したタグに紐づく画像のRSSをフィードをつくってくれるというもの。

  • テストも書いた。SAMは標準だとchai/mochaみたいな感じだけど仕事ではjestを使っているので頑張ってjestで書いた
  • jestだとAWS関連をうまくモックしてくれるライブラリが見つけられなかったので自分でちまちま書いていった。現実の挙動を予想しながらテストを書いているので実際に本番で動かさないと動くかどうかよくわからないという悲惨な状況。次はテスト用のスタックを作っても良いかも知れない
  • 何も考えずにDynamoDBを採用してしまったけど画像にタグをつけて管理するみたいなユースケースに全然向いてないと思った。そもそもDynamoDBはDynamoDBの制約を受け入れることによって強力なスケーラビリティを手に入れるという感じだなーと思ったのだけど、別に個人用途のプロダクトなのでスケーラビリティとかさほど関心がないしその点でも全然向いてなくて、ただただ大変なだけだった
  • Aurora Serverlessへ移行することも考えたけど、CFnでAurora Serverlessを扱うのがとてもめんどくさそうだったので目を背けてしまった。CDKを使えば楽できるのかも知れないけど、SAMの世界観から外れそうなので調べなかった
  • とはいえ、必要十分なものができあがったと思う。S3とかLambdaとかに乗っかることで今の所費用は発生していないはず
  • これくらいの規模になってくるとなんかもうtemplate.ymlとかがつらすぎるのでSAMじゃないほうが良いかも知れない(うまくスタックを分割すればいいんだろうか、不明)

Github Actionsから投稿できた

画像アップローダーだけだと意味がないので画像を投稿してみている。 Puppeteerでブラウズしてスクリーンショットを撮ってアップロードしている。

github.com

Puppeteerってやつにも興味があったのでPuppeteerを使ってみることにした。近年のSPAが当たり前という世界では以前のようにMechanizeとかではやりづらい気がするので。

PuppeteerをLambdaで動かすのは大変そうだったのでFargateで動かそうかと思っていたのだけど、Github Actionsってやつを使うと楽にできるらしいと聞いたので試してみたところ、本当に最高だった。最高というよりは、もはや信じられないという感想に近い。 Puppeteerはまあまあ使うのに癖がある気がするけど、慣れてくるとまあこんなもんかという印象だった。headlessとかもあって偉い。実ははるか昔にWatirを触ってからさほどこの手のやつには触ってこなかったので、改めて便利だなーとなった(SeleniumとかPhantomJSもあんまり触る機会がなかった)。

PuppeteerもGithub Actionsも覚えたことでやれることの幅がかなり広がった気がするのでやってみてよかった。

次にやること

去年の10月くらいから勉強がてらずっと何かつくっていたけど、これで一通り作りたかったものは作れた気がする。

scrapbox.io

に書いているように勉強したい項目はまだ色々とあるけど、なんか実際に手を動かそうというネタがぱっと思いつかない状態。 最近は仕事の方でもこれまであんまりやってこなかったパフォーマンスチューニング周りだったりインフラ周りのタスクをつかめているので、ひとまずはそれを継続して勉強していくで良いかなあ。

GCPで電気カーペットを勝手にON/OFFするやつをつくった

これです。

github.com

自分が使っている電気カーペットは6時間で自動電源OFFという機能があって非常に不便なので、偶然スマートプラグにつなげていたし8時、14時、20時に勝手にON/OFFすることでつけっぱなしにしようと考えたという感じです。 スマートプラグを持っていなければ普通にタイマー式の電源タップを買ったほうが楽だと思います。

電気カーペットの電気代なんて誤差なので別に24時間つけっぱなしでも良いんですが、まあ一応26時~8時の間はつけなくてよかろうという判断をしました。 平日の日中は家にいないだろうしもうちょっとがんばって人感センサーと連動させることも考えましたが、まあやっぱりどう考えても電気カーペットの電気代なんて誤差なのでまあ良いかとなった次第です。

実装としてはメチャクチャ単純ですね。これだとなんの勉強にもならないので今回はあえてGCPを使ってみることにして、以下のリポジトリを参考にしました。

github.com

github.com

感想としては、

  • GCPはAWSと比べると全体的にスッキリしている気がする。例えば複数リソースあるときにAWSだとCFnとか使わないとうまく管理できない気がしているけど、GCPだと階層構造がちゃんと考えられていてプロジェクト単位で管理できるのが良さそう。また、AWSだと権限周りで何かと悩まされるけど、GCPをちょっと触った限りではそもそも権限という概念自体表出しなかった。個人で軽く使うならGCPの方が良いかも
  • ただ、プロジェクトはCLIの方でもちゃんと切り替えないと誤ってリソースが紐付けられてしまうので注意が必要。このへんはちょっと慣れたら気にならなさそうだけど
  • FirebaseとGCPの関係が良く分かってない。雑に言うとHerokuとAWSの関係だと思えば良いのだろうか

という感じです。GCPのチュートリアルみたいなのも読まずに勘でやってるので、また触ろうという気持ちになったらもう少しちゃんと勉強したい気がする。ファーストインプレッションは良好です。

叩くと室温に応じて冷房か暖房をONにしてくれるAPIをTypeScriptとAWS Lambdaの勉強がてらつくった

起床前とか自宅に近づいたときにIFTTTとNature Remoで勝手にエアコンをいれるようにしてるんだけど、季節が移り変わると別に寒くないのに勝手に暖房が動いたりしてうっとうしくなりそうなので、Mackerelから室温を取得して適当にエアコンをいれてくれるAPIをつくることにした。

github.com

これを npm run build; sam deploy --guided --parameter-overrides "MackerelApiKey=XXX" "IftttApiKey=XXX" すれば多分誰でも使えるけど、Mackerelのサービスメトリクス名が固定だったりするのでおそらく実際は役に立たない(自分以外にこういうことやりたい人がいなさそうなのでサボっている)。

最近しばらくホームオートメーションとLambdaで遊んでるので似たようなことをしているように見えそうだけど、今回の主な差分はTypeScriptを使うようにしてみたところ。TypeScriptの勉強をしてみたかったんです。

当初は

www.linkedin.com

にある方法でオンデマンドにTypeScriptファイルをトランスパイルして動かそうと思っていて、Hello Worldを返すだけなら実際それでも動いたんだけど、本格的な実装が終わってから import axios from 'axios; するだけで実行がスタックしてしまうことが分かった。

使い物にならないし回避方法も分からないしうまくいったとしても実行効率が悪いはずなので、諦めて手元でトランスパイルするように方向転換した。ちょっと楽できるようにnpm-scriptsに書き足しておいた(けど手元でよく使うコマンドのみなので、例えば sam invoke 相当のものは書いてない)。

TypeScriptはまだ良くわかってないけど覚えられると色々と便利そうなのでもう少し勉強を進めていきたい。

以前つくったRSSフィードにguidを追加する簡単なサービスをAWSに移植した

これのことです。意外と2年前につくったものなんですね(もっと昔につくった気がしていた)。

shimobayashi.hatenablog.com

当初はherokuで動かしていたんですが無料枠をめちゃくちゃ圧迫するのでVPSに移して、今度はAWSの勉強がてらVPS撤退を進めようということにしたのでこのアプリケーションについてもAWSへ移植しました。

構成としては、以前はXPathFeedのようにストレージなどは持たずにリクエストがきたらパラメーターから動的にフィードを生成してレスポンスするというものだったところから、AWSでLambdaを定期実行してDynamoDBから設定を読み込んでフィードを生成してS3へ外部からアクセス可能な形でアップロードするというものに変更しました。

こういう構成にした理由としては基本的にはコスト削減以上の理由は無いですね。常時リクエスト可能なインスタンスを建てるとそれだけでVPS契約できるくらいのコストがかかりそうだったのでそれは避けたという形です。DynamoDBを使っているのはAWSコンソールからテーブルを操作できるので設定が楽だからというだけです。

多分そのまま sam build --use-container; sam deploy --guided しても皆さんのお手元では動かないけど(めんどくさがってDynamoDBがCFnの管理下になっていないため)、ソースコードは一応公開しています。

github.com

それにしても大したアプリケーションじゃないんですがAWSに不慣れということで変なところでいちいちつまづきました。 sam local invoke しながら動作確認して開発していたんですが、最後にエイヤッとLambdaにデプロイしてから不思議と動かない要素が多くて苦労したので、あんまりlocalで動作確認しても意味ないなと思いました。

以下、苦しみです。

shimobayashi.hatenablog.com

www.noobs.tokyo

特に require 'aws-sdk' はアンチパターンということが分かりました。なぜか動作がスタックするという以外にも、依存が大量に含まれているせいかビルド時間もデプロイ時間も急増するので、個別に指定したほうが良いです。

ともあれ、これでVPSで動いていたものは全部AWSへ移植できた気がするので先程VPSをシャットダウンしてみました。これで実生活に問題が無ければVPSを晴れて解約できそうです。

次は何を勉強しようかなあというところで、今んとこのネタとしては

  • CFn
    • template.yamlを勘で書いていて何もわからないので
  • CDK
    • SAM使ってるうちは使わなさそうだけど自分でCFnを使ってなんかやろうと思ったらYAML書きたくないので
  • TypeScript
    • CDKでも使えるっぽいしフロントエンドでもサーバーサイドでも使えて良さそうという雰囲気があるので
  • AWS SAA取得を目指してみる
    • そもそも体系的な知識がまったくないので

あたりかなあ。なんか良い勉強法などあれば教えて下さい。