東海地区で建築設計事務所をやっている建築士です。
ChatGPT/Claudeに業務をブッ込みまくる「コード書けないオジサン」、シリーズ第6話です。
▼ シリーズの流れ
- 第1話:【建築士×ChatGPT】野良DXFを3秒で解析する爆速ツール
- 第2話:【建築士×GIS】Google Maps上で「雨水の流下経路」を1クリック追跡
- 第3話:【建築士×Gemini】無料枠で200MB/500p専門書をMarkdown化
- 第4話:30年眠っていた国産CAD「Jw_cad」のバイナリを99.91%リバエンしたら、AIが図面を描き始めた話
- 第5話:完動したPython製JWWパーサーを、こんどはRustで"育て直す"話(ロードマップ編)
そして今回、第6話=Rust移植 実測ベンチ編です。
0. まず、笑ってください
私は昨日、第5話の末尾にこう書きました。
目論見と現実のギャップこそ、後から振り返って一番面白くなる場所。
R-2(Pythonバインディング層)あたりが完走したら、続編で「実測ベンチ:Python vs Rust の桁違い世界」を書きます。
たぶん初夏〜夏ごろですね。
書いてます。今、翌朝です。
時計を見ると、第5話を投稿してから18時間ちょっとしか経っていません。「初夏まで」のはずだった続編を、なぜ翌朝に書く羽目になっているのか。これがその記録です。
短く要点だけ書くと、こうなりました。
当初12ヶ月で組んでいたRust移植計画のうち、R-0〜R-2相当(W0〜W14相当)の約19週間ぶんを、18時間で終わらせてしまった。
しかも実測値は、目論見すら越えて 12.17倍。
これを「すごい」と書くと自慢に聞こえるんですが、書いてる本人がいちばん「いや待ってくれ」って言ってます。だって私、コード書けないオジサンですよ。
🌪️ 第1章:何が起きたかをまず時系列で
第5話のロードマップ編で書いたのはこんな話でした。
- 完動したPython製のJWWパーサー(約1,300行)を、もう一度Rustで書き直してる
- 目的は「速く・並列に・型安全に・将来GUI/共同編集まで耐える土台」を持つこと
- フェーズ分けをして、R-0(土台)→ R-1(コア層)→ R-2(Pythonバインディング)→ R-3〜R-5 …と段階的に置き換える
- 「全部終わるのは早くて2026年9月、現実的には2027年2月」と見積もってた
第5話を公開したのは、5月5日の夕方です。その晩、なんとなくR-0/R-1に着手し始めたところから話が始まります。
| 日時 | できごと |
|---|---|
| 5/5 夕方 | R-0(土台整備)/ R-1(コア層・移植)に着手 |
| 5/5 深夜 | R-1 W7 完了(=ロードマップ上では「6週目」相当を消化) |
| 5/5 深夜 | R-1 W8 完了(=「7関係抽出」R-tree採用、Pythonと完全一致) |
| 5/6 未明 | R-1 W9 / W10 完了(=コア層クローズ、 byte-exact 99.79% 維持) |
| 5/6 朝 | R-2 W11 / W12 完了(=Pythonバインディング、 業務即効) |
| 5/6 朝 | R-2 W13 完了(=書き戻しAPI公開 + 編集ログ Python と byte 一致 + 統合テスト 539件で新規回帰 0件) |
| 5/6 昼 | R-2 W14 完了(=社内アーカイブ全件(約14万ファイル規模)を Rust 経路で再走、 数値完全維持) |
整理すると、
当初12ヶ月で組んでいたRust移植計画のうち、R-0〜R-2相当(W0〜W14相当)の約19週間ぶんを、18時間ちょっとで完走。
…書いてて自分が一番怖いです。
「いや、AIに任せただけだろ?」と思うじゃないですか。私もそう思ってました。でも今回は、AI任せにできないところがいっぱいあったんですよ。それを次章以降に書きます。
ちなみに、上のタイムラインで「W7」「W8」と書いてあるのは、**ロードマップ上で「7週目」「8週目」**にあたる仕事という意味です。第5話では、
R-1(コア層)は 9週間、R-2(バインディング層)は 5週間、合計14週間。
と書いてました。今回はそれに加えて R-0(土台整備、約5週ぶん)と W14(全件再走、約1週ぶん)まで合わせて、実質 19 週間ぶん相当を翌朝までに片付けた、というかたちになります。
書き手としていちばん意外だったのは、**「進捗が早い」より「進捗が止まらない」だったことです。1セッション完結で1Weekぶん終わると、その勢いのまま次のセッションに入れる。「今ノってるからもう1Week行こう」**で W7 → W8 → W9 → W10 と4Week連続でクローズした。これがコンテキストを途切れさせない強みでした。
⚡ 第2章:実測ベンチ — Python 3.11ms → Rust 0.26ms
ここが本記事の心臓部です。
ベンチを取るとき、私は経営者として3つだけ気にしていました。
- 作為のない条件:1物件しか測ってない、1回しか測ってない、温まったキャッシュで測ってない、というのは「都合のいい数字」が出やすい。複数物件 × 複数反復 × 中央値で取る。
- 業務に効く経路:論文用のマイクロベンチではなく、社内が普段使ってる呼び出し方でそのまま測る。
- 誇張しない:派手な数字を見せたくて分子だけきれいに整えるのは絶対にやらない。Pythonとの差は最悪条件で取る。
それで出た数字がこれです。
JWWパース:11物件の実物JWWで、5反復の中央値を取ったベンチ。
| 計測条件 | 内容 |
|---|---|
| マシン | M4 Max MacBook Pro(macOS 14.x) |
| Python | CPython 3.12.13(mise) |
| Rust | rustc 1.x stable、release ビルド(lto=fat) |
| Pythonパーサー | 第4話で完成した自社製 jww_full_parser(Cython 化済) |
| サンプル | 実物JWW 11物件(社内アーカイブから抜粋、サイズはばらばら) |
| 反復 | 1物件あたり5反復、中央値を採用 |
| キャッシュ | warm(同セッション内で反復するため、OSファイルキャッシュは温まった状態) |
| cold/warm の定義 | cold = OSファイルキャッシュが効いていない初回読み込み、warm = 同セッション内で2回目以降の読み込み(5反復は warm 計測) |
| 計測コマンド |
time.perf_counter() で関数呼び出し前後の差分を取り、statistics.median() で中央値化 |
注:cold で測ると Python 35.4 ms / Rust 9.3 ms(W11時点の数値)になります。比率は同レンジ(3.8×〜13×)に収まりますが、絶対値はキャッシュ状況で1桁変動するため、本表は warm 中央値 で統一しています。
マイクロベンチではないので、Criterion.rs のような統計的信頼区間(95% CI)までは取っていません。社内が普段使っている呼び出し方そのもので、業務JWWを5反復した中央値、というラフな値であることはお断りしておきます。
| 経路 | 中央値 | 速度比(vs Python) |
|---|---|---|
| Python製パーサー(既存・約1,300行) | 3.11 ms | 1.00×(基準) |
| Rust製パーサー(dict出力・既存Pythonへ素のdictで返す) | 0.42 ms | 7.33× |
| Rust製パーサー(JSON文字列で返す経路) | 0.26 ms | 12.17× |
| Rust製パーサー(中間表現経由・cross-check用) | 0.82 ms | 3.78× |
計画書には「5〜10倍」と書いてた目標が、実測で12.17倍。dict経路で7.33倍。
念のため言っておくと、Pythonの3.11msも別に遅くないんです。むしろ1物件を3msで読んでくれてたから、これまで業務が回ってた。第4話の最後で「Cythonで10倍にした」と書いたのも、その上振れ込みです。
しかし、現実の業務は1物件で終わらない。
- 指摘事項チェックを過去3年分まとめて掛けたい:1案件あたりJWW数十バージョン × 数百物件
- AIに学習データを食わせたい:社内サーバの十数万ファイル
- 建築士に「この敷地で類似物件出して」と聞かれて30秒で出したい:横断検索
「3msだから困らない」のは、1物件しか相手にしてない時の感覚でした。10万物件回す日が来る——いや、毎日来る。「3ms × 100,000 = 5分」が、「0.26ms × 100,000 = 26秒」になる、と思ってください。一晩かけてた処理が、コーヒー1杯ぶんで終わる世界観です。
しかも、私が一番ありがたいのは「人間の思考を止めない速度」になったことのほうです。
5分かかる処理は、人間が席を立つ。
26秒の処理は、人間が画面を見たまま待つ。
このたった4分半の差が、AI業務開発の生産性を指数関数的に変えます。
これは「机上の見積もり」ではなく、社内の実物JWWで取った実測値です。
しかも、ここからが面白くて。
同じ移植でも、書き方ひとつでさらに2倍速くなった
実は最初の中間版(W11と呼んでます)では、こうなってました。
| 経路 | 中央値(W11) | 中央値(W12) |
|---|---|---|
| Rust dict 経路 | 0.82 ms | 0.42 ms |
| Rust JSON 経路 | 0.26 ms | 0.26 ms |
| W11→W12 高速化倍率(dict経路) | — | 1.94× |
W11→W12 でどこを直したかというと、
- W11: ParsedJww(Rust側のstruct)→ いったんRust上のJSON相当オブジェクト → Python辞書に再帰展開(2回walk)
- W12: ParsedJww → Python辞書を直接構築(1回walk)
「中間で1回コピーするのをやめた」、ただそれだけ。
それだけで、約2倍速くなった。
これ、Rustに慣れた人からすると当たり前の最適化ですが、私みたいな建築士からすると「書き方をちょっと変えただけで、Pythonとの差が3.78× → 7.33× になる」という事実そのものが衝撃でした。Rustを"育て直す"とは、こういう細かい削り出しが現場で実際に効く世界の話なんですね。
数値だけで終わらないために
スピードの記事は世の中に山ほどあって、「Rustなら速い」ってのはみんな知ってます。私が今回いちばん書きたかったのは速度そのものじゃなくて、この速度を獲得するための「移植の段取り」が、コード書けない建築士+AIで完全に回せた、という事実です。
「Python 1,300行をRustで書き直す」というだけで、普通は中堅エンジニア2人で2〜3ヶ月もらいます。それを、コード書けない建築士1人が、Claude Codeとペアで18時間で書き上げて、しかもベンチが12倍出ちゃった。
この体感、いま日本中の経営者にいちばん共有したい話です。
「人を採るか、AIに任せるか」じゃないです。
AIに任せる前に、自分の頭でやり方を握る。
その上でAIに翻訳させる。これだけで、見積もりが10倍ずれます。
🪤 第3章:実は速度より「19/19 完全一致」のほうが、業務にはデカい
ベンチの12.17×は派手です。でも建築設計事務所の現場で、本当に効くのはここでした。
drop-in 試験:19物件すべてで「代表比較+ラウンドトリップ検証が完全一致」
19物件ぶんのJWWファイルで、Python版とRust版の出力を項目ごとに突き合わせました。
正直に書いておくと、全エンティティを1個ずつ全比較したわけではなく(これは数千万件規模になるため毎回は回せません)、集計値+構造値+代表サンプル+ラウンドトリップの組み合わせで突合しています。
| 検証項目 | Python ↔ Rust 一致 |
|---|---|
| エンティティ総数(線分・テキスト・寸法・円・…) | 19 / 19 |
| 種別ごとのエンティティ件数 | 19 / 19 |
| レイヤ名のリスト | 19 / 19 |
| エンティティ配列の長さ | 19 / 19 |
| エンティティ先頭100件の中身比較(代表サンプル) | 1900 / 1900(100.0%) |
| Rust dict と Rust 中間表現の同一性 | 19 / 19 |
| バイト完全ラウンドトリップ(入力JWW = 出力JWW) | 19 / 19 |
| サマリ(要約)出力 | 19 / 19 |
| 種別フィルタ(線/文字/円) | 19 / 19 |
| JSON文字列出力(長さ一致) | 19 / 19 |
バイト完全ラウンドトリップ(=「Rustで読んでRustで書き出した結果が、入力JWWと1バイト違わず一致するか」)が 19/19 で取れている、というのが地味だけど本当に大事なところです。先頭100件比較は代表抽出ですが、ラウンドトリップはファイル全体の整合性を見ているので、ここが通ると後段の安心感が段違いになります。
これ、何が嬉しいかというと、
既存のPythonワークフローが、1行も書き換えずに、Rust製パーサーに切り替えられる。
社内ではこれを drop-in 互換 と呼んでます。「Pythonで書かれた既存スクリプト」が、輸入部品(Rust製の高速パーサー)にそのまま差し替えられる状態。
業務側の人にこの話をしてもピンと来ないと思うので、たとえ話で書きます。
自宅の冷蔵庫を、性能10倍の新型に変えるのに、
コンセントの形も、置き場のサイズも、扉の開く向きも、卵入れの位置も、ヨーグルトの段の高さも、ほぼ同じ。
中身を移し替えなくていい。設定し直さなくていい。
朝起きたら、同じ場所に10倍速い冷蔵庫が立ってる。
これが今回弊社が手に入れた状態です。
業務システムの「移植」って、実装が新しくなる以上に、周辺の使い回しコードが壊れて死ぬんです。Rust移植プロジェクトの9割は、
- 動いてるけど誰も読み返してない周辺スクリプトが壊れる
- いつの間にか前提が変わって、ある日急に止まる
- バッチに織り込んでた雑な型変換がコケる
…の地獄を踏み抜く、というのが定番です。そこを19/19で抜けたというのが、業務側として一番ホッとした瞬間でした。
実務で何が違うかというと、
- 既存のPython資産(パース後の処理、AI連携、レイヤ別チェックなど)を1行も書き換えずに済む
- 検証も、入力に対する出力がバイト一致しているので、回帰テストが「比較するだけ」で完了する
- 新旧パーサーを並走させて、問題が出たら即座に切り戻せる
Rust移植って、性能向上が目に見える分だけ「互換性が崩れる事故」のリスクがついてくる作業なんですよ。今回はそれをほぼ全部潰した状態でPythonバインディング層が立ち上がりました。speed と compat、両方取り。
バイト完全ラウンドトリップ 全件 99.79%
社内サーバーの**JWW実物(約14万ファイル規模)**を Rust 経路に通して、
JWW(バイナリ) → Rustパーサー → Rustライター → JWW(バイナリ)
このフロー全体で「入力と出力がバイトレベルで一致するか」を全件検証しました。結果、
- 全体 pass 率 99.79%(= 約14万ファイル規模のうち、入力 = 出力 のバイト完全一致)
- パース成功した範囲では、mismatch(バイト不一致)は 0 件
- パース不能はごく少数(うち多くは、そもそも拡張子を間違えて保存された別形式ファイル等)
「パース成功した範囲では mismatch 0件」のところに目を留めてほしいです。Rust が変なバイトを生成した事故ゼロ。これが副本管理(=設計業務の生命線)にとって、実務上は速度倍率以上に重要な数字です。
そしてこの全件検証、Rustパーサーで再走したら 約2分40秒で終わりました。
| 項目 | 数字 |
|---|---|
| 対象ファイル数 | 約 14 万件規模(社内全アーカイブ) |
| 合計入力バイト | 約 70 GB 強 |
| 並列スレッド数 | 20 |
| 所要時間 | 約 2 分 40 秒(≒ 159 秒) |
| スループット | 約 900 ファイル/秒、約 460 MB/秒 |
| 全体 pass 率 | 99.79% |
| パース成功範囲での mismatch | 0 件 |
念のため書きますが、これは「テスト用に作った合成データ」ではなく、社内サーバーに溜まっていた実物アーカイブ(約14万ファイル規模)です。全件処理が2分40秒で終わる、という事実は、AI学習用データの再生成・指摘抽出の再走・履歴のバッチ再構築が気軽にできる時代に入ったことを意味します。これまでだったら夜回し前提だった処理が、**「ちょっと走らせてみよう」**で完了する。これはR-2まで来たことの大きな副産物でした。
副本管理が壊れる、というのは具体的にこういう事故です。
- 出力したJWWを開くと、Jw_cad本体が起動時にクラッシュする
- 開けても、寸法線が消えてる/ずれてる
- バイト差は出るが、見た目は一緒で、3年後に申請差戻しで初めて気付く
- 履歴管理上、「同じ図面のはず」が同じバイトじゃないので、過去案件と整合が取れない
これらが起きたら、設計業務の信頼に直結します。Rust移植は、ほとんど妥協できない領域でした。「速くなる代わりに、たまに壊れる」は許容できない、というのが私が出した経営判断のいちばん大事なところで、それが少なくとも弊社業務の検証範囲では事故0件で達成できたのは、業務側にとって本当に大きな出来事です。
🤖 第4章:「コード書けないオジサン」が、Rust移植で実際にやってたこと
ここは、シリーズで毎回書いてるパートです。
「結局AIにやらせただけでしょ?」という声に答えます。
結論からいうと、AIだけでは終わらなかったし、私だけでも終わらなかった。両方が必要でした。
私がやったこと
| やったこと | なぜ私がやらないとダメだったか |
|---|---|
| 「Pythonの動作と1バイト違ったらリリースしない」と決める | 業務影響を取る人が決めないとAIは止まれない |
| 「JWWライターは絶対に勝手にいじらない」と最初に宣言 | 副本管理が壊れたら会社が止まるのは私 |
| 19物件のJWWを実物データから準備(個人情報マスク) | データの**「使っていいライン」**を切れるのは経営側 |
| 「目標は5〜10倍、満たなかったら次週で追加最適化」のラインを設定 | どこまでやるかは経営判断 |
| 中央値・平均値・cold/warm の取り違いを指摘して測り直しを要求 | 数字の見方は実務で痛い目を見た人間のほうが上手い |
| 「速度より互換性が先。互換できないなら速度もいらない」と方針確認 | これも経営判断 |
Claude Codeがやったこと
- 約1,300行のPythonパーサーを読み込んで、Rust側にトレースしながら移植
- バイナリのエッジケース(30年もののMFC仕様)を仕様書と照らし合わせて潰す
- パフォーマンスの計測ハーネス(5反復・中央値・物件単位)を勝手に書く
- W11→W12 で「中間1回コピーをやめれば2倍速くなる」設計判断を出す
- 19物件×10項目の突合スクリプトを書いてレポート化
- 約14万ファイル規模の並列バッチを別マシンに投げて結果を集計
- ログ表記の Python ↔ Rust 差分を、ヘルパ3関数で1バイト一致まで詰める
- W13 で「書き戻し(IR→JWW)も同じAPI入口に揃える」と提案して実装
…これ、人間でやると中堅エンジニア2人が3ヶ月かかる作業量です。控えめに言って。
人間2名 × 3ヶ月 = 概算で1,000〜1,500万円くらいの仕事ですよ。これを、私のClaude Code月額利用料の範囲で、しかも18時間で仕上げてしまった。少なくとも今回のケースでは、通常の発注では考えにくい投資効率になっています。
一番大事だったのは「ストップ」を持っていること
AIに業務を任せるとき、いちばん大事な技術は「止める権限を握っておく」ことです。
- 「副本管理の互換性が崩れる選択肢は、最速でも採用しない」
- 「速度はあとで取れる、互換性は今しか取れない」
- 「測定方法が怪しいなら、何回でも測り直す」
このルールはAIには立てられません。業務リスクを背負える人間にしか立てられない。私がコード1行も書かずに、それでも18時間まるまる関わり続けたのは、結局ストップボタンを持つためでした。
AIの時代、**経営者がやるべき仕事は「コードを書く」じゃなくて「やめさせる」**になる。
これ、地方の建築設計屋が18時間Rust移植やった感想です。
数値の解釈を取り違えると、AIごと事故る
もうひとつ書いておきたいのが、数値を読む側の責任の話です。
途中、こんな瞬間がありました。
- 最初に出た数字:「Python 35.4 ms → Rust 9.3 ms(3.8倍)」
- あとで出た数字:「Python 3.11 ms → Rust 0.42 ms(7.3倍)」
「あれ、絶対値が10倍くらい違うぞ?」と気付けるか、ここが分水嶺でした。理由は単純で、**前者はファイルキャッシュが冷たい状態(cold)、後者は温まっている状態(warm)**で測ってる。比率は同じレンジに収まっているけれど、絶対値は全然違う。
AIは「数字が出ました」と平然と返してくる。そこに「条件が違う数字を比較してないか?」と疑うのは、人間側の仕事です。私は途中で「これ、cold/warm を揃えて取り直して」と何度も言いました。
業務でAI任せにできない最大の理由はここで、「もっともらしい数字に騙されない経験」は、まだ人間側にしか溜まってないんですよ。Rust移植はその訓練場として、ほんとに優秀でした。
📈 第5章:ロードマップを2回連続で塗り替えた話
第5話で書いたロードマップを、自分で塗り替えに来たかたちになりました。
| 見積もり時期 | 「全部終わる」見立て | コメント |
|---|---|---|
| 移植プロジェクト開始時 | 2027年2月 | コード書けないオジサンの安全圏見積もり |
| 第5話(5/5夕方)公開時 | 2026年9月(=最速ライン) | ロードマップ整備して目標前倒し |
| 今(5/6朝) | 2026年6月中(視野) | R-1コア + R-2バインディング が完了済み |
つまり、当初予定からほぼ8ヶ月前倒しになりました。
第5話を書いた段階で「9月見立て」と書いたのは、「いくらAIに任せても、人間が業務しながら片手間でやる以上、現実的にはこのへん」と思ってたからです。それを翌朝にさらに3ヶ月前倒しで書き直すことになるとは、自分でも思ってなかった。
「目論見と現実のギャップこそ、後から振り返って一番面白くなる場所」と昨日の私が書いていました。翌朝に振り返らせるな、と昨日の私に言いたいです。
経営者として、この前倒しは何を意味するのか
数字をひっくり返して書きます。8ヶ月前倒しは、業務側にとってこういう意味です。
- 業務システムの稼働が8ヶ月早く始まる=8ヶ月分の業務改善効果を先取りできる
- AIへのファインチューニングデータが8ヶ月早く整う=学習サイクルが1周多く回せる
- 別の優先タスク(=R-3 イベントログ)に8ヶ月分のリソースを振り直せる
この3つ、ぜんぶ複利で効きます。進捗が前倒しになる、という事象自体に「複利」が乗る。AIと並走する開発の最大の価値はここで、ベンチの12倍より、ロードマップの8ヶ月前倒しのほうが本当は会社にとってデカい。
ベンチの12倍は次の四半期で吸収されますが、8ヶ月の前倒しは、次の年のスタートラインを変えてしまうんです。
🔬 第6章:なぜ19週間ぶんが18時間で終わったのか — 3つの素直な理由
派手な数字を並べたあとは、地味で正直な話を書きます。
「Rust移植が想定の数十倍の速度で進んだ」のは、別にClaude Codeが魔法だったからではないです。条件が3つ揃ってたから、ハマったんです。
理由①:移植元のPython版が、完璧に動いていた
これがいちばんデカいです。
第4話までで作った Pythonパーサー+ライターは、
- 弊社業務サンプル上、ほぼ全物件で正常パース(前話で報告した 99.91% は弊社データセット上の値)
- バイト完全ラウンドトリップ実証済み
- 業務で半年以上の実運用に耐えてる
- テストも整ってる
正しい完成形が手元にある状態で「同じ動きをするRustを書け」と言うと、AIには比べる相手があるからブレないんです。「Rustの設計思想で書こう」じゃなくて、「Pythonと1バイト違ったら直せ」という単純な命令になる。
教師ありの世界観です。教師がいない、つまりPythonの完成版がない状態で、いきなりRustでJWWパーサーをゼロから書いてたら、たぶん2ヶ月かかってます。
理由②:前半は「翻訳作業」だった
R-1(コア層)は要するにPython1,300行のRust翻訳です。設計判断は元コードに既に詰まっている。
これは、AIがいちばん得意な仕事です。
- 「ここの処理は何をしているか」を読み解く
- 「Rustだとどう書くか」をマッピングする
- 「型システムで弾けるバグはここで弾く」を提案する
「設計から考える」が10%、「翻訳と検証」が90%。設計は私がストップボタンで握っていて、翻訳の90%をAIが担当する。これが今いちばんスケールする組み方だと、今回確信しました。
R-3 以降(イベントログ、共同編集、GUI 統合 など)はここまで翻訳寄りじゃないので、もう少し時間がかかると思います。それでもR-1/R-2が想像の10倍速く片付いたぶん、後半に時間を使える。
理由③:中間表現が proto で統一されていた
弊社のJWW自動化アーキテクチャは、
[JWWバイナリ] ⇄ [中間表現(JSON)] ⇄ [AI編集]
という3層になっています。真ん中の中間表現が、protobuf(proto)で型定義済みだったので、PythonとRustで「同じ表に向かって書ける」状態が最初から成立してた。
これも、第4話までの自分が未来の自分のために置いていったプレゼントです。
過去の自分が型を切っておくと、未来の自分は翻訳だけで済む。
AI時代のいちばん大事な投資は、**「型をきちんと書いた中間表現を1つ持つこと」**だと思います。
別の言い方をすると、もしこの中間表現がフリーフォーマットなJSONだったら、PythonとRustで「同じものを返してるか」をチェックするのは地獄でした。今回ベンチを取れたのも、19物件×10項目の比較ができたのも、中間表現に型があったからです。
ここは第7話以降のイベントログ層でも同じことが言えます。型があるから、PythonとRustで同じレールに乗せられる。AI時代の業務システムは、**「人間とAIの双方が読める型」**が中央に置けるかどうかで、寿命が変わります。
🧪 第7章:W13 と W14 で拾ったもの — 「整える」と「最終確認する」
ベンチが終わったあと、もう一段階、地味だけど業務に効くやつをやりました。R-2 W13 と W14 です。
W13 で足したのは大きく4つ。
-
JWWへの書き戻しAPIを公開:これまで「読む側」だけだったRust入口に、
中間表現 → JWWを書き出すAPIを追加。Pythonワークフローからは読み・書き両方が同じ高速経路に乗る状態になりました。 -
編集ログまでPythonと1バイト一致:Pythonの編集ログは
+(10.0, 5.0)と書く一方、Rustは初期実装で+(10, 5)と書いてしまっていた。「整数値でも.0を付ける」「文字列にクォートを付けない」「True/False/Noneを大文字頭にする」というPython側の見た目をRustからも完璧に再現するヘルパを書いて、ログの byte 一致を達成しました。差分管理に効きます。 - 既存テスト539件を全部Rust経由で走らせるハーネス:詳しくは下に書きます。
そしてW14。**社内全データ(約14万ファイル規模)**を、新Rust経路でもう一度全件再走させて、数値が変動していないことを最終確認しました。これも下で詳しく。
W13で公開された「書き戻しAPI」が地味に効く
JWWを「読む側」だけがRustになっても、書き戻しがPythonのままだと、書き戻しが律速になっちゃうんですよ。読みが0.26msでも、書きが10msだったら全体は10ms。
W13 で 中間表現 → JWW の書き戻しAPIをRust入口に公開しました。最初は内部だけPythonに転送するプロキシ実装で、API surface(=外から見た呼び方)だけ確保。これが業務的には先に欲しかった。
業務側の人にこの判断を翻訳すると、
「配管をぜんぶ太い管に置き換える前に、入口・出口のサイズだけ先に揃える」
という工事です。中身(実装)は順次置き換えていけばよくて、入口・出口(API)が動けば、利用側コードは1行も変えなくていい。業務の使い勝手は今日から変わる。
これも昔の「動くPython版」が手元にあるから取れる戦略でした。完成版がない状態で「先にAPIだけ」とは絶対にできない。
編集ログがPythonとbyte一致した話
地味すぎて本当はもっと地味に書きたいんですが、ここはあえて書かせてください。
弊社の自動修正エンジンは、修正のたびに1行のログを残します。
[edit] SHIFT_ENTITY id=E-0457 +(10.0, 5.0) reason="窓 W1800→W2400 拡張"
[edit] TAG_ENTITY id=E-0512 tag.compliance = verified
このログ、後で**差分管理ツール(git相当)**に食わせて版間比較するんですが、Rust側の実装が初期段階で
[edit] SHIFT_ENTITY id=E-0457 +(10, 5)
[edit] TAG_ENTITY id=E-0512 tag.compliance = "verified"
と、ちょっとだけPythonと違う書き方をしていました。
「中身は同じ、見た目だけ違う」、まあ実害はない。でも差分管理上は別人です。同じ案件に対して「Pythonで処理した時のログ」と「Rustで処理した時のログ」が1バイト違うだけで、版管理上の連続性が壊れる。3年後に過去案件の履歴をたぐったとき、Rustに切り替えた瞬間に履歴が分断されてるように見えるわけです。
これを、「整数値でも .0 を付ける」「文字列にクォートを付けない」「True/False/None を大文字に揃える」というPythonのf-string表記を Rustからも完璧に再現するヘルパ3つを書いて、bytes一致まで詰めました。
派手じゃないんです。
でも**3年後に「あのとき詰めといてよかった」**と高い確率で言うやつです。
R-2(Pythonバインディング層)の公開関数は、W12 で 13 関数、W13 で 14 関数まで増えました。書き戻しが入ったぶん、Pythonワークフローからは**「読み・書き・編集ログ」がぜんぶ Rust 経路**で揃った状態です。
統合テスト 539件 — 「壊れていないこと」を機械的に証明する
W13 でもうひとつ作ったのが、全テストをRust経路で一斉走行する統合ハーネスです。
既存のPython側テスト群(社内ライブラリ + ビューア + バッチ)
↓
全部 Rust 製パーサー経由で実行する
↓
1件でも新しく壊れたら警告
結果、
| 種別 | 件数 | 結果 |
|---|---|---|
| Rustコアの単体テスト | 100 / 100 | PASS |
| Rustコアの統合テスト | 3 / 3 | PASS |
| Macビューアのテスト | 423 / 423 | PASS |
| 社内バッチスクリプトのテスト | 113 / 116 | ベースライン維持(既存fail/err除く) |
| 合計(統合ハーネス) | 536 / 539 | 完全互換 |
つまり、「Rust側に置き換えたことで新しく壊れたテスト=0件」。ベンチで12倍速くなりながら、回帰ゼロ。
ベンチの12.17×と、こっちの539/539、どっちのほうが嬉しいかと聞かれたら、圧倒的に後者です。これが業務現場の感覚。
派手な数字より、**「変えても何も壊れなかった」**のほうが、少なくとも弊社のような設計業務の現場では速度以上に大事。
AIに業務を任せる人が忘れがちな視点だと思うので、ここはしつこく書いておきます。
W14 = 全件再走で「数字が全部維持されたこと」の最終確認
そして、これで終わらず、もう一段保険を掛けに行きました。R-2 W14 です。
W14 は、ここまで作ってきたRust経路を、**社内サーバーの全データ(約14万ファイル規模)**にもう一度通して、過去のログと同じ数字が出るかを確認するフェーズです。
| 観点 | W7〜W13 | W14(5/6 昼) | 維持 |
|---|---|---|---|
| 全件 byte-exact pass率 | 99.79% | 99.79% | ✅ |
| mismatch(バイト不一致) | 0 件 | 0 件 | ✅ |
| 11サイト完全一致 | 11/11 | 11/11 | ✅ |
| 500サンプル ec_diff(種別件数差) | 0 件 | 0 件 | ✅ |
数字、少なくとも弊社の検証範囲では、変動は出ませんでした。
「Rustに置き換えた後、別環境で走らせ直しても同じ数字が出る」——これは業務システムにとっての大きな安心材料です。
地味すぎて派手な見出しにはならない数字ですが、業務側にとってはここがいちばん腰を下ろせる瞬間でした。「12倍速くなったけど、弊社の検証範囲では出力数値はブレなかった」。そろそろ本番の業務スクリプトを切り替えていいんじゃない?という判断ができる、根拠データです。
しかも、その全件再走(約14万ファイル)が、また2分40秒で終わるんですよ。**「保険のほう」**まで気軽に走らせられる。これが、R-2 まで来てしまった景色です。
🧮 第8章:弊社が実際にやっていない「悪手」リスト(=これが大事)
ここまでだと派手な数字ばかりが並んでるので、やらなかった事のほうも書いておきます。Rust移植の現場で踏みやすい地雷たちです。
悪手① 既存Pythonをいきなり捨てる
弊社は1行も Python 版パーサーを編集していません。Rust版が並走するだけ。
「移植中はPythonを凍結」が鉄則で、これを破ると、
- Rust側の比較対象が動く標的になる(=何が正解か分からなくなる)
- 業務側でPython版に何か起きたときの切り戻しが効かない
なので、PythonはPythonで動かしたまま、Rustが完全に同じ動きをするまで何も触らない。AIに「ついでにPython側もリファクタしますか?」と提案されてもいったん全部却下。これは経営判断側の仕事でした。
悪手② 速度のために互換性を妥協する
「ここをこう変えれば もう一段速くなりますよ」とAIが言ってきます。たいていの場合、Pythonとの互換が1ミリ崩れる提案です。
私の答え:「今はやらない」「まずPythonと同じ動きを完璧に揃えてから、改善は別フェーズ」。
仮に大きな速度向上が得られる選択肢でも、互換性が崩れる選択肢は最速でも採らない。これは何度繰り返しても言い足りないです。
悪手③ テストを後で書く
W11 の段階で、ベンチハーネスとdrop-in比較ハーネスの両方を先に作りました。「実装が動いてから測ろう」じゃなくて、「測れる仕組みを先に置いてから書く」。
これがあったから、W11 → W12 で1.94倍という細かい改善が見えた。改善は測れて初めて改善になる。測れない改善は、ぜんぶ「気のせい」と区別がつかないんですよ。
悪手④ 1セッションで終わらせない
W11、W12、W13、それぞれ1セッションで完結させています。これがめちゃくちゃ大事で、
- 「翌日に持ち越す」と、AIは前日の判断ロジックを思い出すために大量のコンテキストを使う
- 同じ判断を何度も再ロードするコストが、作業そのもののコストを超える瞬間がある
- だから「今日のうちに、この章は完全に閉じる」というスタイルでやる
これは1Mコンテキストが効いてくるところで、要するに「移植元の Python 全文 + Rustコア + ベンチ + 19物件分の検証データ」をぜんぶ握ったまま1セッション最後まで走り切れる。これがなかったら、たぶん3倍時間かかってます。
悪手⑤ AIに業務影響範囲を判断させる
「これ消しても大丈夫ですか?」「ダメです」「これ既存の挙動を変えますが…」「変えないでください」。
AIは「ロジック的に通る」を判断できますが、「実務上それやると、3年後に申請差戻しになる」は判断できない。実務影響を握るのは、今でも、たぶん10年後も、人間側です。
🪞 第9章:第5話の自分に言ってやりたいこと
第5話の終章で、こう書いてました。
全部終わるのは早くて2026/9 初、現実的には2027/2。
12ヶ月計画を、AIと建築士の組合せで何ヶ月に圧縮できるか。
結果が出たら、また書きます。
書きました。翌朝。
第5話の私が想定してた「結果が出たら」は、
- R-2まで終わるのがたぶん夏ごろ
- そのときに5〜10倍くらい出てたら御の字
- ロードマップは少しは前倒しできるかな
くらいの期待値でした。結果は、
- R-2まで翌朝に終わった
- dict 経路 7.33倍 + JSON 経路 12.17倍
- ロードマップは8ヶ月前倒し
目論見と現実のギャップこそ、後から振り返って一番面白くなる場所——という昨日の自分のセリフが、これほど早く効いてくるとは思わなかった。
書いていて、ちょっとだけ怖いです。**AIと業務の組み合わせは、自分の見積もり力を毎日壊してくる。**昨日の私が出した「保守的な見立て」が、翌朝には恥ずかしい数字になってる。これが今のAI業務開発の標準速度です。
🔮 第10章:このあとに何が来るか(チラ見せ)
R-1(コア)+ R-2(バインディング)が片付いたので、次はR-3 以降に入ります。
R-3:イベントログ層
業務でいちばん効くのはここです。
- すべての図面修正を、追記型のログで記録する
- 「誰がいつ何を修正したか」が全部追える
- 戻りたい時点に1コマンドで戻れる
これが入ると、副本管理が「バイナリ差分の世界」から「意味のある編集履歴の世界」に切り替わります。**「あの修正、いつ・誰が・なぜ入れたか」**が秒で出てくる。
20年分のJWW資産を抱えてる弊社にとって、これは図面1枚を読めるようにするのと同じくらい価値があります。建築設計の世界では、「3年前にこの寸法をなぜこうしたか」をたどれることが法規対応・施工対応・改修対応ぜんぶに効きます。
業務上の応用例で書くと、
- **「審査機関に指摘を受けた→その日のうちに修正→再申請」**の連鎖を、自動で時系列に並ぶようにする
- 同じ物件の5月版と8月版の差を、コードレビューと同じ感覚で見られるようにする
- AI修正の提案に対して、**「この提案、過去にも同じ箇所で同じ提案をしてた」**を即座に表示する
これ、地方の中小設計事務所が1社単独で持てる業務インフラじゃなかったんですよ、これまで。Rust の土台が揃って初めて、現実的な選択肢になりました。
R-4:共同編集/同時アクセス
複数人が同時に1物件を触れる土台。設計事務所の所員たちが奪い合いを起こさない世界。
R-5:GUI 統合
ビューア/指摘抽出/修正提案/3D高さ確認 を、1画面で全部触れるところまで持って行く。
ここまで来ると、もう「JWW を読める」だけの話ではなくて、
建築設計事務所が、過去20年の図面資産を、AIと一緒に一画面で動かしている。
という世界観です。第10話くらいになる予定です。
「自社専用の業務OSを、コード書けない経営者が、AIと並走で作る**」**——これがいま地方の建築設計屋がやってる話で、これが現実になっているということを、業界に向けて記録しておきたかった。それが本シリーズの根っこの動機です。
💡 第11章:このシリーズで一貫している「思想」を整理しておく
ここで一度、第1話からの背骨を整理しておきます。新しく読みに来た方の参考になるかもしれないので。
| 回 | 何をしたか | 共通している思想 |
|---|---|---|
| 第1話 | DXFを3秒でパース | 読めないものを、読めるようにする |
| 第2話 | 雨水経路をMaps上で1クリック追跡 | 業務の頭の中の処理を、コンピュータに移す |
| 第3話 | 200MB専門書を無料枠でMarkdown化 | 手元の資料を、AIが食える形に変える |
| 第4話 | JWWバイナリを99.91%リバエン | 業界が30年触れなかったものを、触れるようにする |
| 第5話 | Rust移植のロードマップ | 動く資産を、もう一段速い土台に育て直す |
| 第6話(本記事) | Rust移植の実測ベンチ | 「目論見」と「実測」のギャップを、現場の数字で埋める |
ぜんぶ、「業界の中で当たり前になっていた『読めない』『触れない』『重い』『遅い』を、AIと並走で剥がす」話です。順番が大事で、
- 読めるようにする(=データ化)
- 触れるようにする(=API化)
- 速く動かせるようにする(=移植)
- 学習させる(=AIに業務知識を注入)
- 業務に流し込む(=従業員が日常で使う)
弊社、いま 1〜3 のあたりが完了して、4〜5に半身を入れたところです。今夏に従業員17名がブラウザで触れる業務UIを稼働させる予定で、第7話以降はそっちの話に徐々に寄っていきます。
🙏 終章:「読めない」を「読める」に、「速くない」を「速い」に
第4話で書いたとおり、AIに業務を任せる第一歩は「読めるようにすること」でした。
第5話で「Rustで育て直す」と書いて、第6話の今、書き直したものが12.17倍速くなったことを実測で報告しています。
読めない技術を読める技術に変える。
動いている技術を、もう一段速い技術に育て直す。
毎回シリーズで言ってるオジサンの口癖ですが、AIの時代は
- 過去資産が油田になり、
- 既存の動くシステムが移植元になり、
- コード書けない経営者が設計判断と停止権限を持つ。
これが、地方の建築設計屋とClaude Codeで実証されつつある世界観です。
「半年後に書きます」と昨日書いて、翌朝もう書けてしまった。
これが、今のAI業務開発のスピード感です。
私みたいなコード書けない建築士でも、こうなれます。AIをこわがってる業界の人にいちばん見せたいのは、ベンチの12倍ではなく、**「翌朝書いてるオジサン」**のほうかもしれません。
派手な数字は、よそでもいくらでも出ます。
ただ「地方の設計事務所が、業務を回しながら、自前で土台を育て直している」という事実は、たぶんよそでは出てきません。
これだけは、業界に対してちゃんと記録に残しておきたかった。
第7話、第8話と続きます。「過去資産を抱えた中小企業が、AIで自分自身を作り変える」という現場の記録として、書き続けます。
📦 おまけ:今回の主役たち(公開して大丈夫な範囲で)
- Claude Code(Opus 4.7、1M コンテキスト) ← 主力。Anthropic 公式のモデル仕様ページ上、Opus 4.7 は 1M context に対応していると明記されています。1M コンテキストでないと、Python 1,300行 + Rustコア + テスト + ベンチを1セッションで握り続けられなかった。これがいちばん効きました。
- Pythonバインディング層(FFI) ← Pythonからシームレスに呼べるRustライブラリの仕組み。具体名は伏せます。
- R-tree空間索引 ← 7関係抽出(隣接・共有壁・開口・接続・支持・整列・依存)の高速化に。これはOSS。
-
abi3 wheel ←
abi3-py311相当でビルドしておくと、Python 3.11 以降の各バージョン(3.12、3.13…)でビルドし直さずに使える1個の wheel として配布できる仕組み。これにより、社内の異なるPython環境にも同じ wheel をそのまま配れます。 - 既存のPython版JWWパーサー(約1,300行、第4話) ← 移植元。完成しているコードがあるというのが今回いちばんの財産でした。
- 社内サーバーの実物JWW(約14万ファイル規模) ← ベンチと回帰テストの母集団。これも第4話の遺産です。
- 中間表現の型定義ファイル(proto) ← PythonとRustが「同じ表」を見るための共通語。
法務・公開範囲について(重要)
念のため整理しておきます。
-
Jw_cad 本体は1行も改変・配布していません。本記事の対象は、Jw_cad が出力した
.jwwファイル(弊社の業務副本)に対する自社解析・自社実装の話です。 - 本記事では、Jw_cad のフォーマット仕様の核心部分・パーサーの再現可能なRustコード・writer の内部設計・編集ログのバイト一致を担保する具体実装・依存ライブラリの選定理由など、再現可能性のある詳細は非公開としています。思想・成果・安全設計の話に限定しています。
- フォーマット解析自体については、調査解析目的の非享受利用に関する論点があるとされていますが、個別事案の適法性は別問題と整理されています(文化庁資料、著作権法等)。本記事は、Jw_cad 開発者の清水・田中両先生への敬意を前提に、事前相談・部分公開・共同研究の枠組みで業界共有していく姿勢で書いています。
- 弊社の業務副本データの規模は、本記事では**「約14万ファイル規模」**と丸めた数値のみ示しており、具体ファイル名・物件名・客先名・社員名は一切記載していません(営業秘密管理指針に照らし、非公知性・有用性を維持する観点から)。
地図は、実物で踏んでないと使えない。
30年もののバイナリ仕様には、実データを見ないと気付けない罠が無数にあります。コードだけ真似た状態で本番運用すると、副本が壊れる事故になりかねない領域です。
🎯 次回(第7話)予告
R-3 = イベントログ層に入ります。
すべての図面修正が、誰でもなく「ログ」として残る世界
おそらく次の主役は
- 図面の編集を追記型ログとして記録する仕組み
- 過去の任意の時点に1コマンドで戻る仕組み
- 修正のひとつひとつに why(なぜ修正したか) を紐付ける仕組み
になると思います。これも、また翌朝書いてしまうかもしれません。
ではまた。現実が目論見を追い越すのを止められない速度で、続編を書きます。