【話し手】
吉川 哲史(YOSHIKAWA Satoshi)
吉川 哲史
フェアリーデバイセズ㈱プロダクト開発部部長/ Twitter @emergent GitHub emergent
URL http://
本コーナーでは技術へのタッチポイントを増やすことを目標に、各分野で活躍されている方をお迎えします。
今回のテーマはRustです。効率的で信頼性が特徴と言われているRustを商業サービスに組み込んだ吉川さんに、Rustの魅力を伝えていただきます。
はじめてのRust
日高:まずはRustとの出会いからうかがえますか。
吉川:現職に就くちょっと前の話になります。転職活動をしているときのコーディング試験対策で勉強し始めていたんです。
日高:採用試験でよくありますね。
吉川:はい。4年前ぐらいだったかな。当時はコーディングから離れていたこともあり、いろいろな言語に触れてみようと思いました。転職先で何の言語を使うかも想像がつかなかったんで。
日高:そこでRustも勉強対象に?
吉川:実はRustを使い始めたのは転職後です。試験対策ではプロジェクト・
日高:プログラミング言語を変えて何度も解くやり方はずいぶんとストイックに感じます。
吉川:それまではC言語やスクリプト言語をかじったぐらいでしたがKotlinやSwift、HaskellとかLisp系など気になったもの、流行っているものをかたっぱしからWebで検索しては実装してとやっていました。Rustもそのひとつです。
日高:コンパイル言語とスクリプト言語での速度差などはよくいわれます。
吉川:ありますね。同じ問題を解くと言語ごとのビルドや実行環境の違いをフラットに評価できました。その中でも、Rustはビルドツールの充実さやコンパイル時のエラーメッセージの親切度合いで、開発しやすさを感じました。
本番環境で使いたい
日高:今でこそ吉川さんはRustの書籍を執筆[1]されていますが、この勉強のあとに本格的な利用が始まったんでしょうか。
吉川:私の場合、早いタイミングで本番利用する機会があった点が良かったですね。前提となるプロダクトの話をしたほうがいいかもしれません。転職活動を通じてフェアリーデバイセズというスタートアップへ入社したのですが、ここでは主に音声AIをベースとしたプロダクトを提供しています。
日高:いわゆる音声認識技術でしょうか。
吉川:音声の文字起こしという意味での音声認識も含みますが、それ以外にも、翻訳や音声合成、音声からの話者識別や感情認識もサービスとして提供しています。また、マイク付きのデバイスも開発しており、集音した音声の前処理も扱っています。現在では、首かけ型のデバイス
日高:工事現場では手が離せなさそうですし、スマートフォンと同じ形よりは、首かけ型のほうがいいのか。
吉川:そうなんですよ。それで、デバイスやサーバでリアルタイムに音声認識を行うためには独特な課題があって、そこに難しいポイントがあります。
日高:サーバとのAPI通信と聞くとREST APIのような問い合わせて結果を受け取るかたちを思い浮かべます。
吉川:会話の音声は時系列の連続的なデータなので、話し終わるまで待ってから音声認識を行うのでは、結果を受け取れるまでに時間がかかってしまいます。なので、話している途中から音声データを送信しながら音声認識を行い、途中の結果も返却しています。ここで非同期処理が大量に発生するため、WebSocketを使って双方向でデータを送受信します。
日高:それは大変そうです。たくさん音声データを受け取ってから音声認識したほうが当然、精度の高い結果だけを返せる。でも、レスポンスが遅いとユーザー体験が良くならない。
吉川:これらを行うクライアントとサーバがもともとC++で実装されていたのですが、改修やメンテナンスをするにも言語仕様を熟知していて、かつ非同期処理にも慣れていないとつらいんですよ。
日高:おぼろげにわかってきました。複雑になるほどメンテナンスが困難となるが、これをRustで改善できるのでは?
社長を説得
吉川:商用サービスなのですぐには置き換えられませんが、クラッシュレートの低下や修正コストの低減は魅力的です。ソフトウェアの品質が高いと商用サービスの評価も上がります。
日高:ドラスティックに書き換えるのが怖いという感覚はよくわかります。
吉川:だからメインのサービスではなくて最初は追加機能を担当するマイクロサービスを対象にRustを使おうと考えました。
日高:ここが最初のチャレンジになった。
吉川:はい。私もRustを本格的に使っていたわけではなかったので、リスクが少なそうなところで試してみたくて。社長を説得して開発を始めました。
日高:説得は大変じゃなかったですか?
吉川:安全性が高く、速度もC++の実装と遜色ないよと。あと今後の品質改善につながる取り組みだと伝えましたね。社長はその時点ではRustのことは知らなかったんですが、社長自身もエンジニアなのでちゃんと話をわかってくれました。
日高:それはよかった。でもC++が使える人からするとC++で書けばいいじゃんとなりそうですよね。
吉川:自分がC++に熟練していない人の代表として、つまずきがちなところに対して、安心してプログラミングができるんですよと。
日高:Rustへの熱意を感じます。実際に導入した結果は満足がいくものでしたか。採用にあたっての注意点などもあれば聞いてみたいです。
Rustの特徴
吉川: 開発してデプロイした結果、非常に安定して運用できていて、作ってよかったなというのが率直な感想です。
日高:特にRust言語ならではのメリットがありましたか。
吉川:開発中はメモリやスレッドの扱いに対して細かくエラーを吐いてくれるので、コンパイルが通った時点である程度の安定動作を期待できるという点がメリットに感じました。良いパフォーマンスでありながら、メモリ周りの問題に悩まされないという体験は新鮮でした。
日高:メモリ周りはよく問題になる部分ですね。
吉川:CやC++での開発時は、不正なメモリアクセスによるセグメンテーションフォルトに必ず遭遇していました。
日高:以前に組込み開発に私も携わっていましたが、実行時エラーは不具合を特定する作業が大変なんですよ。コンパイルが通ったあとの検証が本番というか。
吉川:そうなんですよ。Rustはコンパイル時点でこの不正なメモリアクセスが起きる可能性が取り除かれている点が大きいですね。
日高:それはうれしい。とても強力な言語機能だと感じました。
吉川:変なメモリアクセスやリソース競合が発生するとデバッグが大変ですから。それがない幸せを噛みしめました。
日高:コンパイル時に安全性を担保する工夫があるんでしょうか。
吉川:安全性を担保するしくみで重要なものに所有権、借用、ライフタイムがあります。Rustではひとつの値に対して必ずひとつの変数だけが所有権を持つというルールがあります。その変数でしか値を使えないと不便なので一時的に参照でき、これを借用と呼びます。関数やブロックのスコープを抜けるときに所有権が移行されない場合はメモリが解放されるのですが、この値が生まれてから解放されるまでの期間をライフタイムと呼び、コンパイル時に不整合がないかチェックされます。
日高:ライフタイムをチェックすることは、どういう点がうれしいのでしょうか。
吉川:値が解放されたあとに、その値を保持していた変数への参照が発生してしまうと、不正なメモリアクセスとなってしまいます。参照が存在する期間が、所有権を持つ変数のライフタイムを超えないようにすることで不正なメモリアクセスを防げます。
日高:寿命の長短を見比べて期限外の参照を防ぐわけか。
吉川:ライフタイムは、コンパイラに備わっているボロー
日高:静的に解決するための工夫ですね。ちなみにライフタイムを判断できない場合はどうなりますか。
吉川:コンパイラだけで判断できないケースでは、エラーを吐いてくれます。その場合、コード上でアノテーションとして開発者が明示することで解決できるケースもあります。参照を厳密に管理しているのでメモリ安全性が守られているわけです。Rustではこのように所有権の機構や型システムを組み合わせて、静的に安全性を高めています。慣れるまではコンパイルエラーが大変ですが。
品質を高めるRust
日高:なるほど。でもRustのコンパイラが怒ってくれるなら人に怒られるより気が楽ですね。
吉川:現場でもそう感じました。Rustでマイクロサービスを作るのとC++のメインサーバ側から呼び出す部分を追加する両方を開発しましたが、C++側でのレビュー指摘のほうが品質に影響する部分が多かったんですよ。
日高:C++では設計技法やテクニックとして安全性をカバーしている部分が多いと感じています。
吉川:はい。それまでの自身の経験では、プログラマーのスキルに依存したコードがあって、さらにそれを単体テストや結合テストといったQA
日高:動作が不安定といった課題は時間をかけて原因を探って解決することが多い。
吉川:しかしRustではメモリやスレッド安全性に関わる問題はコンパイルが通ればほとんど解決しているわけです。これはプログラミングが得意だと感じるシーンが少ない私にとってたいへんなメリットでした。
日高:安心感が違いますね。少なくとも安全じゃない使い方をしてもコンパイルが通っちゃう状況とは前提が大きく違う。もちろんC++でもスマートポインタなど安全にメモリを扱う方法があるのは間違いないんですが。
吉川:スタートアップでは限られた生産性をどの方向に集約するかが重要になってきます。実装直後のプロダクトの安定性が高いと、これはもうめちゃくちゃメリットで採用する価値が高いなと。
エコシステムの整備
日高:安定性といえばAndroidでもBluetooth通信スタックをRustで書き換えるという動きがあります。脆弱性の低減やメモリの安全性を高めてバグを予防できると考えているようです。
吉川:通信プロトコルやOSといった低レイヤ向けに良いという意味でRustはシステムプログラミング言語と言われたりもしていましたね。特徴を活かして使われる場所がいろいろと増えています。
日高:Rust言語の開発環境も成熟してきていますか?
吉川:RustにはCargoというビルドシステムがあり、非常に優秀です。パッケージマネージャも兼ねているのですが、パッケージ数は充実しつつあるものの軒並みバージョンが低いんですよね。
日高:どのパッケージも1.
吉川:0.
日高:はい。私はモバイル開発者ですが0.
吉川:安定していても0.
日高:OSS開発者が多いという意味でしょうか。
吉川:Tokioの場合でいうと、AWS
日高:それはすごい。Rustコミュニティにとっても企業のバックアップ、安定的な開発はメリットだと思います。
吉川:エコシステムが回っているとプロダクト開発でも安心して採用できますしね。非同期ランタイムであるTokioが安定してきたことで、それをベースとするミドルウェア、たとえばHTTPサーバフレームワークのActix Webなどの実用もしやすくなってきました。ビジネス上、必要な機能が充実してきたと感じます。
エラーは友達
日高:高速、高信頼性という特徴が活きる用途から Rust の導入が進みそうですね。開発ツールなども十分そろっていると感じていますか?
吉川:RustのビルドシステムCargoがよくできているので、コンパイラからリンタ、フォーマッタがこれひとつでそろえられます。また、rust-analyzerという言語サーバを導入するとコーディング中の型検査や自動補完が効いて、さらにエラー箇所もわかりやすくなるのでいいですね。私はVisual Studio Code上にこの環境を構築して開発しています。
日高:エラーが丁寧だと助かりますよね。初学者ほど迷ってしまうので。
吉川:画面上ですぐアラートを出してくれるし、エラーメッセージには解消方法を書いてくれることも多いです。エラーメッセージの指示にしたがって足りないパーツをカチカチと入れる感覚かな。型やライフタイムのパズルがはまっていくコーディング体験が新鮮で気持ちがいいんです。
日高:環境がそろい始めている今こそ始めるタイミングだと思えてきます。
吉川:ツール類の充実だけでなくRustのオンラインコミュニティ
日高:間違いないですね。Rustの安全性は複雑な事業や基幹システムほど効果を発揮しそうだと感じました。
吉川:所属しているフェアリーデバイセズでもよりRustを活用していきたいと考えていますが、やりたいことに対してまだまだエンジニアが足りない状況です。一緒にやってくれる方を募集しています。
日高:貴重なお話をありがとうございました。