形状認識処理のディレクターを務めている寺田です。昨年10月よりDTダイナミクス(ミスミグループ出資の戦略的IT子会社)のお世話になっています。
私が入社した時点では meviy の形状認識はすべて C++ で書かれていましたが、そこに Rust を導入したというお話です。
Rust で何作ったの?
ゴチャゴチャと御託を並べる前に、まずは Rust で何を作ったのかを簡単に紹介しましょう。 大きく分けて下記の3領域に Rust を導入しました。
- 溶接リモデル機能
- 平板展開機能
- 自動テストツール
ここでは先頭の「溶接リモデル」について簡単に紹介します。 この機能の内部実装を C++ から Rust に置き換えて、またロジックも大きく変更することによって、溜まっていた不具合を大幅に解消しました。
溶接リモデルとは
上図の左がリモデル前、右がリモデル後です。
板金製品は、平らな板金材を折り曲げて製作しますので、平面に展開可能な形状となっている必要があります。しかし左の形状は切れ目が入っておらず、平面に展開できない形状です。 また、板金の曲げ部に相当する円筒面もモデリングされておらず、すべての折り目が直角のピン角になっています。
一方、右のリモデル後の形状は、展開可能なように適切に切れ目が入り、曲げ加工の箇所は円筒形状に修正されています。 meviy はお客様がアップロードした左のような形状データを自動的に右のような製造可能な形状に「リモデル」し、切れ目を入れた箇所には自動で溶接指示が入ります。
設計の段階で平板展開まで考慮した形状(図の右側)をモデリングするのは骨が折れますので、左のような形状モデルをアップロードするユーザーも多いのです。「加工に必要な細かな調整は加工会社側でよしなにやって欲しい」というのが市場のニーズです。従来はこの作業を人が図面を読み取って行っていたのですが、これを meviy は自動で処理します。
どんな問題があったか
下図はリモデルの失敗例です。
キャプチャ画像だけではどういう形状になっているのか分かりづらいかとは思いますが、不自然でおかしな形状が生じていることは見て取れるのではないでしょうか。 このデータのように、面と面が90度ではない角度で接続しているような形状において、リモデルが不正な形状を生成してしまうことがありました。
どう Rust を導入したか
C++ で書かれていた既存ロジックをそのまま Rust に移植、ということは一切やっていません。
既存の溶接リモデルの実装は、根本的なアルゴリズム設計の部分でやや筋が悪いように私には感じられましたし、メンバーからも同様の意見が挙がりました。 多くの不具合が根底の設計に起因しているように思えたのです。 具体的に何をどう変えたのかはお伝えできませんが、「こういう設計思想でやり直せば、挙がっている不具合を一気に解消できるのではないか」という提案をし、チームや事業の賛同を得ることができました。
根底から設計を覆す提案だったので、C++ の既存実装はかなりの部分が捨てられることになり、大幅に書き換える必要がありました。 その新たな書き直しを、Rust で行ったということになります。
いわば、言語の切り替えと機能の改良を同時に行ったわけですが、これが良かったと思います。 機能を変えずに言語の移植だけするほうが簡単に思えるかもしれませんが、機能に退行がないことを確認するリグレッションテストの手間は、移植だろうが機能改良だろうが変わりません。 そのくせ、移植だけの場合は機能性には進展がないわけなので、事業の視点では進捗ゼロと評価されてしまい、理解を得られにくくなってしまいます。 事業の理解を得ながら技術的負債を返済するためには、同時に機能の進展を伴うように計画するのが望ましいと考えています。
以上の大改修が奏功して、上の図で示した不具合はもちろん解消しましたし、KPIとして計測している自動見積もりの成功率にも向上が見られました。
それにしてもリグレッションテスト(と見つかった不具合の修正)は大変でした…(遠い目)。 開発と事業の共同作業による全員野球(おじさん用語)でしたね。ご尽力いただいた開発メンバーおよび関係者の皆さんに深く感謝いたします。
なぜ言語を変えるのか
ポール・グレアムの「普通の奴らの上を行け(Beating the Averages)」というエッセイが好きです。 ポール・グレアムは Lisp というプログラミング言語で Web アプリを開発し、成功を収めました。 他の競争相手を出し抜いた秘訣は、Lisp にあると彼は述べています。 20年以上も前に書かれたエッセイですが、私の中では少しも色褪せていません。 今回 meviy に Rust を導入するに当たっても、心の中のポール・グレアムが背中を押してくれました。
このエッセイは次のように断言します。
まず、思いっきり物議を醸しそうな発言から始めよう。 プログラミング言語は、その力において差がある。
私も、C++ と Rust では、その力において差があると思っています。
続けて彼は、次のように主張します。
- 自分が慣れ親しんだ言語より非力な言語を「見下ろす」ときには、力の差を認識できる。
- 逆に自分が習得していない言語を「見上げる」ときには、力の差を認識できない。
私たち日本人は日本語で思考します。つまり、思考というのは母語の制約を受けます。 プログラミング言語もそうです。 単に機械語を吐き出すための呪文ではなく、思考の道具であり、思考を規定します。
(私も含め)おそらく多くの日本人は、中高生のときに英語の完了形に苦しめられたことでしょう。 逆に英語話者が日本語を学ぶと、「完了形がないなんて…一体あのニュアンスを日本語ではどう表現するの?」と戸惑うのかもしれません。 同様に私たち日本人は、英語の一人称が I しか無いことに大いに戸惑うわけです。
つまり私たちは、母語に備わっている概念が外国語に欠落しているときにはその差を認識できますが、逆に母語にない概念が外国語に登場すると「なんだこれ」「わけわからん」「何の意味があるんだ」という反応になりがちです。 それと同じことがプログラミング言語でも起こるのだと、ポール・グレアムは言っています。
私は C++ も Rust も知っていますので、その力量の違いが分かるつもりです。 更には、Rust を含め別の言語を通じて習得した概念は、C++ でコードを書くときにも活かせることがあると感じます。 ですから、開発チームに Rust を導入することは、メンバーのスキルを一段上のステージに引き上げることにつながると信じています。
もちろん新言語の習得は新概念の習得ですから、学習コストは掛かるでしょう。 しかしそれは一時的な出費です。 一方、スキル向上は複利で効いてきますし、逆にC++だけを使い続けるとそれによる負債も複利で積み上がってしまいます。 それを考えれば、学習コストは必ず回収できると私は確信しています。
さてここで、このエッセイの原題は Beating the Averages であることを強調したうえで、一節を引用します。
もしあなたが平均的なベンチャー企業と同じことをやっていれば、 平均的な成長率が期待できる。問題は、だ。ベンチャー企業の平均的な成長とは、 すなわち、潰れてしまうということだ。ベンチャー企業の生存率は50%よりはるかに 小さい。したがって、ベンチャーをやるなら何か変わったことをしなければならない。
meviy やDTダイナミクスはまだまだ発展途上の事業フェーズです。 グローバルにサービス展開する上では強力なライバルが世界にひしめいています。 meviy という事業が潰れる可能性はないとは言えません。 そういう危機感を持って、「平均的なやり方」が持つ引力に対抗しなくてはなりません。 CAD/CAM業界においては C++ が未だ「平均的なやり方」でしょう。その引力に抗いたいのです。
なぜ Rust なのか
一般論としての Rust の良さについては、ネットに幾らでも情報がありますので敢えてここでは触れません。 本記事では、Rustと meviy、とりわけ「3DCAD形状処理」というドメインの相性を考えてみたいと思います。
大前提: C++ は捨てられない
まず前提として、C++をゼロにすることはほぼ不可能です。何故なら、3DCADデータを扱うには3DCADカーネルの利用がほぼ必須であり、これはC/C++によるアクセスが基本となるからです。従って何らかの形でC++は併用せざるを得ず、これはRust導入の足かせの一つとなり得ます。
しかし以上を差し引いても、Rustの言語設計やツールチェインは十分魅力的です。それに加えて、形状処理はRustと相性が良いと考えており、その理由は下記のとおりです。
理由1: CPUバウンドなパフォーマンスが求められる
形状処理は外部との頻繁なI/O処理がないので、パフォーマンスは完全にCPUバウンドです。RustはC++と同等の速度性能を発揮できる言語であり、CPUバウンドなパフォーマンスを追求するには最適な言語(のひとつ)です。 meviy の形状処理の中には計算時間を要するものもありますので、高いパフォーマンスが出せることは非常に重要な要件です。
理由2: エコシステムの縛りが少ない
言語選定でよく問題となるのは、エコシステムです。
DBやクラウド等と連携する用途では、そのためのエコシステムが充実しているかどうかも技術選定の重要なファクターとなるでしょう。 また機械学習のように、Pythonがデファクトスタンダードとしてエコシステムが整っている領域もあります。 必ずしも言語の良さだけで選定できるとは限りません。
形状処理の分野でエコシステムがあるとしたら、それはC++で組み上げられています。 上述したように、3DCADカーネルはC/C++のAPIを提供していることが多いですし、この分野の商用ライブラリもC/C++のAPIが多いです。
しかし meviy には、こういった C/C++ のエコシステムとは切り離すことが出来るアルゴリズムもかなりのボリュームが書かれています。 カーネルを必要とするモジュールさえうまく分離できれば、あとは純粋なRustで実装できます。カーネルに依存するモジュールをFFI (Foreign Function Interface) で分離するのはちょっと骨が折れますが、そもそも特定カーネルに強く依存する設計は望ましくありませんから、依存を一部のモジュールに局所化することは良い設計にも繋がっていくはずです。
理由3: 大量のヒューリスティックなアルゴリズム
meviy で必要な形状処理は、単一の美しい理論ですべてを解決できるようなものではなく、多くのヒューリスティックなアルゴリズムをコツコツと積み上げていく必要があります。 こういった開発は属人化しやすく、またコードもスパゲッティになりやすいものです。
これにはRustの次のような特性が大変効果的です。
他人が書いた C++ のコードを触るのは、大変怖いものです。 C++ は安全性が低く、コンパイルが通っているだけでは全く安心出来ないからです。 また、コードのフォーマットや命名規則にも無用な個性が現れやすく、地味にストレスが掛かります。
このあたりが Rust では大幅に改善されています。 テストを記述する習慣さえチームに根付けば、他人のコードでもかなり安心して触ることが出来るでしょう。
理由4: meviyはPMFしている
PMF (Product Market Fit) の明確な基準に私は疎いので間違っていたら申し訳ありませんが、meviy は顧客とファンを獲得しており、売上も着実に伸びているので、市場に受け入れられていると言って良いはずです。 つまり、「そもそもこのコンセプトのサービスに市場はあるのだろうか」というレベルの仮説検証は既にクリアしています。
PMF 前のフェーズであれば、システムの堅牢さにこだわるよりも、なりふり構わず矢継ぎ早に機能を投入して市場の反応を見ることが重要ですし、時には大胆なピボットも必要になります。 その場合には開発者の学習コストを払う余裕はないかもしれず、だとするとRustは最適な選択肢ではないかもしれません。
しかし meviy はこのフェーズを脱しており、次なる不確実性は「この方向性で自動見積もりの精度向上と範囲拡大をどこまで伸ばしていけるのか」という技術的な課題になっています。 それは同時に、PMFまでに積み上げた技術的負債をどう返済していくか、という戦いでもあります。 Rust がそのための武器になるはずです。
さいごに
CAD/CAM 業界というのは、若いITエンジニアから見るとレガシーな印象があるかもしれません。 ともすると、製造業は「完成した」業界で、もうドラスティックな変革は起きない領域と思っている方もいるでしょうか。
しかしこの業界はまだまだ変革の余地が残っており、挑戦していく価値のある領域だと私は思っています。 そのためにはこの業界が若いITエンジニアにとって魅力的に映ることが必要ですし、そのためにも Rust に限らず新しい技術を取り入れていく努力を怠らないようにしたいところです。
製造業やCAD/CAMを知らなくても構いません。Rust が書けなくても構いません。 若くてもベテランでも構いません。 meviy の挑戦を面白いと思って頂ける方、一緒にやってみませんか?