MIGRATION DEMO

legacy-orders を TypeScript + Hono に移行した稼働版

AI駆動開発ハンズオン 演習E の題材です。レガシー風の Java コード(551行・9クラス)を移行し、Cloudflare Workers 上で実際に動かしています。このページの「移行後」の出力はすべて、いま この Worker が生成した実物です。

1. 同値性 — 移行前と1バイトも違わないこと

移行で最初に証明すべきは「速くなった」ではなく 「壊れていない」 です。Java版 Main.java と同じシナリオを実行し、出力を突き合わせます。

移行前 — Java 記録した実行結果

created: ORD-00001 total=12803 yen
created: ORD-00002 total=5940 yen
search 'ta' -> 2 orders
==============================
 MONTHLY ORDER REPORT 2026/08
==============================
orders   : 2
canceled : 0
sales    : 18743 yen
------------------------------
[sales by category]
  BOOK : 3800 yen
  DEVICE : 9000 yen
  FOOD : 5400 yen
------------------------------
[orders by customer]
  tamura : 1
  tanaka : 1
==============================

移行後 — TypeScript + Hono ● この場で実行

読み込み中…
照合中…

Java側は Windows の JDK 21 で java com.example.orders.Main を実行して採取した出力です(ブラウザ内で Java は動かせないため記録値)。移行後は右側の GET /api/scenario?at=2026-08-13T06:30:00Z をこのページから呼んで取得しています。同じ判定は npm test でも自動実行されます。

2. 実際に叩いてみる

Java版の OrderService.createOrder() がそのまま HTTP API になっています。税・割引・送料の計算順序は移行前と完全に同じです。

ここにレスポンスが表示されます

バリデーションを試すなら、数量を 99 にして在庫3個の「27インチモニタ」を選ぶと out of stock が返ります(Java版と同じ文言)。

3. 移行で変えた5点

機械的に置き換えられない箇所です。移行はこの判断の集まりであって、文法の変換作業ではありません。

論点移行前(Java)移行後(TS)そう判断した理由
static な共有状態private static Map STOREリクエストごとに newWorkers は分散実行で、どの isolate に載るか保証がない。static を素直に移すと在庫が増減して見える非決定な挙動になる。永続化するなら D1/KV へ外部化する。
時刻の取得new Date() を直接呼ぶ生成時刻を引数で注入Java版はテストから時刻を固定できなかった。注入可能にしたことで「同じ入力なら常に同じ出力」になり、レポートの差分比較ができるようになった。
タイムゾーンCalendar.getInstance()JST(UTC+9) を明示JVM のデフォルトTZ依存だった。Workers は常に UTC なので、そのまま移すと毎月1日の 0:00〜8:59 JST に前月扱いになる時差バグが出る。
Map の反復順序HashMap の keySet()キーを明示的にソートHashMap は反復順序を保証しない=レポートの出力順が「たまたま」だった。ソートして決定的にした(今回のデータでは Java版と同じ並びになる)。
改行コードSystem.out.println常に LF を返すprintln はプラットフォーム依存の改行を出す(Windows なら CRLF)。同じコードなのに OS で出力が変わっていた。HTTP レスポンスとして扱うため LF に統一。

いずれも Java版のコードを読まないと気付けないものです。AIに移行させる場合も、この判断を下してレビューするのは人間の仕事になります。

4. API

エンドポイント説明
GET /api/scenarioMain.java と同じシナリオを実行。?at= で時刻固定
GET /api/products商品マスタ10件(ProductRepository.findAll)
POST /api/orders注文作成(OrderService.createOrder)。エラーは 400
GET /api/health疎通確認