EVE Online の240万行の Python 2 — 先送りされた移行は負債か判断か

2003年にローンチした MMO が2026年になってようやく Python 3 への移行を開始した。16年間同じランタイムに留まった選択は、放置された技術的負債なのか、それともコストとリスクを正確に計算した経営判断なのか。

導入

2026年8月25日、EVE Online の開発チームが「The Move to Python 3 Begins!」と題した開発ブログを公開した。2003年にサービスを開始し23年目を迎えるこの宇宙 MMO のサーバーコードが、ようやく Python 3 への移行を始めるという告知である。発表文が自ら掲げた成功の定義は奇妙なほど控えめだ。この移行の成功とは「まったく気づかれずに」終わることであり、例外があるとすれば「何かがほんの少し滑らかに動く瞬間」くらいだと書かれている。

Python 2.7 の公式サポートは2020年に終了した。発表時点で6年以上が経過している。その間 EVE は、2010年に上げた Stackless Python 2.7 の上でランタイムを一度も変えずに動き続けてきた。発表文の表現をそのまま引けば、16年間同じバージョンに留まったという事実は、その選択がいかにうまく機能していたかを物語る。そして続く一文がこの記事全体の鍵である。「十分に信頼できたからこそ、大規模で潜在的にリスクのある移行はこれまで自らを正当化できなかった」。

Hacker News に投稿されたこの記事は406ポイントと227件のコメントを集めた。最初の反応は嘲笑ではなく驚きだった。「日付を確認してしまった」と書いたユーザーがいて (@jamesnorden)、「2026年にこの見出しを読むのはちょっと面白い」という反応も出た (@q8zd3)。だが議論が深まるにつれ、問いの向きが変わっていった。16年は失敗した放置なのか、それとも毎回正しかった計算の積み重ねなのか。幸いこの発表文は感想ではなく数字を出してきた。数字を追えば答えの輪郭が見えてくる。

コンパイラを唯一の真実とする — 240万行の実測座標

発表文が公開したコードベースの規模は Python 240万行、ファイル約2万個である。単純に割れば1ファイルあたり平均120行ほどだ。このうちかなりの部分は Python 2.7 よりさらに古い時代のコードで、2.3 や 2.5 の頃の作法で書かれ、Python 3 がそもそもパースを拒否する構文を含んでいる。

ここで開発チームが採った方法論が、この発表文のもっとも実務的な部分である。彼らは移行距離を推定せず、計測した。約2万個のファイルすべてを、実物の Python 2.7 インタプリタと実物の Python 3 インタプリタでそれぞれコンパイルしたのだ。理由は明快で、コードがパースできるかどうかについてはコンパイラこそが唯一の真実 (ground truth) だからである。静的解析器の推定でも開発者の勘でもなく、実行可能な判定が毎日観測できる数字を生む。

初回スキャンの結果は、発表文の言葉どおり「嬉しい驚き」だった。ファイルの95.9パーセントがすでに両バージョンでコンパイルできた。Python 3 が拒否する構文を使ういわゆるブロッキング行は、240万行のうち約3,300行。比率にして0.14パーセントである。内訳も具体的だ。旧式の print 文が約1,500件、123L のような long リテラルが約800件、EVE のローンチより前に非推奨となった構文で書かれた例外節が約600件、そして「等しくない」を意味する <> が50件。最後の項目について発表文は、現役の Python 開発者の多くが見たことすらないほど古い書き方だと付け加えており、HN でも実際にその反応が出た (@orsenthil)。

算術的にはファイルの4.1パーセント、およそ800ファイルほどに3,300行が散らばっている計算になる。発表文が「山だと思っていたら、大きいが非常に計測可能な丘だった」と書いた根拠がこれだ。第1段階はこの丘を削る作業であり、道具は Python-Future である。Python 自身がこの種の移行のために配布していたコード書き換え機構 2to3 の上に建てられたツールで、古いパターンを一つずつ現代的な形に書き換える「フィクサー」を適用する。肝心なのは、その出力が Python 2.7 と Python 3 の両方で受け入れられる形だという点だ。つまり第1段階の間、サービスは 2.7 の上で動き続ける。

制約条件も明記されている。すべてのキャラクター、すべてのスキルポイント、すべての格納庫のすべての資産、すべてのウォレットのすべての ISK が Python 2 のコードで書き込まれており、その全部が Python 3 で寸分違わず同じ値として読み戻されなければならない。しかも本番サーバー Tranquility は、24時間のうち23.75時間を生き続けている必要がある。7月にテストサーバー Singularity で第1段階の変更分をプレイヤーとともに検証し、発表当日にその変更分が本番へ配備された。

成功事例もすでにある。同じ開発元の EVE Frontier は、自社の Carbon エンジンを最新の Python 3 の上ですでに動かしている。発表文によれば Frontier の移行は Python のマイナーバージョン12個分、言語進化16年分を一気に飛び越えるプロジェクトだった。ただし発表文はその成功をそのまま貼り付けはしない。Tranquility には23年分のコードだけでなく23年分の実プレイヤーデータが積み上がっており、その重さが Frontier とは決定的に違うと自ら線を引いている。

先送りは怠慢ではなく値札だった

移行を先送りにした16年を理解するには、EVE がただの Python ではなく Stackless Python の上に建てられたという事実から見る必要がある。発表文の説明どおり、Stackless の軽量な「タスクレット (tasklet)」は、サーバーノード1台で数千人のパイロットを同時にさばくことを可能にした仕掛けである。そして開発元は Stackless を単に採用しただけでなく、もっとも重要な貢献者の一つになった。ここで問題の性質が変わる。これはランタイムを差し替える作業ではなく、自らが共同著者である言語フォークを捨てる作業なのだ。

上流の状況もすでに決着している。Stackless の本体リポジトリ stackless-dev/stackless は現在アーカイブ状態で、最後のプッシュは2025年2月13日である(GitHub API で確認)。上流が止まれば維持コストはすべて自分持ちになる。発表文が挙げた二つ目の動機がまさにこの点だ。現代的なライブラリ、デバッガ、プロファイラはすべて Python 3 を前提に作られており、Python 2 に留まる年ごとにそのうちより多くが手の届かない場所へ押しやられ、その分だけ「ゲームを良くする代わりに自分たちで保守しなければならない」ものが増えていく。

HN の議論でもっとも鋭い問いはここから出た。あるユーザーは Stackless をどう処理したのか、greenlet に行ったのか asyncio に行ったのかと尋ね、自分で調べたうえで「どちらでもなく自前だ」として carbonengine/scheduler リポジトリを共有した (@zzzeek)。実際に確認すると、そのリポジトリは MIT ライセンスの C++ プロジェクトで、リポジトリ説明は「Greenlet コルーチンのためのチャネルとスケジューラを提供する」であり、README はタスクレットとチャネルのスケジューリング順序と挙動を Stackless Python にできるだけ近づけて設計したと述べている。ただし Stackless API のすべてではなく、Carbon が必要とする機能のみを実装したとも明記されている。正確に言えば asyncio でもなく純粋な greenlet でもない。greenlet コルーチンの上に Stackless 互換のスケジューラとチャネルを実装し直した自前のレイヤーである。

ここで必ず区別しておくべきことがある。今回の発表文は、EVE Online 本番の Stackless をどうするのかについて一言も述べていない。Simon Willison も同じ点を指摘している。公開されているのは Carbon エンジンと EVE Frontier の側に Stackless を離れた解があるという事実であり、その解が Tranquility にそのまま適用されるかどうかは発表されていない。移行計画のもっとも難しい軸が、まだ公開範囲の外にあるということだ。

先送りの経済学は EVE だけの話でもない。HN であるユーザーは、ゴールドマン・サックスと JP モルガンがつい数年前まで Python 2.7 をコア言語として維持しており、いまも本番に残っていると証言した (@chews)。別のユーザーは、銀行では Python がフロントオフィスのトレーディングソフトにおける「Visual Basic」のような位置を占めており、メジャーバージョンの移行には数年かかり、数億ドル規模のコストと数千人の開発者を要し、ミスは高くつくと付け加えた (@cyberpunk)。さらに別のユーザーは、名の知れた金融企業が10年以上古い Python バージョンに縛られてサポート終了済みの SDK を使い続け、API 変更で壊れた経験を伝えている (@lokar)。これらの証言が描く絵ははっきりしている。ランタイム移行を先送りする判断は、四半期単位で見ればほぼ常に合理的なのだ。コストは即座に発生し、便益はぼやけており、失敗の損失は破滅的である。

懐疑論も載せてこそ公平だ。あるユーザーは、240万行の Python に対する解決策がさらに多くの Python であり、その主たる動機が「パフォーマンス」であることを冷笑した (@oybng)。この冷笑には技術的な裏づけも付く。長年のプレイヤーでもある開発者は、EVE のボトルネックは単一サーバーの処理速度ではなくネットワーク IO とデータベースの往復であり、ネットワーク層はすでに C で書かれていると指摘した (@ShinTakuya)。大規模戦闘で時間を引き延ばす TiDi の原因がインタプリタ速度でないなら、インタプリタの置き換えが体感性能をどれだけ変えるかは検証されていない約束にすぎない。発表文自身もこの点では後退している。最近の Python 3 リリースが言語史上屈指の高速化をもたらしたと書きながら、それが EVE にとって具体的に何を意味するかは「言うにはまだ早い」と明示しているのだ。

もっとも根本的な批判は言語ポリシーに向かう。あるユーザーは、2002年の Perl 5.8 で書いていればファイル先頭にバージョン宣言を一行入れるだけで今日の Perl 5.42 でそのまま動かせただろうとして、Python はすでに書かれたコードより、まだ書かれていないコードを優先しているように見えると記した (@amiga386)。並行性設計への惜しみの声も出た。Stackless のタスクレットと継続の組み合わせは、永続的な状態を持つ長時間実行タスクに大きな可能性があったのに、現代の Python は asyncio という別の方向へ行ってしまったという指摘である (@est)。

残る2万行、そして EOL を帳簿に載せる方法

今回の発表で実務者がもっとも長く噛みしめるべき数字は、3,300 ではなく 20,000 である。同じスキャンが数え上げたところでは、両バージョンで問題なくコンパイルできるのに挙動が変わるコードが約2万行ある。機械が直せる部分より、人間が一行ずつ読まなければならない部分のほうが6倍多い。

発表文が挙げた古典的な例が除算だ。Python 2 では 1 / 2 は 0 だが、Python 3 では 0.5 になる。その数値がダメージであり ISK であり座標であるとき、各行は機械的な置換ではなく人間の判断を要求する。これが第2段階の中身であり、第1段階を先にやる理由でもある。機械的な瓦礫を先に片づけてこそ、人間の注意が本当に人間を必要とする場所だけに使われる。注目すべきは、この2万行が静的解析で洗い出した候補リストであって不具合リストではない点だ。実際に何行が誤動作するかは誰も知らない。検査が生んだのは答えではなく、有限で数えられる作業キューである。移行の不確実性を消したのではなく、境界線を引いたのだ。

シナリオは三つに分かれる。楽観的には、第2段階の2万行はほとんどがテストで濾し取られ、データ互換性を保ったままインタプリタが入れ替わり、プレイヤーは本当に何も気づかない。悲観的には、整数除算や文字列とバイト列の境界から来る微妙な誤差が経済システムや戦闘判定に染み込み、発生時点と検出時点が数週間ずれる。23年分の実データが積み上がった世界では、この種の誤差はロールバックではなく補正作業を要求する。現実的にはその中間だろう。発表文がすでに述べているとおり、マイルストーンごとに Singularity のプレイテストを挟む理由がこれであり、ここでプレイヤーコミュニティはマーケティング装置ではなく実際の検証インフラである。

まとめると、実務者に残る教訓は三つだ。第一に、移行可能性は議論の対象ではなく計測の対象である。コンパイラの通過率は会議で言い張れない数字であり、毎日再実行できる。第二に、EOL の利息はコードではなく周辺に積み上がる。コードそのものは EOL の翌日も同じように動く。代わりにライブラリ、デバッガ、プロファイラ、採用市場、上流リポジトリが一つずつ剥がれ落ちていく。Stackless のリポジトリがアーカイブされた時点から、その維持コストは全額自己負担になった。第三に、EOL は日付ではなく条件である。2020年1月1日に何も起きなかったという事実が誤解を生む。組織が帳簿に載せるべきは日付ではなく「いつからこのランタイムの上で必要な道具が手に入らなくなるのか」という条件であり、その条件が満たされる時点は告知なしに静かにやってくる。

結論

先送りされた移行は失敗か判断か。正直な答えは、どちらも真だが時間軸が違う、である。四半期単位で見れば毎回正しかった。発表文自身が「十分に信頼できたからこそ、大規模でリスクのある移行は自らを正当化できなかった」と書いており、これは言い訳ではなく正確な記述だ。しかし、その正しい決定を64四半期積み上げると、言語史上最大級の性能向上をそのまま見送り、上流がアーカイブされたフォークを一人で抱え、世代の変わった道具のエコシステムの外に立つ組織になる。個別には合理的な選択の総和が、集合的には不合理な位置を作り出す。

だからこの発表からもっとも学ぶべきは移行計画ではなく計測方法である。2万個のファイルを二つのインタプリタでコンパイルし、3,300 と 20,000 という二つの数字を得た瞬間、16年分の漠然とした恐怖は有限の作業リストに変わった。負債を返す前に、負債を計上したのだ。

残る問いはそれぞれの組織に向かう。いま本番で動いているランタイムやフレームワークのうち、上流がすでに止まっているのにまだ帳簿に載っていないものは何か。そしてその距離を今日測るには、どんなコマンドを一行走らせればよいのか。EVE はその答えがコンパイラ二つだったと教えてくれた。


出典: