有名テック企業の技術ブログを、ひとつのフィードで。
フィード
35件
こんにちは。プロダクト開発部の森 @jiskanulo です。 2026年4月22日から24日までRubyKaigi 2026 Hakodateが開催されました。 rubykaigi.org 函館アリーナを3日間に渡って貸し切る大規模イベントの運営をしていただきましたスタッフの皆様に感謝を申し上げます。 ファインディ株式会社もPlatinumスポンサーとして協賛しました。 私もブースに立って出展やファインディ各サービスのご案内をさせていただきました。 お話しをしていただいた皆様にも重ねて感謝申し上げます。 ブースに立つ合間にセッションを聞いて自分でやれそうなことに思いを馳せたり、他社様のブースを回ってプロダクトのお話をしたり、昔の同僚や知人と再会したりと個人的にもいい刺激の多い3日間でした。 さて、4月24日、最後のセッションのMatzさんのキーノートにてRubyファイルをネイティブバイナリにコンパイルするSpinelが発表されました。 早速Spinelを使ってみた感想とつかいどころを記します。 Spinelとは 検証環境とセットアップ 動かしてみた Hello, World! eval / requireの挙動:エラーにならず無音で間違う eval は no-op に置き換わる require は文ごと消える 現時点での注意点 Spinelを使ってみる requireなしでJSONを扱う ハマりどころは個別に踏みに行く価値がある Spinelを試すときの判断基準 個人的所感 おまけ: Spinelの由来 おわり Spinelとは SpinelはRubyのAOT (Ahead-Of-Time) コンパイラです。 RubyソースコードをPrismでパースし、全プログラム型推論を行いCのコードに変換してネイティブバイナリを生成します。 パイプラインは次のとおりです。 Ruby → Prism → AST → 全プログラム型推論 → Cコード → ネイティブ実行ファイル リポジトリのREADMEによると、miniruby比で約11.6倍、Conway's Game of Lifeでは86.7倍という性能が示されています。 またバイナリサイズもmrubyを含めずに数十KBに収まるので容量が厳しい環境にも適用できるとのことです。 実体としての./spinelはPOSIX shell wrapperで、内部でspinel_parse → spinel_codegen → ccを直列に呼び出している、という作りです。 検証環境とセットアップ 検証は手元のmac環境で行いました。 4月24日公開直後にmacで動かそうとしたタイミングではmalloc.hが存在しないなどでエラーになったのでDockerでUbuntuのコンテナを起動して操作しましたが、現在は対応されています。 土日で函館観光しているうちにコントリビュートが進んでいますね。コントリビュートのチャンスですね。 mac build対応 https://github.com/matz/spinel/commit/4593581eb87cea45b59fb28b9dcf2cd75a9bcbab windows対応 https://github.com/matz/spinel/commit/1fe3136aa9bf834b5f37176faca7346503fb1446 環境は次のとおりです。 macOS (arm64) Apple Clang Spinel masterブランチ(2026-04-28時点) ビルドと実行の基本フローはシンプルです。 spinelをmakeし、spinelにrubyファイルをわたせば実行形式バイナリが出力されます。 make deps # 初回のみ: libprism 取得 make # spinel_parse / spinel_codegen / ランタイムをビルド ./spinel app.rb # Ruby → 実行形式(./app) ./app 動かしてみた Matzのキーノートとも被りますがサンプルコードを動かしてみました。 またキーノートで話があったとおりevalとrequireはサポートしていないとのことです。 eval, requireを使うと具体的にどうなるのかも試してみました。 Hello, World! 最小の動作確認はそのまま動きます。 # hello_world.rb puts "Hello, World!" ./spinel hello_world.rb ./hello_world # => Hello, World! eval / requireの挙動:エラーにならず無音で間違う 2026年4月28日の現時点ではコンパイル時にエラーにならず、warningも出ず、しかし実行すると無音で間違った出力を返すという挙動です。 具体的に2つのケースを見ていきます。 eval は no-op に置き換わる 次のRubyコードをSpinelでコンパイルして実行します。 # test_eval.rb code = "1 + 2" result = eval(code) puts result $ ./spinel ./tmp/jiska/samples/test_eval.rb ./tmp/jiska/samples/test_eval.rb -> test_eval 実行すると結果は0です。 $ ./test_eval 0 生成されたCのコードを見るとeval()の呼び出しがno-opに置き換わり、戻り値は型推論で決まったゼロ値(mrb_intのため0)になります。 const char *lv_code = "1 + 2"; mrb_int lv_result = 0; // mrb_int = int64_t typedef lv_code = "1 + 2"; lv_result = 0; // ← eval() 呼び出し自体が消滅、0 を代入するだけ printf("%lld\n", (long long)lv_result); mrb_int はmrubyのような」命名に見えますが lib/sp_runtime.h で int64_t のtypedefとして定義されたSpinelランタイムの整数型です。 https://github.com/matz/spinel/blob/64105ec86d08c9edc92c3d17bf059126ceaa15d3/lib/sp_runtime.h#L53 require は文ごと消える 次はrequire "json"とJSON.generateを使うケースです。 # test_require.rb require "json" puts JSON.generate({ name: "spinel", year: 2026 }) こちらも実行すると0になります! $ ./spinel ./tmp/jiska/samples/test_require.rb ./tmp/jiska/samples/test_require.rb -> test_require $./test_require 0 requireの行は生成されたCのコード上で文ごと消えます。 続くJSON.generateもSpinelから見れば未定義メソッドであり、evalと同じくゼロ値を返す呼び出しに化けます。 最終的にputsには0が渡って表示される、という流れです。 現時点での注意点 現時点では「コンパイルが通った」「実行ファイルができた」「実行できた」の3点だけを見ていると間違った結果を吐いていることに気づけません。 Spinel向けにRubyを書くときはREADMEを都度確認することが重要です。 Spinelを使ってみる 次に実際のユースケースを想定してみます。 実例として、GitHubのPR一覧JSONを入力に取り、各PRのnumberとauthorを表示するスクリプトを書いてみました。 入力はARGV、stdinの優先順で受け取ります。 requireなしでJSONを扱う require "json"が使えないので標準のRegexpとString操作だけで処理を組む必要があります。 なお、ここで示すコードは正しいJSONパーサではありません。require "json"が使えないSpinelの制約下で、入れ子オブジェクトや},を含む文字列値が現れない、フラットな配列形式の固定データからnumberとauthorをアドホックに取り出す例として読んでください。本格的なJSON処理が必要な場合は、入れ子・エスケープなどで容易に壊れるため、この実装は使えません。 実際のRubyファイルは次のとおりです。 多少トリッキーなところは感じますが、こうした限定的な用途であれば、RegexpとStringの標準機能だけで実装できることがわかりました。 if ARGV.length > 0 input = ARGV[0] else input = readlines.join end records = input.split(/},/) results = [] records.each do |chunk| if chunk =~ /"number"\s*:\s*(\d+)/ num = $1 if chunk =~ /"author"\s*:\s*"([^"]+)"/ auth = $1 results << "##{num}<span class="sy
はじめに こんにちは。プロダクト開発部 転職開発チームでエンジニアリングマネージャーをしている松村(@shakemurasan)です。 2026-04-22(水)から2026-04-24(金)までの3日間開催されているRubyKaigi 2026に現地参加しています。 rubykaigi.org この記事は、Day1 13:00-13:30のkoicさんのセッション『Exploring RuboCop with MCP』について、事前準備編と当日編(セッション当日に残したメモと感想)を1本にまとめたものです。 事前準備編にはAIによる予想が含まれるため、実際のセッション内容と一致するとは限らない点をあらかじめ断っておきます。 はじめに 事前準備編 koicさんの人となり AIに予想させてみたら、本人告知で焦点が絞れた 本人おすすめの教材とPRを少し覗いた 当日編 前半: MCP Ruby SDKとStreamable HTTP 後半: この1年間の試行錯誤 結びへ: 決定性と非決定性、そしてElicitation 聴き終えて腹落ちしたこと おわりに 事前準備編 koicさんの人となり koicさんはRuboCopのトップコミッターで、2025年にはMCPの公式Ruby SDK (modelcontextprotocol/ruby-sdk) のメンテナーにも加わっています。 github.com そこまでの道のりはFindy Engineer Labの取材記事『365日欠かさずコミットを積む。なぜRuboCopコミッター伊藤浩一はOSSと向き合い続けるのか』と、直近のお話はご本人のブログ『MCPの公式Ruby SDKのメンテナーに加わった』で詳しく綴られています。 findy-code.io koic.hatenablog.com 個人的な話をすれば、私がRubyを書き始めて数年の頃、地域のRubyコミュニティで何度かkoicさんをお見かけし、ジュニア時代の自分に刺激をくれた方の一人でもあります。 AIに予想させてみたら、本人告知で焦点が絞れた セッションタイトルだけでは論点が見えにくかったので、実は事前に予習の材料として、AIにkoicさんの直近のPRやIssueをもとに内容を予想させていました。 返ってきたのは大きく3通りの案でした。 1つ目は、stdio実装とMCP primitives(tools / resources / prompts)の写像を中心に据える構成。 2つ目は、MCPのtool annotationとRuboCopのCop属性の対応を核に据える構成。 3つ目は、Streamable HTTPを軸に据え、組織運用論にまで広げていく構成。 いずれもkoicさんの公開PRやIssueから拾えそうな筋ではあり、最初は「なるほどこのどれかだろうな」と眺めていました。 その後、koicさんご本人が『RubyKaigi 2026に登壇します』で背景と予習の案内をすでに公開されていることに気づきました。 koic.hatenablog.com 本人告知で軸に置かれていたのは「RubyツールチェインへのAI時代の課題提起」で、Streamable HTTPは副題として明示されていました。 一方で、tool / resource / promptといった「よく溢れている情報」は深掘りしない、とも明言されています。 AIの予想と本人告知を観点ごとにまとめると、次の通りです。 観点 AIの予想 本人告知 中心軸 RuboCop実装詳細 / MCP primitivesの写像 RubyツールチェインへのAI時代の課題提起 Streamable HTTP 1案の中心、他2案では末尾に触れる程度 副題として明示、講演の大きなトピック tools / resources / prompts 写像の中心概念として扱う 「よく溢れている情報」として深掘りしない旨を明言 当たっていたのは「Streamable HTTPが主要トピックの1つ」と見立てていた点で、大きく外れたのは「tool / resource / promptを写像の中心概念として扱う」という方向性でした。 AIの予想は世に広く出回っている話題の重心に引っ張られやすく、本人が「あえて深掘りしない」と宣言していた領域こそがむしろ中心に置かれていた、というコントラストになります。 そのおかげで、当日聞きに行くべき焦点が一気に絞れました。 本人おすすめの教材とPRを少し覗いた 本人告知で紹介されていた教材のうち、RubyWorld Conference 2025でのkoicさんの登壇アーカイブに目を通しました。 「なぜstdioだけでは足りず、双方向のHTTP通信が必要なのか」という道筋が登壇の流れで追えるため、セッション前のウォームアップに助かりました。 当日編 本編は事前告知どおりの2部構成で、前半がMCP Ruby SDKの話、後半がRuboCop x MCPの話でした。 なお、当日のセッション資料は『Exploring RuboCop with MCP』としてすでに公開されています。 speakerdeck.com 以降は、現地で受け取った温度感の記録として読んでもらえればと思います。 前半: MCP Ruby SDKとStreamable HTTP Ruby SDKはもともとShopify社内で少人数のエンジニアが始めたもので、koicさん自身もRuboCopを念頭に早い段階から参画し、コミッターに招かれたのち、mcp gemとして公開された、という経緯が紹介されました。 MCPにはTier1〜3のランクが定義されていて、現在のRuby SDKはTier3。 Tier1を目指していく、と明確に宣言していました。 本題のtransportsの話では、規格としてstdioとStreamable HTTPの2つが並びます。 stdioの単純さはさらりと触れ、時間が割かれたのはStreamable HTTPのほうでした。 HTTPの規格のままで、WebSocketのような独自プロトコルに寄らずに双方向通信を成立させる。 実装はRackアプリケーションとして組んでおり、HTTPで叩かれたタイミングでMCPセッションIDを払い出してセッションを確立し、Queueを介してやり取りを何往復も成立させる。 1リクエスト1レスポンスではなく、1リクエストを起点にサーバー・クライアント間で通信が走る、という絵が丁寧に描かれていきます。 手を動かさないと実感が湧きにくい領域ですが、Rackの上に素直に乗っているという話を聞いた瞬間、普段触っているWeb技術の延長線上で捉えていい話なのだ、と急に距離が近く感じられました。 そして前半の締めでkoicさんが置いた次のようなニュアンスの一言が、個人的に一番刺さっています。 「AIになってガラッと変わったと思われるが、Linuxであるとか低レイヤの世界は何も変わっていなくて、我々はその上で開発をしているに過ぎない」 弊社でもたびたび話題に上がる「AIの台頭によりエンジニア自身にとってはむしろ基礎が大事になっていく」という考え方と一致しており、強く共感しました。 後半: この1年間の試行錯誤 後半はトーンが少し変わりました。 「1年間いろいろ試行錯誤してきたが、うまくいかなかったことが多かった。その話をします」とkoicさんが率直に切り出します。 成功譚ではなく、試行の経過と現在地の共有だ、というモードに切り替わりました。 最初のアイデアはシンプルで、RuboCopの結果をJSON構造でMCP化すればAIフレンドリーになって良いのではないか、というものでした。 しかし実際に手を動かしてみると、RuboCopはそもそも著名なgemなので、AI側もすでに相当学習していたように感じられた、と振り返ります。 わざわざMCPの皮を被せなくても、ある程度のことは既にできてしまう相手だった、ということです。 アイデアを広く募集して議論もしたものの、寄せられたものをそのまま実装して全員が喜ぶ機能になる自信は持てなかった、とも続きます。 結びへ: 決定性と非決定性、そしてElicitation そこから結びに向けて「RuboCopはこれまで、インプットに対して結果が一意に定まるものだった」と改めて位置づけ直されます。 「決定性こそがLinterとしての価値だった」という前提を言葉にしたうえで、そこに非決定性を持つLLMを組み合わせたら何ができるのか、と続きました。 具体例として並べられたのは、LLM側に委ねるSamplingと、ユーザーに聞き返すElicitationでした。 どちらもサーバーからクライアントに問い合わせを返せる仕組みですが、自分の耳に特に残ったのはElicitationのほうです。 ユーザーに対して定まったフォーマットの質問と回答フォームを返せる仕組みで、「この修正、どう進めたい?」と聞き返す余地をMCPの上で作れる、という話として置かれていました。 決定性のあるRuboCopの流れのなかに人間に問いを返すポイントを差し込み、そこを挟んだ非決定性を許容する。 決定性を捨てる話ではなく、どこで問いを立て、どこで非決定性を受け入れるかの設計の話として受け取りました。 この時私が思い出したのは、自チームでRuboCopのルール改廃を議論する時の話です。 一元的に適用するか悩ましいものが出てきたとき、その悩みには既存コードの暗黙的な規約、各エンジニアの思想や経験、copとして定義されているベストプラクティス、と様々な要素が絡んでいます。 これらは機械的に一意には定められないものです。 この統治過程にLLMが自然な形で介入し、対話を経てLinterに落とし込んでいくのはありそうな役割だと感じました。 (それをRuboCopの機能として提供されてユーザーが嬉しいかはさておき) ちなみにMCPの規格としてElicitationが発表された当時、弊社でも管理者向けのLocal MCP Serverにこれを組み込む事例があり、『生成AI時代のサービス運営管理 - MCP Server for Administratorの実践 -』(2025年9月16日公開)としてまとめられています。 tech.findy.co.jp 一方通行になりがちなMCPのやりとりに confirm / approveのステップを挟むという考え方は、koicさんが当日RuboCopの文脈で示したElicitationの位置づけとそのまま重なるものでした。 聴き終えて腹落ちしたこと 少なくともセッションの内容は「RuboCop x MCPのベストプラクティスがバシッと決まっている」わけではないということです。 むしろ、当事者として踏み抜いた人しか持ち得ない肌感を、苦労ごと公開してもらった30分だった、というのが近いと思います。 文字にするとシンプルですが、現場で聴講した皆さんにはkoicさんの試行錯誤と苦労が生々しく伝わっていたのではないかと思います。 現地参加する醍醐味をこういうところにも改めて感じました。 MCP化が思ったほど刺さらなかったこと、アイデアを集めても一意の答えに収束しないこと、Human in the Loopをどう設計するかが実装より先にあること。 どれも、ドキュメントや事例紹介を眺めていても掴めない、当事者として踏み抜かないと分からない種類の手触りです。 前半と後半を通して一本の線で繋がっていたのは、RubyツールチェインをAI時代にどう位置づけ直すかという問いだったように思います。 Streamable HTTPという具体的な技術基盤の話と、RuboCop x MCPと