最近のこと。主に Claude Codeで色々開発している話。


プロフィールページのリニューアル

これ→https://ricemountainer.net/

もともとCloudflare Pagesで動かしていたやつで、静的HTML1枚をぽつんと置いてあるだけのもので、ビルドも何もしてない非常にシンプルなものだった。できればこのままこの構成で続けたかったのだがPagesからの移行が必要ということで、あまり気乗りしなかったが対応することにした。実はこれのリニューアルがClaude Codeを使って本格的に始めた最初のプロジェクトである。どういう感じで開発できるのか試すにはちょうどいい素材だと思って着手した。

といいつつも、基本的にシンプルなHTML1枚あればそれでいいという考え方は同じで、わざわざCloudflare Workers使うという気もしなかった。なのでR2バケットをpublic accessibleにしてそこに格納してアクセスさせるという方式をとった。ちょっと面倒くさいのが、Github->R2でGithub Actions使ってputしなければならないところ。Workersなどと違ってGithubにプッシュさえすればそのままデプロイまでしてくれないので、経路を自分で用意する必要があった。ただここもClaude Codeに「作って」って言ったらすぐ作ってくれたので、別にそこまで苦労していない。一方でCloudflareのAPIトークン(R2にputするためのもの)を発行・管理しなければならなくなったのは若干、面倒くさいなとは思っている。

と、ここまで書いてて思ったが、そういえばGithub PageにすればR2へのputとかAPIトークンの管理とかそんなことしなくてよいのではないか??Cloudflareからプロキシ出来るのか知らないが、そのほうがシンプルだな。そうしようかな。Claude Codeに聞いてみよう。

ブログ移行しましたページのリニューアル

はてなブログからCloudflareにブログ移行した際、旧カスタムドメインに紐づけて「ブログのURLが変わった旨を案内するサイト」のこと。ここでその辺を話をしている。サイトはこれ→https://blog.rmblankslash.net/

もともとHugoで適当に作った簡易なサイトだったが、ブログの例にもれずこれもPagesだったので、Workersに移行するに至った。最初にHugoで作った時と同じだが、ただ単にブログの移行をアナウンスするだけの簡素なサイトで、Next.jsやらAstroやら大仰なものを適用するのも抵抗があり、なんかないかなーと考えた結果Honoxを採用することに決めた。今まで使ったことがないフレームワークで個人的好奇心から使ってみたかったということと、デザインも何も気にしないシンプルなサイトを作るという目的になんとなくマッチしたから、という理由による。ただよくよく考えるとこれも目的と要件を告げてフレームワーク選定をClaude Codeに任せた方が良かったかもしれないと、作った後の今になって気づいた。

はてなブログ時代のスラッグは/entry/[hogehoge]あるいは/entry/[YYYY]/[mm]/[dd]だったが、最初にHugoでサイトを作ったときは、スラッグのパスによらず「 https://blog.ricemountainer.net に移行した」ことだけを伝えるようなシンプルな動作しかしていなかった。どうせだからここも作り直すかと思い、旧のスラッグと現行のスラッグのマッピングを作って(ここだけは自分でやった、まあ適当にコマンド書いてファイル作っただけだがw)、リクエストパスに従って移行先のパスの表示や自動遷移先も切り分けるように変更した。SEO的に効果があるのか不明だがとりあえず想定通りに動いてはいるので満足してる。

ストレイテナーWeb通知くんのリニューアル

ストレイテナーWeb通知くんも、Next.js on Cloudflare Pagesで動いていた。ので、ブログと同じくWorkersへの移行が必要だった。

↑の流れから続きで開発に着手したので、あまり深く考えることなくHonoxを採用してしまった(気づいたらもうHonoxでプロジェクト始めてしまっていた)。ただまあ別にフレームワークにこだわりがあるわけではないし動くならなんでもいいかと思ってそのまま進めることにした。というわけでHonoxで動いている。また、もともとSupabaseをDBに使っていたが、この機会にどうせだからDBも変えようと思い、D1に移行した。開発のポイントをかいつまんで書き出すと以下のあたり。

  • 現行のOneSignalのSubscribeプロンプト表示にはReactのhook(useEffectとか)使ってたが、HonoxだとデフォルトではReact入ってないので使えない。が、同名でほぼ同じ動作をするhookはHonoxにも備わっているようで、現行のソースコード見せながら「同じ動きをする奴をHonoxで作って」っていうだけで実装された。すごいね。
  • OneSignalのsubscribeにあたり、OneSignalのApp Idをクライアント側に露出しなければならない。通常この手のものは環境変数に設定して管理するもので、Next.jsだとNEXT_PUBLIC_ prefixつければクライアント側から参照できたが、Honox(Vite)だとこういうわけにはいかず、どうやるの?って話をClaude Codeに聞いたらimport.meta.env使いましょうって話になりそのまま実装に至った。Viteはビルド時にこうやって指定された環境変数を静的に置き換えてアセット生成するらしい。ここは知らなかったので一つ学びになった。これをCloudflare Workersのビルド時環境変数に指定することでWorkersのビルド時に適用させる。ただ一方でOneSignalのApp Idはサーバー側でも使用するため、「ビルド時環境変数」「Workers自体の環境変数」でそれぞれ別に同じ値を管理しなければならないのは若干面倒くさい。究極的にいえばビルド時のところはハードコーディングでもいいんじゃないかという気はしており、そのうち直すかもしれない。
  • 最初はてっきり「プロジェクトルートディレクトリにSQLiteのDBファイル置いといてローカルの開発はそこで実施(DBファイルを.gitignoreに入れておく)」くらいに思ってたが、D1を使ったプロジェクトをローカルでwranglerで動かす場合、プロジェクトの.wranglerディレクトリの下に「ローカルD1」なるものが作成されてそれが使用されるようで、私がその事実を知らない一方でClaude Codeがそれ前提で実装するので、話がかみ合わず何度か質疑応答する羽目になった(無駄なトークン消費が。。)調べたら確かにそういうことが書かれている記事が見つかった。確かにそういえばR2とかも.wranglerのほうで代用されるしな…なるほど。という発見があった。
  • ↑の関連だが、D1相手の場合(ローカルでもCloudflare でも)、Drizzleでmigrationのファイル作成をするまではnpx drizzle-kit generateでよいのだが、migrationの適用はnpx drizzle-kit migrateではなくnpx wrangler d1 migrations applyになる。また、D1のmigrationがどのディレクトリの下にあるSQLファイルを読むか?についても、wrangler.jsoncに設定しておく必要がある。なんならmigrationのファイルの作成自体もnpx wrangler d1 migrations createで出来るみたいだが(どうやって何を作るのか知らん、試してないから)、このドキュメントでも「SQLファイル自体はDrizzleで作ってwrangler.jsoncmigrations_dir指定してもいい」って書いてあるので基本的にはdrizzle-kit generate->npx wrangler d1 migrations applyでいいんだろうと思う。
  • また↑の関連だが、Cloudflare Workersでは「ビルド」と「デプロイ」でそれぞれコマンド設定する箇所があるが、Honoxプロジェクトの場合、デフォルトでは「ビルド」はvite build、「デプロイ」はwrangler deployしかやらないので、どちらかに「migrationの適用」を埋め込む必要があった。そういえばどっちが適切なんだろうなと少し思ったが、Claude Code君は「ビルド」側のほうにampersand chainingで実装してもらった。"build:remote": "wrangler d1 migrations apply DB_NAME --remote && npm run build",だそうだ。Cloudflare Workersのビルドコマンドをこれに置き換えた。
  • さらに↑の関連だが、D1を使う場合、基本的にはDBアクセスするのにいちいちwranglerコマンドを経由する必要がある。これはローカルでも同じで、例えばテーブルの件数取得したいという場合はnpx wrangler d1 execute DB_NAME --local --command "SELECT count(1) FROM table_name"となる。また、これはSQLiteのドットコマンドをサポートしていない。例えばnpx wrangler d1 execute DB_NAME --local --command ".table"はエラーになる。このため、普通にsqliteでローカルにDBファイル作って開発するのに比べて、いちいち手間がかかるというか、融通が利かないというか、平たく言えば面倒くさい。ローカルで言えば、(私の場合は).wrangler/state/v3/d1/miniflare-D1DatabaseObject/の下に(長い乱数文字列).sqliteというファイルがあり、こいつ目掛けてsqlite3 .wrangler/state/v3/d1/miniflare-D1DatabaseObject/(うんたらかんたら).sqliteすればsqlite3コマンドでも中を確認はできたが、Cloudflare D1はsqlite3コマンドでアクセスする術を提供しておらず、wranglerでやり取りするしかない。関連として、現行のデータをD1に移行するにあたり、移行ツールの作成が必要になったので、これもClaude Codeに作ってもらったのだが、中身見てみたらINSERT文のSQLファイル作った後、node:child_processexecFileSync使ってwranglerコマンドで実行するというなんとも無理やりなことをやっており、まあ考えてみればそれしか手段がないので仕方がないが、結局そういう話になるのかというちょっと切ない気持ちになった。この辺、もう少し柔軟なやり取りができるようになればいいのになーという気はする。
  • 今更だが、この過程で知ったのだが、PWAのWebアプリインストールは、Safariは未対応らしい。ちなみにFirefoxも対応してない。よく調べたらMDNの公式ドキュメントに書いてあったが今まで知らなかった。両ブラウザがbeforeinstallpromptイベントをサポートしていないことによるとのことだ。当時「どうしてもインストールできない」という人がいたが(OneSignalのサブスクライブだったかな、、、忘れた)、これが原因かもしれないとなーと今にして思い返したりしている。

今後の計画

自分専用の「Tシャツ・筋トレ・英単語勉強Webアプリ」をリニューアルしたい。これは現状Cloudflare Workersだが、Remix v2+Supabaseで動いているので、中身をリニューアルしたい。まずRemix v2を変えたい(React Routerでもいいが、その辺含めて変更を検討したい)し、SupabaseもD1に切り替えたい(この辺の「個人の趣味プロダクト」のデータの場所は統一していた方がわかりやすいので)。

これはそもそもの話として、Webアプリのままリニューアルするのか?というところから検討したい気もしている。たとえばSlack Appで作り直してもいいのでは?というのも自分の中でアイディアにある。Slack Appはモーダルで画面呼び出せるので、やろうと思えばWebアプリのCRUD的な操作は全部実現できるはずなのだ。画面遷移は3秒以内に完了しなければならない(Slack からのAPIには3秒以内にレスポンスしなければならない)とか 、画面上でのInteractiveな操作(useStateとかのHook使うようなクライアント側の処理)ができないとかで、多少制約はつくが、着眼点は面白いと思っている。運用に難が出ないか、事前にある程度確認しておく必要があるが…

別にWebアプリのままでもいいんだが、今までずっとWebアプリのまま運用してきたので、正直ちょっと飽きてきたし、不満も出てきている。それに、実際の開発をClaudeにやらせる以上、もはやアプリケーションの実行形態にこだわる意味がなくなってきている気がしており、どうせならがっつり変えちゃっていいんじゃないのという気もする。不満の種でいうと、例えば、Webアプリだと、今更ながら、「Chromeのタブの一つ」として動作するのが、若干、自分のイメージと違っている(独立した「アプリ」の一つとして動く方が感覚に合っている)。じゃあPWAにするか?っていうとそこまでする気も起きないし(通知が必要とかそういう類のものではないので)。それと、Webアプリだと、「自分専用」の要件実現のために、どうしても認証の導入が必要になるが、これが単純に面倒くさい。実装が、というよりIDaaSに相当する部分をWebアプリとは別に1つ持って管理しなければならないのが地味に嫌だ。Slack Appであれば認証部分の実装は原則不要になるので、考えなければならないことが1つ減るのは個人的に結構大きいのだ。それに、現状「Tシャツの記録管理」「筋トレの記録管理」「英単語勉強」と、全然性質の違う処理機能がモノリポで固まっているが、本来的には分離しておいたほうが運用面やデータの分離などの観点ではよいはずなのだ。Webアプリだとその分Webアプリを作らなければならず非効率な一方で、それぞれでSlack App作って分離させたほうが分かりやすいし保守性も高まる。まあ考え方次第な部分はありそうだが…

これは一応現状問題なく稼働しているし、Pagesでもないので別に移行が急務でもないが、そう遠くないうちに何かしらの形で置き換えようとは思っている。

Claude Codeについて思うこと

基本的には 「頭と手際と要領と勘が滅茶苦茶よくて私に完全に忠実なプログラマーの相棒」 という感じ。要件の理解、コーディング能力、懸念点の洗い出しなどすべてが迅速かつ正確で、良い意味で全部人間離れしている。今更いうことでもないが、コーディングするという点でいえばもう正直完全にClaude Codeのほうがすべての面で上で、自分でコード書くよりかなり早く、しかも正確で、かつ品質のいいものができあがる。もともとコーディングは結構好きな方の人間だったが、これを覚えてしまうと最早自分でコード書くのはあほらしくなる。たまに趣味でちょっと書いてみてもいいかもな、くらい。Codexとか他の類似ソフトは触ってないが、おそらく似たような感じだろう。

ただ、「すげー」って思えるのは、「自分がやりたいこと」が、ある程度正確に言語化できている(AIへ指示出来ている)からなんだろう、というのもなんとなく感じる。「こういうの作って」とお願いして出来上がってきたものが、指示する前になんとなく思い描いていたボンヤリとした要件の姿を、割と的確に具現化できていたもので、つまり「自分ならこういう感じで作るだろうな」という作業のイメージが事前にあって、それを超高速かつ超正確にやってのけるから感動できるのだ。多分、その分野に対する知識や経験、解像度がある程度高い(少なくとも0ではない)から、要件=指示と成果物の間にそこまで大きなミスマッチが産まれづらく、結果「言うだけで欲しいものが出来上がった!」という感動体験になるんだろう。逆に言えば全く知らん分野で「作って」といって作ってもらっても、それが凄いのかどうか判断がつかず、感動しようにもできない、ような気がする。飲み会でおっさんの過去の武勇伝きいて「へ~そうなんですか…」みたいにしらけるのと少し近い気がする。ちょっと違うかも。まあいいか。

なので基本的には「開発力を底上げするためのツール・ソフトウェア」なんじゃないかという気がしている。もともとそういう能力を持っている人であるほど効果を感じるし、そうでない人にはそこまで響かない。似たような言説はXでもチラホラ見かけたので、同じような考えを持つ人もいるんだろう。感動の度合いというか方向性?性質?が違うけど、例えばそれまでずっとnotepadでコード書いてきた人がVS Code使うようになって「こいつはすげえぜ!」っていうのと本質的には同じ気がする。ただ、将来的にはVS Codeみたいな「人間が見る・書く」ためのIDEは消滅しそうとも感じており、そういう意味ではClaude Codeはプログラミングのパラダイムシフトみたいなものかもしれない。まぁまだガッツリ使い込んでもいないので、そのうちその辺の考え方も変わるかもしれないが、今の所はそういう感想である。

余談だが、XのTLだと「Opus 4.8は使い物にならねえ」という呟きをよく見かけるのだが、個人的には全然そうは感じない。確かにたまーに変なこと言い出すが、他のAI(GemniやChatGPT)でも起きてることだし、それに比べれば(比べるのも失礼なほど)非常に些細なもので、無視できるレベルである。それほど小難しいことやってないからそういう変な挙動に遭遇してないだけなのかもしれないが、今の所はOpus 4.8には十分満足している。直近、Fableが再開したとか、Sonnet 5.0がリリースされたとか見かけるけど、そういう意味ではあまり興味がない。あ、sonnetは試してみてもいいかもしれない。まあ、そんな感じです。