$30 off During Our Annual Pro Sale. View Details »

アルゴリズムの専門家と挑むフロントエンド実装 − 複雑なロジックを支える設計とパフォーマンス最適化

アルゴリズムの専門家と挑むフロントエンド実装 − 複雑なロジックを支える設計とパフォーマンス最適化

Avatar for Akiyoshi Keisuke

Akiyoshi Keisuke

November 26, 2025
Tweet

Other Decks in Technology

Transcript

  1. ⾃⼰紹介 3
 澤浦 司 @plcherrim • フロントエンドエンジニア (React) • 推し

    TypeScript テクは Branded Types • 放置ゲームに⼈⽣を溶かされている 秋吉 圭輔 @udon1206 • アルゴリズムエンジニア • 最近は Rust にお熱 • ゲームは Splatoon が好き
  2. 突然ですが問題です これを解けますか?  には解けません 6
 ある化学⼯場では、N (≈500,000) ⼯程からなる⽣産計画を⽴てている。 各⼯程はちょうど 1 ⽇かかり、複数の⼯程を同⽇に実⾏してもよい。 これらの⼯程には、次の

    2 種類の制約が合計 M (≈500,000) 個 課されている。 • 順序制約:⼯程 A は⼯程 B よりも前の⽇に実⾏する必要がある • 同時制約:⼯程 C と⼯程 D は同じ⽇に実⾏する必要がある すべての制約を満たしながら、全⼯程を完了できるか判定せよ。 可能な場合は、必要となる最⼩の⽇数を求めよ。 可能でない場合は、原因となる制約をすべて列挙せよ。 D A C B …
 …

  3. こたえ アルゴリズムの専⾨家 に お願いします 7
 1. 制約から有向グラフを構成 2. 強連結成分分解して閉路を検出。あれば完了不可なので対象の制約を列挙 3.

    トポロジカルソート + 最⻑路 DP で最⼩⽇数を求める 計算量は O(N+M) で、⼗分⾼速 🤔 いかがでしたか? 

  4. 計画最適化サービスの構成 計算‧最適化ロジックを内包したアルゴリズムを VertexAI で動作 9
 データ永続化 Frontend Cloud Run Backend

    Cloud Run Algorithm Vertex AI Cloud Pub/Sub Database Cloud Firestore Cloud Storage フロントが要求すると バックエンドから起動し 結果を書き込みながら 終了を通知 最適化本体にはそれなりに時間がかかるため、ジョブシステムに分離 この際、インスタンスの起動などにも数⼗秒ほど必要になる
  5. 問題の整理 同じ計算ロジックが 2 箇所に分散してしまった! 12
 フロントエンド
 アルゴリズム
 計算ロジック
 最適化
 計算ロジック


    UI
 フロントエンドの専⾨家なので、正直難しいロジック書きたくない‧‧‧ アルゴリズムの専⾨家なので、正直フロントエンド覚えたくない‧‧‧
  6. 誰がどこで実装するのか 真⾯⽬に向き合うと、多くのつらみと戦うことになる 13
 13
 TypeScript を覚えてもらう? ⼆重実装の保守は⾮現実的 • フロントエンドで動かすもので はあるが、内容は複雑

    • 内部の挙動や実装⽅針などは理 解が難しい部分も...... • インタフェースだけ決めて、中 ⾝の実装をお願いできるといい 実装責任を分離したい • アルゴリズムエンジニアが使う ⾔語はRust / C# • JS / TS の “お作法” 的な部分に は慣れも必要。習熟を必須とは したくない • パフォーマンスも⼤きな問題。 数⼗万要素のデータを⾼速に扱 えるか? ⾔語/環境差 を抑えたい ⼆重実装は避けたい • そもそもフロントで動かしたい ロジックは、最適化アルゴリズ ムの⼀部分 • これって完全に⼆重実装じゃな いですか?? • ⾔うまでもない話だが、保守コ ストが2倍になるので避けたい アルゴリズムエンジニアに任せたい Where Who How
  7. 解決策は複数ありそう‧‧‧ではあるが アルゴリズムエンジニアが、フロントの罠を⾃然に回避し実装可能な構造が⼤事 14
 • テスト駆動にした上で、重い部分を React でメモ化する  → コードが純粋関数に閉じづらく、React の気持ちを理解する必要アリ

    • フロントエンド実装を避け、バックエンドに API を作成し処理を委譲  → 通信のオーバーヘッドが不可避。楽観的な UI 更新をもっと頑張る必要アリ • アルゴリズムの実装を、WebAssembly として呼び出す  → 再実装も不要で、速度もそこそこ出るかも‧‧‧なんだか良さそう! うぃっす ‧‧‧というわけで WASM、お願いします!!
  8. WebAssembly とは WebAssembly (WASM) とは、プログラムを記述するためのポータブルな バイナリフォーマット 17
 • C/C++ や

    Rust などで書いたコードをコンパイルして、 JavaScript/TypeScript など他⾔語と⼀緒に動かせる仕組み → もちろんブラウザ上でも JS/TS から呼び出せる • サンドボックス内で動作し、 OS に直接⼲渉しないので安全 → ブラウザのサンドボックス内でも動作する
  9. Rust × WASM × TS wasm-bindgen などのライブラリを⽤いると Rust のコードから TS

    の型 が ⾃動で⽣成される → WASM のバイナリを使って、TS から型安全に呼び出せる 18
 Rust: lib.rs
 TS: wasm_crate.d.ts

  10. WASM と TypeScript のパフォーマンス ユーザー操作に即座に応答する「インタラクティブさ」を保つには、 WASM を⾼パフォーマンスで動かす必要がある 19
 • ネイティブな

    Rust と⽐べると WASM ランタイム上で動作する Rust は遅い • JS/TS だとそのまま扱えるデータも WASM で扱うにはデータコピーが発⽣す ることがある • JS/TS は V8 をはじめとする JS エンジン上で、スクリプト⾔語とは思えない ほど⾼速に動作するがそれを超えていく必要がある
  11. WASM と TypeScript のパフォーマンス 単純な数値計算では、WASMよりも TypeScript の⽅が速くなることがある 20
 配列の sum

    を求める関数を 50 回実⾏した時の実⾏時間 L\N 10,000 100,000 1,000,000 TS 1.9 ms 6.8 ms 45.5 ms WASM 3.0 ms 6.7 ms 51.5 ms
  12. WASM と SIMD(Single Instruction Multiple Data) SIMD は CPU が

    1 つの命令で複数のデータを同時に処理する 22
 主要なブラウザは WASM の SIMD 対応 している 明⽰的に書かなくても コンパイラが対応して くれることもあるが...
  13. WASM と TypeScript のパフォーマンス SIMD 対応の演算は WASM が⾼速。ただし可読性とのトレードオフあり 配列の sum

    を求める関数を 50 回実⾏した時の実⾏時間 23
 L\N 10,000 100,000 1,000,000 TS 1.9 ms 6.8 ms 45.5 ms WASM 3.0 ms 6.7 ms 51.5 ms WASM (SIMD) 1.1 ms 3.4 ms 28.8 ms 配列の sum を求める関数を 50 回実⾏した時の実⾏時間
  14. WASM と TypeScript のパフォーマンス 複雑な処理は特に⼯夫もなく WASM の⽅が⾼速になりがち 24
 強連結成分分解のアルゴリズム (頂点数

    500,000 辺数 500,000) TS 84.7 ms WASM 41.8 ms 再帰処理や
 入力に対して計算量が多い もの はWASMが高速な傾向がある

  15. TS と WASM のデータのやりとり データのやりとり⾃体はライブラリがやってくれる 27
 serde-wasm-bindgen で Object を直接渡す

    WASM の⽅で型をつければ、 そのまま渡せる ただデータを渡すコストが 無視できない...
  16. TS と WASM のデータのやりとり 28
 化学品⼯場のデータ例 80 施設 × 20

    品⽬ × 300⽇ = 480,000 のネストされた Object 構造のデータ serde-wasm-bindgen で やりとりすると 50 ms ぐらい かかる...
  17. TS と WASM のデータのやりとり WASM 側は線型メモリなので、それにあったデータ構造は渡しやすい 29
 build した際に出てくる js

    のコードをみると malloc でメモリを確保し、 set で⼀括でコピーする 挙動は JS エンジンに依存する が、多くの場合⾮常に⾼速
  18. TS と WASM のデータのやりとり Object の構造を配列にしてから WASM とやりとりする 30
 TS

    側で配列にして WASM と データをやりとりする 今回のケースだと変換込みで 7 ms 程度でやりとりできる
  19. TS と WASM のデータのやりとり 他に紹介できていない⽅法として 31
 • WASM 側でメモリを確保して、フロントエンド側でそれを参照して扱う •

    境界を跨ぐような回数を減らすために、まとめて WASM にデータを送る • 最適化処理で⽂字列として扱う必要のないデータは数値として扱う などなど...
  20. フロントエンドでしか利⽤しないなら、フロントエンドエンジニアが実装する 35
 最適化時には考慮せず、UI 上の表⽰にのみ利⽤するロジックも複数存在 → それはフロントエンドエンジニアが実装する、という整理に • アルゴリズムに無いなら、そもそも⼆重実装ではない  → WASM

    側で実装する利点は速度くらい • そのようなロジックは、多くの場合で UI と密結合なビジネスロジック  → どうしても煩雑な実装になり、React のメカニズムと絡めた⽅が⾃然 というわけで、気合いでフロント側に実装を寄せている箇所もある 最適化で利⽤しないロジックの存在 重実装で得た、当たり前の知⾒を共有します
  21. 36
 難しいロジックを書くための、あたりまえの3箇条 1 単体テストをちゃんと書く 3 計算量やメモ化戦略など、実⾏速度を注視するプロンプトを⽤意する 2 引数を減らした、副作⽤を持たない純粋関数に、意思を持って分割する ロジックの複雑さのせいで、⽬視ではミスに気付けないことが特に多いです ⾔うまでもないことではありますが書きましょう

    今の AI Agent は、最悪計算量の⾒積もりは割かし正確です。頼りましょう 特に、想定されるデータ量の情報を与えておくのは⼤事です 思いもよらないパーツを使い回すことがあります ソフトウェア開発の基本ですが、ちゃんと分割しておくと後々メモ化が楽です