| @雑談

長田部海床路

生活

ランニングレース

熊本城マラソン

直前の食あたりと靴の取り間違いでコンディション最悪だった。加えて転倒もあり、マラニック状態で 5 時間オーバーでゴール。リタイアしなかったのは偉い。来年は雪辱を果たしたい。

ASO VOLCANO TRAIL

初のウルトラトレイル( 112km )。3 月、 4 月と自分にしてはしっかりトレーニングしてから臨んだ。25 時間以上かかって記録はいまひとつたが、完走できたことがうれしかった。

トレーニングで三瀬峠脊振山ピストン練を 3 回やって、糸島四座縦走が楽に感じられるくらい強くなった( 4 時間半でゴールできた)。ターゲットレースがあると、それに合わせて頑張るので走力がぐっと上がる。 5'10"/km くらいのペースで走るのがそんなにしんどくなくなった。

福岡マラソン

直前期にあまり走れていなかったので不安だったが、マラソン自己ベストを更新できた。もう少し練習して体重も落とせていたらもっと速く走れたかもしれない。

総括

レースはマラソン 2 本とトレラン 1 本だった。カントリーレースも出たかったがうっかりしていて締め切られていてエントリーできなかった。

ボルケーノに出るためにだいぶ時間とお金を使ったので他のレースには出なくても良いかなぁと思っていたが、やはりたまにはレースに出ないと張り合いがない。来年はもうちょいレースに出たい。

登山・トレラン

脊振山系全山縦走トレラン

初めての夜通しのトレラン。 ASO VOLCANO TRAIL の予行演習になった。同僚にサポートしてもらってめっちゃうれしかった。

祖母・傾ファストパッキング

いわゆる祖母傾完全縦走。九合目小屋に泊まった。 20L の Rush 20 では宿泊装備が入りきらなかった、 Rush 30 も買うか…

祖母傾完全縦走

高尾山ハイキング

出張ついでに訪問、日本で一番登山者が多い山を訪れることができた。トレラン装備の人が多かった。ハイキングの人もトレラン装備で登ってた。結構年齢が上の人でもトレラン風の装備だった。来年あたり九州でもそういうスタイルが一般的になるかも。

下山後に食べ飲みした蕎麦とクラフトビールがうまかった。都会の山ならでは。

高尾山薬王院

TAKAO BEER

国見岳山頂祠再建ボランティア

熊本県最高峰の国見岳の山頂祠が倒壊したままなのは、熊本県民にとっては残念だった。再建をすると聞いて、少しでも役に立ちたいと歩荷のボランティアに行った。あまり役には立てなかったが、祠の再建に立ち会えたことは良かった。

国見岳山頂祠

八ヶ岳(硫黄岳)登山

出張ついでに訪問、九州の山ばかり登っていてはダメだと若い同僚にけしかけられて登りに行った。八ヶ岳、ガスガスで何も見えなかったが、久しぶりの森林限界突破と、有人の営業小屋のもてなしで心がほっとした。防風のなか、雨風を凌いでゆっくりできる場所を用意してもらえてるだけでありがたい。

八ヶ岳の森

インターネットトレラン

nagayama さん、 nmy さんとのインターネットトレランも思い出深い。インターネットとトレランという二つの趣味の交錯だし、なんなら仕事と趣味の交錯でもあり、とてと楽しい時間だった。

坊がつる野営( Happy Hikers Hokkein Gathering )

同僚と行ったが野営したのは一人(途中から別行動)。一昨年の方が寒かったが、 Hammock Bivvy Tyvek を使わなかったので寒くて眠れなかった。野営は定期的にやってないと勘が鈍って失敗する。

夜の三俣山

韓国岳

寒い日に登り、雪景色の山を堪能した。えびの高原は雰囲気抜群で、またキリエビに出たいなと思った。

高千穂峰

南阿蘇カルデラトレイルボランティア

二度ほど出場したことがある南阿蘇カルデラトレイルにボランティアとして参加した。ボランティアしんどい。 4 時半集合だったので 1 時半に起きて 2 時過ぎに福岡の家を出て向かった。自分が出た年は雪が降っていてソフトフラスクが凍り付いたが、今年はあたたかくて走りやすそうだった。自分もまたレースに出たくなった。

大矢岳へのトレイル

総括

脊振山系全山縦走と祖母傾完全縦走が思い出に残っている。どうしても限界までチャレンジするような登山の方が印象に残りやすい。年に 1 、 2 回、こういう登山をするといいのかも。

一方で、高尾や八ヶ岳、韓国岳へののんびりハイクも楽しかった。きつい登山とゆるハイクをバランス良くやりたい。ハードなトレランばかりだと疲れる。

今年は九州脊梁に泊まり登山に行けなかったのが残念。年に一回は脊梁で野営らしい野営をしたい。

買い物

Novablast 5

レースシューズに Magic Speed 2 を持っていたが、デイリートレーナーでは初のアシックス。めっちゃ走りやすくてランニングが楽しくなった。ベアフットシューズで足は鍛えられるがどうしても距離が踏めない。アルトラは良いが値段が高すぎる。アシックスがコスパよい。

Novablast 5

iPhone 17 Pro

iPhone 14 Pro からの買い換え。目玉が飛び出るほど高かったが iPhone 14 Pro の下取り価格が高くて助かった。カメラのデザインはどうかと思うが画質がメチャ良くなっててうれしい。 USB-C ケーブルになったのも地味に便利。

Garmin Epix Pro

検証機で Garmin Fenix 7 を使って Garmin に宗旨替えすることにした。 Garmin はヘルスケアや運動関連で踏み込んだアドバイスをしてくれる。 Apple Pay や Mac や iPhone のロック解除、 Siri は便利だったがランニングが趣味なら Garmin が一番いいと思う。

OTTO Cast Mini

Car Play がワイヤレス化されて最高便利。Amazonアソシエイトリンクを貼ったら結構買ってもらえててビックリ。みんな同じような悩みを抱えているっぽい。

HOUDINI Moon Walk Vest

これはガジェット系ではなく服。ほぼ毎日着ている。秋はTシャツの上に羽織り、冬もフリースの上に羽織ったりしてる。暑がりなのでダウンジャケットなどは暑すぎる。こういうのがちょうど良い。

HOUDINI Moon Walk Vest

水出し緑茶ティーバッグ

社長からもらって気に入って自分で買って飲むようになった。水出しでよく出ておいしい。一パックあたり 50 円くらい。毎日ペットボトルのお茶買うのは環境に良くないしお金ももったいない。

総括

年をとったせいか、同じものをスペアで買ったり、買い置きを増やすことが多くなった。その結果見つからなくなったり、食べ物なら腐らせてしまったりする。もっと賢くお金使えるようになりたい。

音楽・本・映画

国宝

Audible で聞いたがめっちゃよかった。映画見に行きたいが暇がなくて行けてない。

Yogee New Waves

ライブに行った。 Good Bye をすり切れるくらい聞いた。

Oasis

ライブのチケットは何度も申し込んだけど当たらなかった。 Live Forever と Supersonic と Acquiesce を何度も聞いた。 Live Forever は 95 年の Glastonbury でのライブバージョンがよい。

Wilderado

スターバックスの店内 BGM を聞いて知ったインディフォークロックバンド。 Surefire という曲がめっちゃいい。いつかアメリカでライブに行ってみたい。

総括

映画は1本も見てない。ドラマすら見てない。 YouTube ばかり見てしまった。来年は1本くらい映画見たい。

ブログ

写真でふりかえるシリーズを 12 ヶ月分書いた

書くネタがないが写真の整理がてら毎月ふりかえるのはよかった。今後も続けたい。

Ruby 3 で動くようにした

Ruby 2.7 で動かしていたのでとりあえず最低限の対応をして Ruby 3.1 にした。 Ruby 3.1 も EOL を迎えているのでなんとかしたい。

フォトギャラリー

私家版 Flickr のようなやつを作った。撮った写真をどこかに上げたいたいという欲求があったが、 Instagram はなんかちょっと違う。 Flickr のような場所が良いが、いまの Flickr は値段が高すぎるのでフォトギャラリー機能を実装してしまった。ちょうど良いアウトプットの場が作れてうれしい。

AI を使って機能の追加

要約生成、自動タグ付け機能を作った。 Dify を使ってポータルシット問いかけ君( AI チャットボット)も使った。開発のサポートだけじゃなく、機能の一部として AI を使う時代になってきてる。

総括

職業エンジニアじゃなくなってブログの維持管理がさすがに厳しくなってきた。いつまでできるかわからないがボケ防止と思って頑張る。

仕事

プロダクトマネジメント

プロダクトマネージャーの役割に葛藤する一年だった。結局、経営やビジネスサイドに言われたことを実行するだけで、プロダクトマネージャーはプロジェクトマネジメントしかやれてなくてつまらない、という不満を部下から聞かされることが多かった。やりがい云々の前に、確かにビジネスとプロダクトが分断されていてなかなか大きな成果を出せなかった。この構造をなんとかしなければならないが、しかしこのような分断が起きるのは自分を含むプロダクトマネージャーが身銭を切りきれていないからではないかと思い至った。コンフォートゾーンを出てリスクを取りにいかないと信頼されないし、大きな権限は渡してもらえない。もっとプロダクトマネージャーが事業を引っ張っていくような体制をつくっていきたい。

とはいえ、必ずしもプロダクトマネージャー自身が革新的なアイディアを思いつく必要はなくて、プロダクトディスカバリーのプロセスをめっちゃ丁寧にやることが大事だと思う。なぜこのプロダクトを自分たちが作る必要があるのか、このプロダクトで世の中にどんな変化を引き起こすのかをつまびらかにする。この部分だけで記事が書けるので別に書こうと思う。

開発部長業

エンジニアに対してもプロダクトマネージャーと同じで、もっとリスクをとってほしいと思うことがしばしばあった。9月にバズってた以下の記事が良かった。

心理的安全性についても結構議論した。職場ではこれまでも心理的安全性を高めることが大事だと言われてきたが、なぜ心理的安全性を高める必要があるのかについての議論が不足していたように思う。働きやすさとかそういうのは二の次で、個々人にフィードバックが適切に行われ、フィードバックによって学びを得て生産性を高めていくことが開発組織における心理的安全性を高めなければならない根拠になると思う。心理的安全性がなければフィードバックをする方は怖くてフィードバックできないし、フィードバックを受ける方も個人攻撃ではないという確信がなければそのフィードバックを素直に受け止めることができない。

これらが機能するために、ダニエル・キムの成功循環モデルはめっちゃ重要だと思う。関係性の質、思考の質、行動の質、結果の質にはループ構造になっているというもの。めっちゃスタープレイヤーが揃っているチームじゃなくても、関係性の質が良ければ結果を出すということは身をもって知った。自分が何となくチームビルディングできていたのでなんとかなるだろうと思っていたけど、これは仕組み化しないとダメだとわかった。チームビルディングをチーム任せにせず、少々御節介でも組織として積極的に関与していくことが大事だと思う。

総括

自分は起業できるほど人間力高くないが、それでも世の中に影響を及ぼすことをやって人生終えられる仕事がいまのような仕事(中間管理職兼プロダクトマネージャー)なのかなと思ってる。来年はどうすればもっと自分の強みが生きるのか考えて行動していきたい。なんのかのと書いているが、とにかく結果を残したい。

| @写真

2025 年 9 月の出来事

  • iPhone 17 Pro を買った
  • 冷や汁をよく作って食べた
  • 月蝕を見た
  • コテンラジオで伊藤野枝のエピソードを聞いた(伊藤野枝は今宿出身)
  • Audible で『国宝』を聞き始めた
  • Docker イメージの手入れカテゴリー・タグ検索の実装
  • 8 月に引き続いてあまり走れず、月間走行距離は 123km

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

いろいろあって手元で docker build が通らなくなってしまったので ChatGPT に相談したら Alpine Linux はビルドが遅くなるので Debian Slim に変えた方がよいと言われてガチャガチャやった。BuildKit を使ってキャッシュせよとも言われたけど、逆にビルドにめっちゃ時間かかるようになったので BuildKit は使わずに普通にビルドしてる。 Apple Silicon の Mac で Linux で動かすように linux/arm64 でビルドしてたけどこれが遅い原因だと散々言われた。クロスプラットフォームで BuildKit のキャッシュを使うとめっちゃ遅くなるらしいので逆効果だった(半日以上ビルドしても終わらないてことがざらだった)。

Docker 、これまで Alpine ベースのイメージを使ってたせいで自前でいろいろコンパイルしたりインストールしたりしてたけど、ビルド済みのものをダウンロードしてくる運用はやっぱり楽。 Alpine 使っても最終的なイメージサイズは膨大になってたし、もっと早めに Debian ベースに変えればよかった。

ちなみにビルドが通らなくなったのは tantiny が依存する rayon という Rust のライブラリが Rust 1.8 以降でしか動かなくなったため。 tantiny は Rust 1.77 までしかサポートしてないので Rust のバージョンを 1.77 で固定していたが、このせいでビルドにこけるようになった。なので tantiny をフォークして rayon と rayon-core のバージョンを古いバージョンに固定した。

tantiny および tantivy は楽に運用できる非常に優れた全文検索ライブラリだと思うけど、 tantiny のメンテナーの人が仕事で使わなくなったそうでメンテナンスされてないのが悲しい。自分でできるならやりたいが、職業プログラマーではないし Rust わからんちんなのでどうしたもんか…。

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

バッチ処理を動かしている 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 年以上更新されていない。どこかでキャッシュ依存はやめないといけないかもしれない。

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

Homebrew で入れた SQLite で load_extension() が動かなくなっていた。

どうも以前は --enable-loadable-extensions でビルドできていたらしいが、 Homebrew 全体でオプション指定をできなくする変更が 4 年前にあったみたいだ。

オプション指定できるのは UX として良くない(ビルド済みのバイナリをダウンロードできない)し、オプション指定を Homebrew のチームでテストしていないからだそう。

TF-IDF で関連記事を表示する機能は SQLite の拡張に依存していたので、最近 Homebrew で入れた SQLite だと機能が動かなくなってしまった(エラーが発生する)。

対策としては自分で SQLite をビルドするしかない。 Mac でそれやるのは面倒なのでこういうのは全部 Docker でやることにした。

Homebrew のウリはビルド済みのバイナリをサクッとダウンロードできてローカルでビルド不要なところではあると思うが、ちょっと凝ったことをしようとするとソースコードをダウンロードしてきて手元でビルドしないといけなくなってしまった。依存パッケージをまとめてインストールできてたことも便利だったんだけど、カスタムインストールをしたいときは昔みたいに依存関係を自分で調べて都度都度インストールしていかないといけなくなった。開発チームの考えもわからなくはないがちょっと残念だ。

ちなみに Homebrew のリポジトリ( homebrew-core )の過去のコミットログを調べるのがめっちゃ大変だった。 tig Formula/sqlite.rb しても 3 分くらい反応がなかった。 git log -Sextension Formula/sqlite.rb してそれっぽいコミットのハッシュ値を見つけて GitHub で検索して何とか上記の Pull Request と Issue に辿り着いた。超巨大なプロジェクトのソースコード管理は Git でやると大変そうだ。

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

Rust 製の全文検索システム Tantivy を Ruby から使える Tantiny を導入したことを書いた。

結構手軽に使えるのだがやはり日本語のトークナイズ(形態素解析)ができないのでいまいちなところがあった。 Tantivy には lindera-tantivy というものがあって、 Lindera は kuromoji のポートなので、これを使うと日本語や中国語、韓国語の形態素解析ができる。 Tantiny に導入できないか試してみたが、自分の Rust 力では到底無理だった。

ちなみに関連記事の表示でも日本語の形態素解析は行っている。

MeCab に neologd/mecab-ipadic-neologd を組み合わせてナウな日本語に対応させつつ形態素解析している。

この仕組みを作ってトークナイズは Ruby で自前で行い、 Tantiny および Tantivy にはトークナイズ済みの配列を食わせるだけにした( Tantiny はトークナイズ済みのテキストを受け付けることもできる)。トークナイズを自前で行うことで辞書ファイルで拾いきれないような固有名詞もカバーできる。例えば 山と道 なんかは MeCab と mecab-ipadic-neologd にトークナイズさせると に分割されてしまう。自前のトークナイザーで単語として認識させていている。おかげで「山と道」をちゃんと検索できるようになっている

なお、自前のトークナイザーはこんなコードになっている。

class Tokenizer
  attr_reader :text

  class << self
    def run(text)
      self.new(text).tokenize
    end
  end

  def initialize(text)
    @text = text
  end

  def cleansed_text
    @cleansed_ ||= text.
      gsub(/<.+?>/, '').
      gsub(/!?\[(.+)?\].+?\)/, '\1').
      gsub(%r{(?:```|<code>)(.+?)(?:```|</code>)}m, '\1')
  end

  def words_to_ignore
    @words_to_ignore ||= %w[
      これ こと とき よう そう やつ とこ ところ 用 もの はず みたい たち いま 後 確か 中 気 方
      頃 上 先 点 前 一 内 lt gt ここ なか どこ まま わけ ため 的 それ あと
    ]
  end

  def preserved_words
    @preserved_words ||= %w[
      山と道 ハイキング 縦走 散歩 プログラミング はてブ 鐘撞山 散財 はてなブックマーク はてな
    ]
  end

  def nm
    require 'natto'
    @nm ||= Natto::MeCab.new
  end

  def words
    @words ||= []
  end

  def tokenize
    preserved_words.each do |word|
      words << word if cleansed_text.match?(word)
    end

    nm.parse(cleansed_text) do |n|
      next unless n.feature.match?(/名詞/)
      next if n.feature.match?(/(サ変接続|数)/)
      next if n.surface.match?(/\A([a-z][0-9]|\p{hiragana}|\p{katakana})\Z/i)
      next if words_to_ignore.include?(n.surface)
      words << n.surface
    end

    words
  end
end

preserved_words が手製の辞書だ。 はてなはてブ も辞書登録しておかないと MeCab だとバラバラに分割されてしまって検索できなかった。

難点としては記事更新後に自動でインデックスの更新が行われず、 cron によるバッチ処理でインデックス更新を行っている[1]。なので検索インデックスにデータが反映されるまでにタイムラグがある。 Tantiny でやれれば記事作成・更新時のコールバックとして処理できるのでリアルタイムに変更を検索インデックスに反映させることができるが、個人の日記なのでタイムラグありでも大きな問題にはならない。

本当は Tantiny で lindera-tantivy を使えるようにして Pull Request がカッチョイイのだが、とりあえずは自分は目的が達成できたので満足してしまった。 5 年くらい前から Rust 勉強したいと思っているが、いつまでも経っても Rust を書けるようにはならない。

[1]: mecab-ipadic-neologd を VPS 上でインストールできず(めっちゃメモリを使う)、手元の Mac で Docker コンテナ化して Docker Hub 経由でコンテナイメージを Pull して VPS 上で Docker 経由で動かしている(その辺について書いてる記事: ブログのコンテナ化を試みたけどやめた

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

Hot Chocolate @ Tana Cafe & Coffee Roaster

この記事は CircleCI Advent Calendar 2018 19 日目の記事ですが間に合わず一日遅れて書いております。すんません 🙇🏻

CircleCI を使った Rails アプリのデプロイフローみたいな話を書こうかなと思ったのですが、すでに他の方が書いてる内容とかぶりそうだし、自分自身ブログに過去何回も書いた話なんで今回はエモ方面の話を書くことにします。技術的な情報はないのでそっち方面を期待している方はすんません。


いまの職場で働き始めて 1 年半なんですが、当初は CI はなく、テストコードもありませんでした。いまはそこで当たり前のように CI が回り、テストのカバレッジもまぁまぁ高く、デプロイは CircleCI 経由でじゃんじゃん行われるような状況となっております。新しく会社に入った人も GitHub の Organization に入ってもらえたらその瞬間から deploy 実行できます。具体的な話は昔書いてますのでよかったらご覧下さい。

8 年くらい前の自分はどうやったら CI だとか自動デプロイだとかできるようになるのか皆目見当が付きませんでした。いま 8 年前の自分と同じような状況にいる人(回りにテストを書く習慣を持つ人がいない人、 CI 動かすためにどうすればよいかわからない人)に何か言いたいと思い筆をとりました。

まずは何はなくとも頑張って一つテストケースを書いてみましょう。最初からカバレッジ 100% とか目指さなくてもよいです。どれか一つ、テストが書きやすそうなコードを見つけてテストを書き、ローカルで実行してテストがパスするのを確認しましょう。テストファーストとかも最初から目指さなくてよいです。

手元でテストが通ることを確認したら、 CI 環境でもテストを実行できるようにしましょう。

昔は Jenkins しか選択肢がなく、 Jenkins が動く環境をセットアップする(サーバーを調達する、 VPS を借りてもらう、などなど)に社内調整が必要でしたが、 CircleCI ならプライベートリポジトリでも 1 プロセスなら無料で使えますので社内調整が非常に楽です(外部にコード出してはダメな職場だと厳しいですね…)。

最初にプロジェクトを追加して言語を選ぶと設定ファイルが自動生成されるので、それをコピペして .circleci/config.yml として保存し、リポジトリにコミットするだけでとりあえずビルドが実行されるようになります。

昔は難しかった CI 環境構築のうち、お金の問題、設定の難しさの問題を CircleCI は解決してくれます。あとはあなたが頑張るだけです。

CircleCI ならビルド終了ごとに結果を Slack などチャットシステムに通知させることができます。まずはテストケースが一つでもよいのでリポジトリへの push をトリガーにビルドが実行されたら結果を Slack に通知してみましょう。

CircleCI Slack Notification

CircleCI Slack Notification

リポジトリに GitHub を使っているなら Pull Request にビルド結果が表示されるようになるはずです。

CircleCI GitHub Build status

これらで「なんかようわからんけどやっとる感」を出していきましょう。

そして過去のコードのことは一旦無視して、あなたが新しく追加する部分に関してはテストコードをセットで書くようにしていきましょう。あなたがコードレビューを依頼するときには必ずテストがグリーンな状態で依頼するようにするのです。

そうこうしているうちに他の人が出した Pull Request でテストが失敗するケースが発生します。 Slack の #circleci チャンネルに赤色の Failure 通知が届き社内が騒然とするかもしれません。しかしこれはチャンスです。

「よかった、これでバグが未然に防げましたね」

あなたのこの一言でテストや CI がもたらす開発効率の向上がチームの皆さんに伝わるはずです。こうなったらもう一押しです。あなたがテストと CI の伝道師になりましょう。テストを書くことが当たり前になってきたら、 CircleCI からの deploy や定型処理を CircleCI でやらせるような使い方にチャレンジしていきましょう。どんどん周囲を巻き込んで、 CI 文化を定着させていって下さい。

何はともあれ、最初は一つのテストコードを書くことから始まります。変更に強いコードを書いてじゃんじゃん deploy し、じゃんじゃん Money making していきましょう🤑