2025年の思い出
しゃかいじんじゅうにねんめ
去年は https://eagletmt.hateblo.jp/entry/2024/12/31/192001
仕事
去年 One Experience がリリースされたものの、その2つの Web アプリが1つになっただけで、それ以外のすべては2つに分かれたままだった。今年はそれらをできるだけ統一していった一年だった。日本と UK でオンコールローテーションをある程度共通化したり、プラットフォームを EKS から ECS に移行したり、どこまで本番環境のデータを開発に利用してよいかの基準を統一したり。とくに最後の話は、これまで全く異なる文化・常識で開発してきたので折り合いをつけるのに無限に消耗した。ECS 移行によって初心者みたいな恥ずかしい障害がなくなったりしたので価値が無かったわけではないとは思うが、どちらかというとマイナスをゼロにする活動だったので、来年はプラスを生み出す活動もしたいですね。
表向き (?) の One Experience は去年の9月頃に終わっていたが、実際には旧システムはその後も動き続けており、これの片付けを自分が担当していてつい最近ようやく最後の DB をシャットダウンすることができた。片付け作業は何も難しいことはなく、使われていないことが確認できたものから消していくだけだが、微妙に使われ続けているところを見つけてその利用者の開発チームに伝えて移行を催促する、というのを延々とやっていた。年初の段階では4月頃に user-facing なものは全部シャットダウンできるだろうとしていたものが7月にずれ込み、その後も進みが悪く、裏側も含めてすべての撤収が終わったのが先週というかんじだった。僕の立場からはほとんどが待ち時間だったわけですが。
厳密には仕事ではないが、1月に久しぶりに対外登壇をした。
https://speakerdeck.com/eagletmt/tokyo-rubykaigi-12-ruby-rust-and-me
Ruby と Rust を日常的に書いてる人の視点からの話を聞きたいということで主催者 (元同僚) から光栄にも声をかけていただき、登壇する機会を得た。登壇自体は何度かしたことがあるが、ここまで抽象的なというかふわふわとした自分語りをするのは初めてで、参加者にどう感じられるのか不安なところがあったが、懇親会で直接反応をもらえて嬉しかった。
趣味
ゲーム
引き続きメトロイドヴァニア系がメインでたまにノベルゲーというかんじだった。
- ENDER MAGNOLIA: Bloom in the Mist https://store.steampowered.com/app/2725260/ENDER_MAGNOLIA_Bloom_in_the_Mist/
- 待ち望んでいた ENDER LILIES の続編のメトロイドヴァニア。接触ダメージがなくなったのが神。システムも親切になっていて前作と比べると若干難易度は下がったかな? という気もするが、十分遊びごたえのある傑作だった。ENDER LILIES のオケコン行けるといいですね https://enderlilies5thconcert.com/
- Awaken - Astral Blade https://store.steampowered.com/app/1716310/Awaken__Astral_Blade/
- 王道的なメトロイドヴァニア。そこまで難易度は高くなく、気持ちよくプレイできるタイプ。日本語訳はやや怪しいが、この手のゲームのストーリーはまぁだいたいよく分からないので、自分は全然気にならなかった
- Pipistrello and the Cursed Yoyo https://store.steampowered.com/app/2870350/Pipistrello_and_the_Cursed_Yoyo/
- 魔法少女ノ魔女裁判 https://store.steampowered.com/app/3101040/_/
- Hollow Knight: Silksong https://store.steampowered.com/app/1030300/Hollow_Knight_Silksong/
音ゲーとソシャゲはあまり変わらず。CHUNITHM はわずかに上手くなったような感触はあるが、レートに変化は無し。オンゲキはレーティングシステムが一新されて虹レから脱落した。プラチナスコアを稼ぐモチベーションが湧かず、オンゲキをプレイする頻度も落ちていた時期があったが、パレプロコラボ第二弾でモチベーションがやや戻ってきてようやく P 枠を埋めきった。ただそれでも虹レに届いてないので、虹レに届くくらいまでのプラチナスコア稼ぎはがんばろうかなぁ。ソシャゲはスタレとブルアカを引き続き遊んでいるが、ブルアカの頻度が下がってスタレの頻度が上がった。自分の好みとしてはオンパロス編よりピノコニー編のほうが上だったのだが、オンパロス編も十分楽しめたし、次のメインストーリーも楽しみですね。最近実装されたマネーウォーズも面白い。
音楽
今年も色々な音楽ライブに行った。主なものを挙げるとこんなかんじ。
- HIMEHINA 7周年LIVE https://himehina.jp/pages/live2025_7th_anniversary_live
- 今まで周年ライブは YouTube でやってたが、2 Days のリアルライブになった。Day 1 は合唱祭で HIMEHINA らしくてよかったですね
- CENTRAL MUSIC & ENTERTAINMENT FESTIVAL 2025「VIVAL」 https://central-fest.com/s/central/page/eventvival
- 今年の謎イベント (?) 枠。メインの目的は HIMEHINA だが、ClariS のライブってこんな雰囲気なんだと意外に感じたり、Reol のパフォーマンスがすごくて流石と感じたりした
- パレプロ感謝祭2025 https://paletteproject.jp/thanksfes2025/
- 去年のオンゲキコラボからの新参者だけど、パレプロがかなり好きになった。人生で初めて法被グッズを買いました。この時の新曲のハレバレパレットはライブ映えして良いですね https://www.youtube.com/watch?v=fOH131JSlIY
- ALL AIKATSU! ROCK FES. https://www.aikatsu.net/portal/topics/topics.php?id=22410
- 突然何? その1。生バンドライブで Sweat Sp!ce を聞ける日がくるとは https://www.youtube.com/watch?v=uln8QKHdbEQ
- Re:ステージ!×オンゲキ PRISM☆FEVER!! vol.1 -オン×ステージ!- https://rst-project.com/event/20250921/
- リステとオンゲキはズッ友! オンゲキのライブが悪いわけではないがリステのライブが最高なので、リステ側メインでオンゲキ含むライブをやってくれてありがとうの気持ち。vol.2 も待ってます。MY GLORY WANTED!!! は公式大会決勝曲であって、ライブでやるような曲ではない https://www.youtube.com/live/tyqAF5ed-cA?t=5h49m25s
- HIMEHINA LIVE 2025『Lifetime is Bubblin』 https://himehina.jp/pages/lifetime_is_bubblin
- HIMEHINA のいつものライブのほう。パシフィコ横浜のキャパで FC 先行が全部落ちて厳しい。それだけ人気になったというのは嬉しいことではあるが、チケットを取れなくなることが出てくると萎えちゃう。Day 2 の開演が1時間以上遅れて退場が23時を過ぎるという結構な大事が発生してしまい、ライブの内容への不満は一切無いが終演をもっと早くしてくれというのが一緒に参加している友人らとの共通認識ではあったが、それがついに爆発してしまったという印象。Lifetime is Bubblin のツアーの時点で17時30分開演を予定しているということで、3時間近い公演ならトラブル関係無くこれくらいの時間には今後も開演してほしいですねぇ https://himehina.jp/post/post-430
- アイカツ!×スパリゾートハワイアンズ ミニライブ https://www.hawaiians.co.jp/sys/show-event/2
- Palette Project 5th one man live 『Sing for the Moment』 https://paletteproject.jp/singforthemoment/
- チケット完売したのめでたすぎ。次はもう少し広い会場でジャンプしても問題無い BLAZE とか ReNY とかどうですかね、オルスタでもいけるタイプだと思うんですが。シャッフルユニットはね~~ライブってかんじでいいですね https://www.youtube.com/watch?v=p6YdxYBK7N4
あとはアイカツ!×プリパラ THE MOVIE -出会いのキセキ!-の映画が公開されましたね。10年経つと当時のライバル同士でもコラボ作品を作れるんですねぇ。さらにコラボライブが来年開催されるということで、とても楽しみ。
バイク
自転車の延長線上のような感覚で元々バイクに興味はあったんだけど、免許も必要だし購入するにはそれなりの費用が必要だしで実際に行動に移すことはなかった。しかし去年クロスバイクを買って走っているうちにバイクへの興味が再燃し、また去年ある友人がバイクを買っていたことにも刺激され、今年の7月頃から教習所に通って10月頭に普通自動二輪の免許を取ってそのまま YZF-R3 を購入した。普通免許を大学一年のときに取ってはいたもののほとんど乗らずに塩漬け状態だったので、公道を走るのも実質初めてみたいなかんじだったが、わりと日常的に乗るようになってきている。現時点での総走行距離は3000kmくらい。ハワイアンズに行くのにバイクを使ったので、そのときの往復400kmが押し上げてる感はある。ちゃんと防寒装備すれば気温2度の中高速道路を走ってもあんまりつらくないことが分かったので、積雪や凍結がなければ真冬でも全然乗れそう。あとは真夏にどうなるか…… 真夏に教習所に通っていたけどほとんど日没後だったので、真夏の真っ昼間にどうなるかはまだ経験していない。自由な移動手段を得たので、CHUNITHM・オンゲキの行脚埋めとかも来年はやりたいですね。
2024年の思い出
しゃかいじんじゅういちねんめ
去年は https://eagletmt.hateblo.jp/entry/2023/12/31/194801
仕事
One Experience というちょうど一年くらいかかった一大プロジェクトが今年の9月頃まで続いていた。去年イギリスに滞在する機会があったのはこれが理由だった。自分は異なるシステム間で単方向のデータ移行というものを担当していて、技術的な概要は社の開発者ブログに書いた通りだが、まぁ大変な話であった。レシピのデータ構造は両者似たようなもので比較的移行しやすかったが、たとえばユーザのデータ構造はかなり離れており、データ元のデータ更新をどう移行するかを考えて実装するのは大変だった。またユーザのデータはメールアドレスやログイン資格などのセンシティブなデータも多く、その意味でも扱いが大変だった。
One Experience プロジェクトに一区切りついてユーザから見たサイト、モバイルアプリは1つになったし Web アプリのコードベースも統合されたが、我々が提供しているサービスはその1つではなく他にもあり、全社で見ると依然として日本のチームが運用してきたものとイギリスのチームが運用してきたものの2つのプラットフォームが存在している。人員もサービスも縮小したいま2つのプラットフォームがあるのは運用上の負荷しかないので、これを1つに統一するということに少しずつ取り組み始めているところである。またプラットフォームだけでなくチームもまた1つに統一していく必要があるわけだけど、日本のチームとイギリスのチームでは言語の壁も時差の壁も厚く、どううまくやっていくか今後模索していくことになる。
イギリスのチームが運用していたプラットフォームでは EKS が採用されていたので、仕事で Kubernetes について触れる機会が一気に増えた。まぁとにかく複雑という感想で、Kubernetes のオブジェクトとコントローラという概念ですべてのものを再構築していて、その抽象化によってオンプレからクラウドまでどこでも運用できるようになっているんだろうけど、数十人規模の開発者が AWS でいくつかの Web アプリを動かすだけの状況では不必要な抽象化レイヤーが多すぎるように感じる。
那覇で開催された RubyKaigi に久しぶりに行った。それまで2016年の京都での RubyKaigi が最後だったはずなのでだいぶ間が空いている。今年参加したのは単純に那覇に行ってみたかったというのもあったし、かつての同僚たちと再会したり最近あまり追えてなかった Ruby 界隈 (?) の状況を感じたいという理由だった。ただ、One Experience に関するアレコレが会期中にも発生して、会にそこまで集中できなかったのは残念だった。
趣味
メトロイドヴァニアというゲームジャンルが好きなことが分かってきたので、今年発売されたゲームを結構やってみていた。その中からおすすめできるものを以下に並べてみる。上にあるほどよりおすすめできる。
- 九日ナインソール https://store.steampowered.com/app/1809540/_/
- パリィ要素がやや強めのソウルライク。自分はパリィはあんまり得意ではないが、タイミングが少しズレても多少デメリットを受けながらもパリィ自体には成功するという調整がちょうどよかった
- 美術、音楽、物語も良く、かなり没頭して遊ぶことができた
- ラスボスを倒すのに4時間くらいリトライし続けたが、リトライが苦にならないような親切さがあるし、リトライを続けていくうちに徐々に上達していく気持ち良さがあった
- プリンスオブペルシャ 失われた王冠 https://store.steampowered.com/app/2751000/_/
- バイオモーフ https://store.steampowered.com/app/1430220/_/
- 倒した敵に変身 (バイオモーフ) して敵の能力を使いながらマップを攻略するゲーム
- 難易度はプリンスオブペルシャ 失われた王冠と同じくらいで、高難易度というほどではなくそこそこというかんじ
- 敵への変身が独自要素ではあるが、変身すると基本的に移動しづらいのでマップ上の特定のギミックを突破するためだけに使って、それ以外は基本フォームでのアクションになってしまうのがもったいない気がする
- ANIMAL WELL https://store.steampowered.com/app/813230/ANIMAL_WELL/
- 攻撃手段が無く、アクションゲーというよりパズルゲーのほうが近いかもしれない
- マップを踏破しながら行動範囲を広げていくという意味ではメトロイドヴァニアと言えそうで、その濃度が高い作品だった
- ボウと月夜の碧い花 https://store.steampowered.com/app/1614440/_/
- 空中で攻撃を当てると再度ジャンプできるというシステムが独特で、これを活かしたギミックがたびたび登場する。必然的に滞空時間が長くなり緊張感がある
- 全体的に良作ではあるものの、ワイヤーアクションの使い勝手が自分には馴染まず、そこが微妙だった
来年は1月からエンダーマグノリアが出るのが楽しみ。
今年も色々なライブに行った。全プリキュア 20th Anniversary LIVE!、イロドリミドリLIVE’24、HIMEHINA LIVE 2024、Nornis LIVE TOUR 2024、i☆Ris 12th Anniversary Live、amusement music fes、あかりGeneration 10周年記念、など。i☆Ris の周年ライブはぴあアリーナ MM での開催で、週一でチケット販売状況を更新していてすごかった https://iris.dive2ent.com/12th-anniversarylive/ 。あかジェネ10周年は同窓会感があってよかった。最近はそこまで頻繁にアイカツ曲を聞いてるわけではないけど体が覚えていた。Let's アイカツ! もやってほしかったねぇ。
(追記) 今年は Palette Project (パレプロ) を知った年だった。きっかけはオンゲキにコラボで3曲収録されたことで、どれも良かったから調べてみたらバーチャルアイドルユニットであることを知った。他の曲も聞いてみても良さそうだったのと、過去のライブのダイジェスト映像的なものを見たらライブでより良さがあるようなものに感じたので、突発で感謝祭2024のライブに行って実際にかなり良かった。パレプロをもっと早く見つけたかったという後悔もありつつ、きっかけを与えてくれたオンゲキにも感謝。
ソシャゲや音ゲーはあまり変わらず。スタレのピノコニー編がかなり面白く、一番更新が楽しみなゲームだった。その流れで崩壊 3rd のシナリオも読みたくなり、スタレコラボイベントのタイミングで始めた。ちょびちょびと進めていてシナリオは面白いところまでまだ進められてないけど……
今年の2月にクロスバイクを買った。いまの住居に引っ越してからはママチャリ*1を買い直して時々使っていたけど、徐々に行動範囲が広がっていってもうちょっといい自転車が欲しいなと思えてきたのでクロスバイクにした。クロスバイクを使うのは人生初で最初の数週間くらいは慣れずに体力を無駄に消費していたが、慣れてきてからは実際乗りやすいなと感じるようになった。そして、片道1時間くらいの範囲であれば基本自転車で移動するようになった。また、オフィスが再び都内に移転してきて、たまたま自宅から自転車で行きやすい場所だったので、通勤も自転車にしている。夏はちょっと早めに出勤して日が落ちてから退勤すれば熱中症対策はそこまで必要ではなく、上の着替えや汗拭きシート的なものを用意しておく程度で済ませられる。一方これからの時期の寒さは悩みどころで、最近は午前中に自宅で仕事した後に出勤するようにしていて、退勤時は日光がない分寒く感じるが気温はそこまで下がらないので何とかなっている。
2023年の思い出
しゃかいじんじゅうねんめ
去年は https://eagletmt.hateblo.jp/entry/2022/12/31/165730
仕事
今年は会社の状況が大きく変わった年だった。退職勧奨やレイオフ、その変化による自主的な退職でとにかく人が減った。それによって自分の仕事にも当然変化があり、今年の後半はイギリスにいるメンバーとコミュニケーションをとる機会が増えた。その関係で一週間ほどイギリスに滞在する機会もあった。海外に行くのは2019年のシアトル以来で、シアトルもなかなか遠かったがイギリスは更に遠い。イギリスは楽しめたが14時間のフライトは拷問以外の何物でもない。
イギリスにいるメンバーとコミュニケーションをとる機会が増えたということは英語でコミュニケーションをとる機会が増えたということで、これが自分にとっては大変だった。Slack や GitHub で英語話者とコミュニケーションをとる機会は今までもあったが、頻度が増えた上に英語の長文 issue やドキュメントを読むのがとにかく遅いのが困る。ソフトウェアエンジニアだと日本人でも AWS コンソールを英語で使ったりスマートフォンを英語で使ったりしている人は普通によく見るが、自分は公式の日本語版がある場合は基本的に日本語版を利用している*1。自分は長い文章については一度全体を流し読みしてから重要そうな箇所を精読し直すような読み方を日本語ではよくしていて、それを英語でできるだけの力がないので日本語と比較して読むのにすごく時間がかかってしまう。英語の力を高めたい気持ちが無いわけではないが、英語メインで仕事をしたいかというとそれは全く無いので、モチベーションが難しい。仕事で必要だから Java や Python に詳しくなりたいけど、別に積極的に Java や Python を使いたいわけでは全くないよな…… みたいなところに英語もある。いや Java や Python よりはもうちょっとモチベーションは高いか。
趣味
ブルーアーカイブは引き続き継続できている。今年の頭には最終編という大きなコンテンツがあって、世間的 (?) にもめちゃくちゃ盛り上がってたと思う。一方で盛り上がりすぎて、一部の変なファンが目立ったりリアルイベントに人が多すぎたりで、数年前のホロライブみたいに急速に自分の興味を失う不安もある。まぁゲーム本編がちゃんと面白いのでゲームをやらなくなる心配はしていない。
あとは崩壊スターレイル (スタレ)、ワールドダイスター夢のステラリウム (ユメステ) と日常的にやるソシャゲが増えた。どちらもリリース初日でこそないがリリースから近いうちから始めた。スタレは PC でプレイできて画面がとても綺麗なのと、原神よりも攻略がだるくないのが気に入っている。対人でランキングを競う要素が無いのも気楽でよい。ユメステはスマホリズムゲーに欲しいものが全部詰まっているのが良い。最高難易度帯になると突然3本以上の指を使う必要がでてくるがずっと2本指だけでやってきた人が3本以上に慣れるためのほどよい難易度の譜面が無い、というのがスマホリズムゲーあるあるだと思うが、ユメステは3本以上必要な譜面を OLIVIER という別の難易度に隔離して、その中で低難易度から高難易度までレベル分けしてあるのがえらい。ただ、この特徴もプロセカ3周年で APPEND という形で実装されてしまい、独自性が早くも失われてしまったので、ちょっと今後が心配ですが…… ユメステはライブイベントも今年豊洲 PIT で行っていて、自分も行ったけどカバー曲無しでオリジナル曲だけという内容で、ゲームリリースから半年経たずにキャストが全員いるわけでもないのにそれができるのは結構すごいなーと思った。
あとはアイカツ10周年の映画とミュージックフェスタ FINAL も今年だった。映画はスタッフトーク回にも行って監督、脚本、プロデューサーのサインの入ったポスターが当たったのが本当に嬉しかった。今も部屋の目立つ位置に飾っている。

FINAL 1日目の冒頭に音響トラブルでダイヤモンドハッピーが中断されておたく大合唱になったり長い MC になったりしたのも良い思い出です。つい先日にフレンズ5周年のイベントがあったり Resound Stars のリベンジ公演があったように、アイカツシリーズの新作が止まってしまっても周年イベントは今後もあってほしいなぁ。5年刻みでも無印 (2012)、スターズ (2016)、フレンズ (2018)、オンパレード (2019)、プラネット (2020) で綺麗に毎年できるね。
他に今年行ったライブは Nornis 1st、i☆Ris 8th、Mia REGINA HEARTBEAT AGAIN、HIMEHINA LIVE 2023 あたりか。後半になるにつれてマスク無しで普通に声を出せるようになってよかった。Nornis は会社のチームメイトも行ってて面白かった。自分は主に戌亥、彼は主に町田目当てだったので今も穏やかな関係が続いています。Mia REGINA はラストライブということで、アイカツ共々今年に閉じたんだなという印象になった。どちらの最終ライブもとても楽しかった。HIMEHINA は今回も新たに別の友人を連れて行って布教した。安定感があるし万人に勧められるというかんじなので次のライブが早く決まってほし~。
音ゲー関連は実力的にもあんまり変わらず。CHUNITHM は今も頻繁に遊んでるが、オンゲキのほうは最寄りのゲーセンから消えたこともあってちょっと足が遠のいてしまっている。今年は自転車をよく使うようになったのでオンゲキのあるゲーセンに行くことも頻繁にあるんだけど、今の時期のように寒いとあまり自転車にも乗りたくないし、それとオンゲキに使う時間がスタレやユメステに変わってしまった感が無くはない。
今年最もプレイしたゲームはティアキンだった。一番面白かったのもティアキンと言っていいだろう。あとは先月末に出たばかりのゲームだけど TEVI https://store.steampowered.com/app/2230650/TEVI/ がとても面白かった。いわゆるメトロイドヴァニアと呼ばれるような 2D 探索アクション RPG をベースに、弾幕ゲーっぽい要素 (敵の攻撃が基本的に弾で、主人公の当たり判定が小さく、ボムで相手の弾を消せる) や格ゲーっぽい要素 (コマンド入力で攻撃) を足した盛り盛りなゲームになっている。自分は格ゲーに馴染みが無いのでコマンド入力せず基本的な攻撃のみで進めたけど。Steam のインディーゲーとしてはちょっと高めの値段だけど、その分ゲームボリュームはあるしサウンドも良いし日本語の声優がやたら豪華だったりする。
趣味開発は…… 今年はこれといったものは無いかなぁ。ISUCON13 で移植のお手伝いをしたくらいか。今年は Ruby と Rust の2つで移植を担当して、Rust のほうは去年までの Actix ではなく Axum を採用するというトライをした。自分が仕事や趣味で使うのもほぼ Axum 一択になってきている。Ruby にも何かしらのトライを入れたかったけど、Trilogy を使ってみるには mysql2-cs-bind 的な gem が無いのが苦しそうだったのと、RBS 対応をやってみようとしたけど Sinatra だと苦しそうだったので、ほぼ例年通りというかんじになってしまった。
2022年の思い出
しゃかいじんきゅうねんめ
去年は https://eagletmt.hateblo.jp/entry/2021/12/30/164456
仕事
2022年が始まったときは自分で手を動かして新しいことに取り組みたいなと意気込んでいたが、2月にデータ基盤チームが解散となり、DWH をはじめとするデータ基盤まわりの仕事を引き継ぐことになり一年を通してこれが自分の仕事の中心となった。解散前にちゃんと引き継ぎのフェーズがあった*1し、DWH 自体は元々興味のある領域だったので DWH の仕事は嫌では全くなかったが、とはいえコードの多くが初見であり社内の標準的な技術スタックから外れたシステムが多かったので、問い合わせ対応やトラブル対応に時間がかかる日々がしばらく続いた。主な仕事としてはログデータに紛れ込んでしまった個人情報をマスキングするしくみを作ったり、Prism が利用している PostgreSQL のデータを削減したりしていた。
これ以外の新しいこととして、就業型インターンシップで学生を多く受け入れた。最近知ったことだが、チーム単位で就業型インターンシップを受け入れた数を比べると自分のチームが特別に多かったようだ。自分のチームには去年から就業型インターンシップを継続してくれている方もいる中で新規に受け入れようと思ったのは、いわゆるリファラルだけでなく現時点で全く繋がりがない人にもきてほしいという個人的な思いがあった。ただ、インターンシップの期間が短すぎたなという反省点がある。自分のチームではたくさんの小さなシステムを開発・運用しているためオンボーディングのコストが高く、最初に目に見える成果を作れるまでの時間がどうしてもかかってしまう。一方で短い期間内に作れそうなものとなるとこぢんまりとしたタスクになってしまう。もし今年うちのチームに就業型インターンシップで来た人がこれを読んでいたら、この点は自分の見積もりが甘くてすまなかったと思っていることを伝えたい。来年も受け入れは続けるが、おそらく今よりも長期間を前提にした募集にすると思う。
趣味
今年はブルーアーカイブへの熱が高まった年だった。去年の8月か9月くらいに始めて、今も継続している。そもそもリズムゲー以外のソシャゲをほぼやったことないというのはあるけど、ここまでソシャゲが継続するのは人生初。当時からシナリオの評判が高かったけど個人的には最初はそこまでピンときてなくて、いま最も評価が高いだろうエデン条約編のシナリオが結構進んだあたりでようやく面白いなと思えた。全体的に昔のエロゲを思い出すようなノリで、そのへんが好きだった世代に刺さりやすいんだと思う。自分の好きなイラストレーターもだいたいブルアカの二次創作をしてるし。ソシャゲ関連だと他にヘブンバーンズレッド、INFINITY SOULS をやった。ヘブバンは麻枝准にはずっと曲とゲームシナリオを書いていてほしいという気持ちが高まった。麻枝准のシナリオが好きならヘブバンのメインストーリーを楽しめると思うけど、ブルアカ以上にメインシナリオを読むための戦闘がキツいのが微妙…… Steam 版を出したのはまじでえらい。リズムゲー以外のあらゆるソシャゲは Steam 版を出してほしい。INFINITY SOULS はたしか2017年のコミケでチラシを配っていたものがようやくリリースされて遊んでみたけど、正直に言ってゲームとしてはだいぶつまらなかった。自分は都築真紀のファンなのでシナリオやキャラクターには惹かれるところがあったけど、戦闘やゲーム性はキツい。開始3ヵ月でテコ入れのようになのはがメインストーリーに絡み始めたのは驚いたが、そこから2ヵ月でサービス終了となり、半年ももたずに消えていってしまった。
今年やってとくに印象に残っているゲームは星のカービィディスカバリー、十三機兵防衛圏、ENDER LILIES かなぁ。例年よりちょっと少ないかも。ポケモン LEGENDS アルセウスはそこまで好きにはなれなかった。ポケモン SV についてはストーリーはポケモンとは思えないくらいしっかりとしていたし戦闘面での調整も基本的に良いものだと思うけど、イベントやマップによっては処理落ちがひどかったり、必要なテラピースの数が多すぎたり、ボックスの表示が遅すぎたりと、なかなか微妙な点が多かった。ポケモン SM や USUM のときもそうだったけど、現代のコンソールゲームにおいて通常プレイで処理落ちがする品質のゲームってちょっとな…… カービィディスカバリーは 3D 初とは思えないくらい違和感ない操作性や視認性があってよかった。ちゃんとクリア率100%までやった。十三機兵防衛圏はこれもまた戦闘パートが蛇足に感じたけどストーリーやキャラクターが良い作品だった。ENDER LILIES はつい最近やったゲームだけど、いわゆるメトロイドヴァニアでインディーとは思えないクオリティで楽しかった。
音ゲー関連では CHUNITHM はレートが MAX 16.16 -> 16.37、バトルランクが S3 -> SS2 になった。レートに対してバトルランクは高いほうだと思う。そして XL TECHNO -More Dance Remix- で無事に S ランクをとり、今年追加されたレベル15でもすべて S ランクをとり銀ポゼになった。次の区切りとしては金ポゼは遠いのでレート 16.50 かなぁ。オンゲキのほうははちゃめちゃに高難易度が追加されていって、解禁がとにかくダルいのがつらかった。オンゲキって今まで楽曲の解禁にノルマ的なものがなくてすごく楽なのが良かったのに…… コンテンツの終了宣言的なものがされ、その具体的な意味が今も分からないままで来年どうなってるんですかね。
今年の Q3 (って表現であってるのか?) は久しぶりにテレビアニメを見た。これも都築真紀の新作である Extreme Hearts が主目的で、ついでにリコリス・リコイル等も見ていた。Extreme Hearts はたいへん面白かったです。
ヒメヒナの現地ライブ良かったですね。前回、前々回のオンラインライブの再演ではあるけど、現地には現地の良さがある。あとは声を出せればというかんじだけど、この点についても最大限気を遣ってハミングなら OK というルールが設定されていたのも良かった。Studio LaRa になったのもこのときだったね。次のライブが来年8月5日と発表されていて、まだ少し先だけど楽しみ。
アイカツがついに10周年となり、記念の映画が公開されたり4ヵ月連続ライブが始まったりした。じわじわと新曲も出てきて良い。その一方でコンテンツとしては止まってしまっているので、来月の映画公開と2月の 2 days のミュージックフェスタ FINAL で終了なのかなぁ。
最後に趣味開発について触れると、slack-thread-expander くらいかな。あとは json-to-parquet も書いたりしたけど、どちらも仕事で欲しくなって書いたのであんまり趣味感がない。slack-thread-expander は Slack のスレッドが大好きな人たちがついスレッドを使ってしまったときにスレッドを無意味にするために書いて、社の Slack で使えるようにしてどうしてもスレッドを使ってほしくない特定のチャンネルのみで有効化したんだけど、自分が知らないチャンネルにも勝手に導入されていて (誰でもどこでも使えるようにしたのでこれ自体は全く構わない)、そこでは普通にスレッドがバンバン使われて slack-thread-expander が日常的に投稿していて、自分の意図とは異なる目的で利用されているのを目撃したりした。そこでは何のために slack-thread-expander が導入されていたのかは僕は分かりません。
*1:明確な引き継ぎがあるのは自分の経験上かなり希である
MySQL でも楽に bulk insert したい
以前 PostgreSQL で unnest を使って楽に bulk insert する方法を紹介した https://eagletmt.hateblo.jp/entry/2021/09/01/030453 。 これの MySQL 版が欲しかったものの array 型が存在しない MySQL では無理かなと思っていたんだけど、MySQL 8.0 からサポートされた JSON 型なら array を表現できて json_table() という関数を使うと達成できそうなことにふと気付いた。
json_table() を使うと JSON の値からテーブル (行) に変換することができる。つまりこれを使えば unnest に近いことが可能になる。
https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html
MySQL [(none)]> select * from json_table('[{"x": 1, "y": 2}, {"x": 3, "y": 4}]', '$[*]' columns (x integer path '$.x', y integer path '$.y')) as t;
+------+------+
| x | y |
+------+------+
| 1 | 2 |
| 3 | 4 |
+------+------+
2 rows in set (0.001 sec)
文法がなかなか独特だけど1つの JSON の値 (配列) から行に変換できている。なのでプログラム側は JSON にシリアライズさえできれば insert into select で bulk insert が可能になる。 PostgreSQL 版と同様に Rust の sqlx を使った例はこんなかんじになる。
#[derive(Debug, serde::Serialize)] struct Record { x: i32, y: i32, } #[tokio::main] async fn main() -> anyhow::Result<()> { let records: Vec<_> = (0..1000) .map(|i| Record { x: 2 * i, y: 2 * i + 1, }) .collect(); let pool = sqlx::MySqlPool::connect("mysql://...").await?; let query = "insert into bulk_inserts (x, y) select * from json_table(?, '$[*]' columns (x integer path '$.x', y integer path '$.y')) as t"; sqlx::query(query) .bind(sqlx::types::Json(records)) .execute(&pool) .await?; Ok(()) }
がんばってプレースホルダを組み立てる必要がなくなって便利。
sqlx crate でフィールド毎に独自のデコード処理を挟みたい
sqlx-with というものを作ってみたので、その経緯について書く。
sqlx crate でフィールド毎に独自のデコード処理を挟みたい
sqlx では query_as() 等の関数を使うことでデータベースから取り出した行を struct にマッピングすることができ、このマッピングは sqlx::FromRow という derive macro を利用することで自動で実装できる。
#[derive(sqlx::FromRow)] struct Row { x: i64, }
このような単純なマッピングではなく、特定のカラムの値に独自の変換処理を入れてから struct に入れたいとする。とくに意味は無いが、たとえばカラム x の値に対して (x, x + 2) という値を struct のフィールド x に入れたいとする。serde であればたとえば split_x という関数を定義して #[serde(deserialize_with = "split_x")] と指定すれば実現できる。これと同じような機能が sqlx::FromRow にあればよさそうだが、現状は無い。なので serde の deserialize_with みたいなものをどうやったら実装できるか考えてみる。最終的には以下のように書けるとよさそうだ。
#[derive(sqlx::FromRow)] struct Row { #[sqlx(decode = "split_x")] x: (i64, i64), }
まず sqlx::FromRow が具体的にどのようなマクロ展開をしているのか実装を見てみると、Row、ColumnIndex、Type、Decode といった様々な trait を使っていることが分かる。
https://github.com/launchbadge/sqlx/blob/v0.6.1/sqlx-macros/src/derives/row.rs
最初の例は以下のような impl を生成している。
struct Row { x: i64, } impl<'r, R> sqlx::FromRow<'r, R> for Row where R: sqlx::Row, &'r str: sqlx::ColumnIndex<R>, i64: sqlx::Type<R::Database> + sqlx::Decode<'r, R::Database>, { fn from_row(row: &'r R) -> sqlx::Result<Self> { Ok(Self { x: row.try_get("x")?, }) } }
特定のデータベースに依存しないようになっているのが特徴で、struct のフィールド名とその型の情報から
&strで特定のカラムにアクセスできる- i64 に対応するデータベース側の型がありデコードができる
という制約をつけている。
ここに split_x という関数を挟んでみると以下のような実装になるだろう。
struct Row { x: (i64, i64), } impl<'r, R> sqlx::FromRow<'r, R> for Row where R: sqlx::Row, &'r str: sqlx::ColumnIndex<R>, i64: sqlx::Type<R::Database> + sqlx::Decode<'r, R::Database>, { fn from_row(row: &'r R) -> sqlx::Result<Self> { Ok(Self { x: split_x("x", row)?, }) } } fn split_x<'r, R>(index: &'r str, row: &'r R) -> sqlx::Result<(i64, i64)> where R: sqlx::Row, &'r str: sqlx::ColumnIndex<R>, i64: sqlx::Type<R::Database> + sqlx::Decode<'r, R::Database>, { let n: i64 = row.try_get(index)?; Ok((n, n + 2)) }
あとはこのように展開されるようなマクロを作るだけ…… とはいかず、このままだと無理なことが分かる。Row の定義から impl の制約を生成しなければならないが、i64 が Type + Decode であるという条件を Row の定義から知ることができないからである。これを知るには split_x のシグネチャを知る必要があるが derive macro には不可能なはず。というわけで sqlx::FromRow ではこのような decode オプションを実装することができない。
sqlx-with
sqlx::FromRow の derive macro で decode オプションを実装できない原因は実装があまりに generic だからだと考えた。sqlx::FromRow を derive macro を使わずに手書きで実装する場合、普通は特定のデータベースを前提に実装する。実際に sqlx::FromRow のドキュメント https://docs.rs/sqlx/latest/sqlx/trait.FromRow.html#manual-implementation でもそのように案内している。
そこで具体的なデータベースを渡せるような derive macro に変えれば、decode オプションを実装できるだけの generic さを残しつつ sqlx::FromRow と同様の便利さを得られそうだ。実際にそのように sqlx_with::FromRow という derive macro を実装してみた。
https://github.com/eagletmt/sqlx-with
use sqlx::Connection as _; #[derive(sqlx_with::FromRow)] #[sqlx_with(db = "sqlx::Sqlite")] struct Row { #[sqlx_with(decode = "split_x")] x: (i64, i64), y: String, } fn split_x(index: &str, row: &sqlx::sqlite::SqliteRow) -> sqlx::Result<(i64, i64)> { use sqlx::Row as _; let n: i64 = row.try_get(index)?; Ok((n, n + 2)) } #[tokio::main] async fn main() { let mut conn = sqlx::SqliteConnection::connect(":memory:").await.unwrap(); let row: Row = sqlx::query_as("select 10 as x, 'hello' as y") .fetch_one(&mut conn) .await .unwrap(); assert_eq!(row.x, (10, 12)); assert_eq!(row.y, "hello"); }
db というオプションにデータベースを渡すことでそのデータベースを前提とした impl を生成でき、split_x のような関数も中で使えるようになった。sqlx::FromRow と異なり指定したデータベース以外には使えなくなってしまうが、現実的に1つの struct を複数の異なる種類のデータベース間で使いまわしたい場面はまず無いだろう。
おまけ: darling
sqlx_with::FromRow という derive macro を実装するために darling というライブラリを初めて使った。proc macro を実装するための derive macro を提供していて、derive macro を実装するには FromDeriveInput を使うと必要な syn の値にすぐにアクセスできる struct が得られて便利だった。
C のヘッダファイルの解析に bindgen を濫用するアイデア
Rust には bindgen というツール、あるいはライブラリがあって binding を書くときに非常に重宝する。
https://rust-lang.github.io/rust-bindgen/
これを濫用すると C のヘッダファイルを解析してマクロの定数値を読み取ったり構造体のサイズを調べたりといったことが手軽に可能そう。
たとえば errno の名前と値とメッセージの一覧を知りたいとき、こんなかんじで errno.h の中身から定義を取り出すことができた。
lazy_static::lazy_static! { static ref MACROS: std::sync::Mutex<std::cell::RefCell<Vec<(String, i32)>>> = Default::default(); } #[derive(Debug, Default)] struct MacroCollector {} impl bindgen::callbacks::ParseCallbacks for MacroCollector { fn int_macro(&self, name: &str, value: i64) -> Option<bindgen::callbacks::IntKind> { if name.starts_with('E') { MACROS .lock() .unwrap() .borrow_mut() .push((name.to_owned(), value as i32)); } None } } fn main() -> Result<(), Box<dyn std::error::Error>> { use std::io::Write as _; bindgen::builder() .header_contents("wrapper.h", "#include <errno.h>") .parse_callbacks(Box::new(MacroCollector::default())) .generate() .expect("unable to collect macros"); let out_dir = std::env::var("OUT_DIR")?; let mut file = std::fs::File::create(std::path::Path::new(&out_dir).join("errno.rs"))?; writeln!(file, "pub const ERROR_NUMBERS: &[(&str, i32, &str)] = &[")?; for (name, value) in MACROS.lock()?.borrow().iter() { let message = unsafe { std::ffi::CStr::from_ptr(libc::strerror(*value)).to_str()? }; writeln!(file, "(\"{}\", {}, \"{}\"),", name, value, message)?; } writeln!(file, "];")?; Ok(()) }
当然こういう用途に使うものではないのでグローバル変数に結果を書き込むことになっているけど、build.rs 内ならまぁ許されるだろう。 本格的に解析するなら bindgen と同様に libclang を直接使ったほうがよさそうだけど、手軽に定数やシグネチャを拾うくらいなら bindgen を濫用するのが楽そう。