| @登山/ランニング

XERO SHOES HFS

熊本城マラソンに出場した。意図せずベアフットシューズで走ることになってしまった。なんとマラソン用のシューズ( ASICS MAGIC SPEED 2 )と間違えてトレランシューズ( ALTRA OLYMPUS 4 )を持ってきてしまっていたからだ。 OLYMPUS は重いし微妙にサイズが合っていないので、迷ったあげく、普段ばきや短い距離でのランニングに使っている XERO SHOES の HFS (ベアフットシューズでソールの厚みが 7.5mm )でフルマラソンを走ることにした。

ベアフットシューズでの生活はもう 3 年くいらいになるが、ランニングでベアフットシューズを使うのはせいぜい 20km くらいの距離までで、フルマラソンをベアフットシューズで走るのは未体験だった。

スタートしてから前半の 18km 地点くらいまでは 5:45/km ~ 5:50/km くらいのネガティブスプリットでサブフォーを狙えるくらいのペースで走れていたが、後半にペースを上げるのは厳しいだろうという感触があった。 18km 地点でこのままではゴールまで足がもたないと悟り、真面目に走るのを諦めてジョグのペースに切り替えた。その後転倒したりもしたが、歩きを挟んでなんとか完走することができた。

ベアフットシューズはふくらはぎのヒラメ筋への負荷がすさまじいので、フルマラソン完走となるとかなり鍛えていないと難しいと思う。普段はベアフッ党の方でも本番はちゃんと厚みのあるソールのシューズを履くことを激しくおすすめする。どうしてもベアフットシューズでマラソン走りたいなら、当然に 30km 走をベアフットシューズでこなしておくべきだと思う。ワラーチや裸足でマラソン完走する人はマジですごい

| @技術/プログラミング

Tantiny 、ろくにドキュメントを読んでいなかったので知らなかったのだけど、リアルタイムで検索インデックスの更新ができるようだった。これまで一時間に一度バッチ処理を動かして、更新された記事があればすべての記事を読み直してインデックスを更新するような富豪的なことをやっていた。アホだった。

| @技術/プログラミング

バッチ処理を動かしている Docker コンテナ含めてすべての環境を Ruby 3 で動かせるようになった。以下の点に難儀した。

  • MeCab が Google Drive からダウンロードできなくなっているので代替を探した
  • Tantiny が依存する rutie という Rust と Ruby をブリッジする gem が新しめの Rust に対応しておらず、 Rust のバージョンを 1.77 に固定する必要があった
  • ActiveRecord が v6 に上がったことにより、 DATABASE_URL を環境変数で渡すことで DB 接続設定を上書きできなくなってしまった
    • 設定ファイルの方を優先して読み込むようだった

ついでにキャッシュも効くように修正した。 sinatra-cache がおかしかったのは Haml の挙動が変わって - form_tag としていたところを = form_tag とする必要があるのと同様に、 - cache_fragment= cache_fragment にする必要があった。再びキャッシュが効くようになって高速になったが、一部 HTML タグが混ざって表示されることがある。 sinatra-cache.gem が依存する sinatra-outputbuffe.gem の方に問題がありそう。この gem は 16 年以上更新されていない。どこかでキャッシュ依存はやめないといけないかもしれない。

| @技術/プログラミング

先週末と今日ガチャガチャやって、ようやく Ruby 3 にアップグレードすることができた。 Ruby 2.7.3 → Ruby 3.1.6 。ただ Ruby 3.1 は今年の 5 月に EOL を迎えるみたいなのでこちらもさっさと新しいバージョンの Ruby に上げないといけない。

やったことは一つ前の記事に加えて以下。

kaminari-sinatra の SinatraHelpers が Ruby 3 & ActionView v6 対応していなかったのでちょこちょこと修正した。

次に padrino-helpers が Ruby 3 と Haml v6 に対応していないのを対応させた。具体的には form_tag の中身のタグが過剰に escape されてしまうので、あんまり良くないかもだが capture_html したやつを html_safe した。 form_tag の内側に来るものはユーザー投稿コンテンツではないはずなのでエスケープはサイト管理者側でできるはず。

ドキュメントでは

= form_tag

!= form_tag

にしろとは言われているが、 form_tag の中身で concat_contet してる片方( capture_html(&block) の結果)が html_safe? => false になるので、 View テンプレート側で何かやっても意味がない( Buffer が汚染されると View で html_safe しても汚染された部分の文字列はエスケープ済みになっている)。

kaminari-sinatra も padrino-helpers も本家にパッチを送ると良いのだろうが、職業プログラマーではなくなったのでなかなか腰が重い。 kaminari-sinatra はテストが通らないし、 padrino-helpers は git clone で submodule の clone に失敗するのでテストが実行すらできないかもしれない。

心の余裕ができたらやってみる。

ちなみに Ruby 3 化するにあたり sinatra-cache を完全に捨てたので負荷が上がるかも。オリジナルの gem は 15 年くらいコミットされてなくて fork して使い続けてきたけど Sinatra や Haml の変更に追従できる気がしないのでいったん捨ててみる。

| @技術/プログラミング

このブログは Ruby 2.7 でずっと動かしていた。コミットログをたどると 2020 年の 1 月から Ruby 2.7 のようだ。 Ruby 2.7 は 2023 に EOL を迎えている。

さすがにまずいと思ったので Ruby 3 にしようと一日頑張ってみたが、なかなかうまくいかない。Ruby 3 の キーワード引数の仕様変更はかなり対応がきつい。どこで ArgumentError が起こっているのかが極めて追いかけづらい。他のメソッドに委譲している場合などは特に。

ガチャガチャやってトップページと個別記事ページまでは Ruby 3 化できたので Ruby 3 でデプロイしてみたが、動かない画面があることに気がついたので Ruby 2.7 に戻した。 Kaminari がちゃんと動かない(具体的には kaminari-sinatra と actionview v6 系の互換性がない)のが原因でページネーションするページがちゃんと動かなそうだったので Ruby 3 化は諦めた。 kaminari-sinatra の ActionViewTemplateProxy#initialize を actionview v6 対応させないと無理っぽい。

kaminari のような有名な gem の派生 gem ならきちんとメンテされてるかなーと思っていたが、 kaminari-sinatra の最終コミットは 4 年前だった。

Ruby で View まで作る人たちはほとんどいなくなってるのだろう。

なお動かないところのデバッグは ChatGPT と対話しながらやった。めっちゃ便利。一人だと気がつかないような部分のコードを見てみろと ChatGPT が言ってくれて、そこにデバッグコードを入れてみるとビンゴだったりする。便利な世の中になった。

忘れないようにやったこと・気づいたことをメモっておく。

  • sinatra は v4 にあげないといけないのでパスの正規表現から ^$ は消さないといけない
  • better_errors の REPL がちゃんと動かないので Backtrace を見たいときはログを開くか better_errors を使うのをやめる
  • fork していた sinatra-cache は sinatra 4 では動かないので外した(キャッシュできない部分をどうするかは要検討)
  • capistrano-puma も Ruby 3 対応させないといけない(期待される systemd のフォーマットが変わっているので単にデプロイするだけではだめで一部手作業が必要)
  • tilt は v2.1.0 に固定( Tilt::ErubisTemplate クラスが消えるため、 padrino-helper がエラーを出す)
  • concurrent-ruby は 1.3.5 未満に固定
  • compass は 1.0.3 に固定
  • SESSION_SECRET は 64 文字以上にする
  • haml の過剰な escape を抑制
  • kaminari-sinatra の ActionViewTemplateProxy#initialize を actionview v6.1.7.8ActionView::Base#initialize に対応させる

| @技術/プログラミング

人気記事集約用のシェルスクリプトは自己流で書いてたのであまり自信がなかったので、ものは試しにと ChatGPT にリファクタリングしてもらった。今日の集計と昨日の集計と全期間の集計で似たようなコードがあるのにコードを共通化できていなかったので共通化を提案されたが、そのまま適用するとちゃんと動かない。重要な細かい仕様をなかったことにしたりもする。 Copilot も試してみたが似たような感じだった。生成 AI はチャットでベストプラクティスを聞いたり、細かい作法を尋ねたりするのには向いているかもだが、ソフトウェア開発者を丸々置き換えることはできないと思う。少なくとも現状は。実際に動かしてみて期待通りに動くかのチェックは絶対に必要だし、人間が細かいところで楽をすることはできるけど、完全に ChatGPT とか Copilot だけでシステムを構築するのは難しいだろう。 AI は人間が知ってることしかできない。人間が知らないことは人間にしかできない。

| @ブログ

人気記事を確認できるようにしたという記事を以前書いている。もう 7 年も前のことのようだ。

調べればこういうログ集約・集計系のサービスはあるようだったが、個人ブログなのでなるべくお金はかけたくない。

しばらくの間は集計後のログを捨てていたが、 2 年半前からログローテートするタイミングで日付ごとのファイルを書き出し保存するようにしていた。日付ごとのログファイルは Amazon の S3 にアップロードしてさくらの VPS サーバーからは待避させている。現状、 2022 年の 6 月 13 日のログから S3 上にデータが残っているので、その日以後の日ごとの人気記事を確認できるようにした。こんな感じ。

日付の選択は最初 React のライブラリを使って作ろうかと思ったが、そういや最近のブラウザーは <input type="date" /> とすると結構ちゃんとしたカレンダー UI と日付選択の機能を提供してくれるので楽をすることにした。

max と min を指定すると選べない日付は非活性にされるし、無理に選択すると form を submit したときにバリデーションしてくれる。

選べない日付は非活性に
max と min を指定すると選べない日付は非活性にされる
バリデーション
選べない日付で無理に submit されたときにはバリデーションもしてくれる

ブログの閲覧者からしたらいつどの記事が読まれていたかなんて興味ないだろうけど、著者である自分には興味深い情報になる。セルフホストのブログだからできる機能だ。