0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VBAマネージャーが遅くなりすぎたので、犯人を一人ずつ挙げた話

0
Posted at

はじめに

自作の VBA 管理ツール「shu-vba-manager」の更新告知です。

前回の記事(クロード・フェーブルが復活したのでVBAマネージャーを改修した話)から一週間ほどで、リポジトリには 29 コミット積みました。大きいのは次の2つです。

  • MCP サーバー化:コマンドごとに払っていた COM 接続のコストが消え、応答が実測 0.01〜0.2 秒級になりました
  • 本体の5分割:9,000 行を超えて一枚岩の限界が来ていた vba_manager.py を、薄い入口+5パートに分割しました(使い方は不変です)

1.png

コードは全部ここにあります。

なぜ今書くか

正直に書くと、一時期このツールはどうしようもなく遅くなっていました。作った本人が使っていてつらいレベルです。

機能を足し続けた半年で、行数は 12,000 行を超えました。それ自体は悪くないのですが、遅さの犯人が何人か紛れ込んでいて、しかもどれも「壊れてはいないが遅い」タイプでした。エラーは出ない。ただ、じわじわ重い。

この一週間でその犯人を一人ずつ挙げて、全員退場させました。その記録と告知です。

TL;DR

  • vba_manager を MCP サーバー化しました。常駐 COM 接続で応答 0.01〜0.2 秒級(従来は1コマンドごとに接続し直し=全工程で一番重い処理を毎回払っていた)
  • マクロ実行中のダイアログで無言のまま固まる問題を根治しました(遅さの体感の正体のひとつ)
  • ゾンビ Excel/非表示 Excel の残留を始末するようにしました(次の作業を壊す時限爆弾でした)
  • 総点検を3回やって残存バグを掃討、モジュール名衝突ガード無効なプロシージャ名の機械拒否を全経路に配線しました
  • ブックの検分コマンド(snapshot / snapshot-diff / wiring)を足しました。増えた理由はやらかしです(本文で正直に書きます:実データのブックに破壊系マクロを撃った話、健全な名前付き範囲を巻き込んだ話)
  • 前回記事の公開ブックに作成者のフルネームが残っていた後日談から、公開前チェック(publish_check.py)を1コマンド化して同梱しました
  • 本体を薄い入口+5パートに分割しました。呼び出し方は一切変わりません
  • 現在 72 コマンド/一式 12,608 行/pytest 67 件(2026-07-12 実測)

前回までのあらすじ

Claude Code と会話しながら Excel VBA を直す自作ツール vba_manager.py の話を連載しています。マクロの取得・置換から始まり、シート・テーブル・ピボット・パワークエリまで触れる「開いたままのブックを扱う Excel マネージャー」に育ちました。前回は総点検と「健康診断」コマンドの話でした。

本題1: MCP サーバー化 ── 一番重い処理を一回きりにする

このツールの CLI は、1コマンド実行するたびに Excel へ COM 接続していました。接続は全工程で一番重い処理です。1コマンドなら気になりませんが、AI との会話では「見る→直す→確かめる」で何十コマンドも撃ちます。毎回の接続コストが積もって、会話全体がもたつく。

そこで vba_manager を MCP サーバーにしました。と言っても本体は書き換えていません。195 行の薄い窓口(vba_mcp_server.py)を上にかぶせただけです。

  • サーバーが COM 接続を常駐で持ち、コマンドは使い回した接続で即応答
  • ツールは5つだけ。vba(command) に CLI と同じ引数列を渡せば 72 コマンド全部使えます
  • アイドルが続いたら COM 参照を自動で手放します(接続を握ったままだと Excel を閉じてもプロセスが成仏できない、いわゆるゾンビの原因になるため)。再接続は実測 0.018 秒なので、速度は無傷です

応答は実測 0.01〜0.2 秒級。体感がまるで違います。

本題2: 遅さの犯人たち

MCP 化で「1手の速さ」は解決しましたが、それだけでは説明のつかない遅さが残っていました。調べたら、犯人は他にもいました。

犯人2: ダイアログの無言ハング

マクロを実行したとき、その先で MsgBox が出ると、COM の呼び出しはダイアログが閉じられるまで戻ってきません。画面のダイアログに人間が気づいて手で閉じるまで、ツールは無言で固まります。エラーも出ません。ただ沈黙する。

AI との会話でこれが起きると、「なぜか今回だけ異常に時間がかかった」ように見えます。改修セッションが妙に長引く日の正体は、だいたいこれでした。

対策として、マクロ実行系のコマンドに安全解除のガードを既定で常設しました。ダイアログが出たらキャンセル優先で自動的に閉じ、何のダイアログが出たかを本文で報告します。意図して応答したい場合だけ --auto-dialog で明示指定します。

犯人3: ゾンビ Excel と非表示 Excel の残留

COM 作業のあとに、非表示でブック0枚の Excel プロセスが残ることがあります。これが残っていると、次にファイルを開いたときそちらに取り込まれて、アドインが読み込まれていない異常な環境で作業が始まります。「なぜかショートカットが効かない」「メニューが出ない」の温床でした。

MCP サーバー常駐中に非表示 Excel が残留する経路を特定して根治しました。前述のアイドル時の参照解放と合わせて、作業の後始末が自動で付くようになっています。

どの犯人も「壊れてはいないが遅い・おかしい」タイプで、単体では気づきにくいものです。全員まとめて退場させたら、ツールは見違えてきびきびしました。

本題3: 頑丈にした話

速くする作業と並行して、総点検を3回やりました(並列レビュー→本体との裏取り→実ブックでの E2E 検証、という型です)。細かい修正は CHANGELOG に譲って、構造的な穴を2つだけ紹介します。

モジュールが黙って消える事故

モジュールを Remove して同名を Import し直すとき、VBE の Remove は非同期で、まだ完了していないことがあります。その最中に Import すると、同名がまだ居るので 連番の別名(例: shu005 → shu0051)で取り込まれます。そしてツールは成功を報告します。あとで見ると元の名前のモジュールが存在しない。実際にこれで一度、モジュールを消しました。

対策は、Remove 後に消滅を待ち、Import 後に実名を照合し、ズレていたら改名で回復する、回復不能なら非ゼロ終了で正直に落ちる、という手順を Import の全経路に入れたことです。

構文的に不正な名前が黙って通る穴

VBA のプロシージャ名は先頭にアンダースコアを置けません。ところがコード注入に使う AddFromString構文検査をせず成功を報告します。壊れたコードが入ったのに、ツールは「できました」と言う。

これも全注入経路に名前の機械拒否を配線し、さらに「注入経路の台帳テスト」を新設して、経路を一つでも足したらテストが漏れを検出するようにしました(台帳を作った時点で、既に2つ漏れが見つかりました)。

どちらの穴にも共通するのは、下のレイヤーが成功と言っても信用しないことです。操作のあとに結果を実測で照合する。AI に作業させる前提のツールでは、ここを厚くするほど会話が安全になります。

本題4: 検分コマンド ── 前後を見比べる目(できた理由は、やらかしです)

破壊的な操作の前後でブックの状態を突き合わせるためのコマンド群を足しました。

  • snapshot ── ブックの状態(値・結合・書式・図形など)を保存
  • snapshot-diff ── 前後のスナップショットの差分を出す。「直した」の裏取りに使います
  • wiring ── ボタンやショートカットとマクロの配線図を出し、呼び先の存在しない壊れボタンを検出します

「修正しました」を言葉でなく差分で確認する、という運用のための道具です。

きれいにまとめましたが、この目が増えた理由は正直に書きます。やらかしたからです

ひとつめ。削除・リセット系のマクロを「動作確認」のつもりで、実データの入った業務ブックに撃ってしまいました。値は無事でしたが、シート上の図形が壊れました。復旧はバックアップからです。当初の snapshot は値・結合・書式しか見ておらず、図形は視界の外でした。壊してから、図形の目が付きました。破壊系マクロの動作確認は無害なダミーでやる、というルールもこのとき書きました。

ふたつめは、突き合わせが働いた側の話です。別のブックで名前付き範囲の掃除をしたとき、VBA の Names("名前").Delete には罠が2つあります。スコープを付けない文字列指定は健全な同名の定義まで巻き込むこと、そしてコレクションを反復しながら削除すると再インデックスで隣を飛ばすことです。実際に健全な印刷範囲を2件巻き込みました——が、削除前後でバックアップと突き合わせる手順にしていたので、その場で検出して復旧できました。壊さない工夫と同じくらい、壊れたことに気づける工夫が要る、というのが今週の結論です。

本題5: 5分割 ── 使い方を変えずに割る

最後に分割の話です。vba_manager.py は 9,000 行を超えて、開くのも直すのも重い一枚岩になっていました。

役割で5つに割りました。

ファイル 行数 中身
vba_manager.py 844 薄い入口(コマンド表と振り分けだけ)
vbam_core.py 864 接続・共通基盤
vbam_view.py 834 見る系(list / get / read-range …)
vbam_edit.py 1,470 直す系(replace / write-range …)
vbam_vba.py 3,937 VBA 注入・実行系
vbam_heavy.py 1,456 重量級(chart / pivot / powerquery …)

5パート合計で 8,561 行。呼び出し方は一切変わりませんpy vba_manager.py <コマンド> も、Python からの import も、MCP サーバー経由も、従来のままです。

分割の効き目は実行速度ではなく「直す速さ」に出ます。AI に修正を頼むと、対象のパートだけ読んで直してくるようになりました。9,000 行を全部視界に入れてから1行直す、という無駄が消えています。

本題6: もうひとつの後日談 ── 公開前チェックも1コマンドにした

前回、before/after のブックをそのまま GitHub に置いた記事を書きました。その後日談です。

公開したブックのファイルメタデータに、作成者のフルネームがそのまま残っていました。Excel ブックは zip の中に docProps/core.xml という文書情報を持っていて、シートをいくら確認しても、ここは見えません。公開後に気づいて、メタデータを空欄化して push し直し、GitHub 上の生ファイルを取得し直して除去を確認しました。

一度やった確認漏れは、次も必ずやります。人間もAIもです。なので手順ではなく道具にしました。publish_check.py として一式に同梱してあります。

  • 作成者メタデータの実名/隠しシート/コメント/定義名に残るローカルパス/外部リンク/残留入力値、の6項目を1コマンドで検査
  • 実名が残っていれば非ゼロ終了(うっかり公開の前で止まる)
  • --scrub で公開用コピーのメタデータを空欄化

ブックを配布・公開する人なら、このツール単体でも使い道があると思います。

数字(2026-07-12 実測)

項目
コマンド数 72
本体(入口+5パート) 9,405 行
MCP サーバー 195 行
フォーム系4ツール 2,397 行
テスト pytest 67 件
一式合計 12,608 行
MCP 経由の応答 実測 0.01〜0.2 秒級

おわりに

道具は使い込むほど遅くなるものだと、どこかで思い込んでいました。実際は逆で、遅さには必ず犯人がいて、挙げれば速くなります。今回は AI と一緒に犯人を挙げました。

一式は GitHub に置いてあります。導入は ZIP ボタンからで、環境確認は setup-check 1コマンドです。

事件は、解決しました。

2.png

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?