Rustを採用してから4年、良かったこと、苦労したこと
フルカイテン株式会社にてプロダクト開発部の部長を努めている横田と申します。
今回は、RustをGraphQLサーバーとして採用してから4年が経過した中で、運用を通じて感じた「良かったこと」、「苦労したこと」についてご紹介します。これからRustを導入しようと考えている方、あるいはRustに少し触れたことがある方の参考になれば幸いです。
Rustを採用したきっかけ
言語の技術選定は一度決めるとそう簡単には引き返せない、重要な意思決定です。4年前に新システムを構築する際に、バックエンドチーム内で議論を重ねました。当時は、新システムのリリース予定は、技術選定からわずか半年後に設定されており、「慣れた言語を使うべきか、新しい言語を採用するのか」といった議論を行いました。
最終的に、Rustを採用する決め手となった理由は以下の通りです。
静的型付け言語で型チェックの恩恵を受けたい
将来、Webアプリケーションでデータ処理を担うことになっても高速に対応できそう
JVMのような仮想環境を必要とせず、コマンドラインでも気軽に使える
米国の西海岸(DropboxやDiscord)で徐々に採用事例が出てきており、グローバルでも勢いが期待できそう
採用市場が小さい分、ニッチ戦略が有効に働く可能性がある
また、チームメンバーの一人が趣味でRustを使用しており、「書き心地が良く、Webサーバー構築にも問題なく使える」と話をしてくれたことも大きな後押しとなりました。金融システムのような厳密な信頼性が求められる分野であればJavaなど成熟した言語の方が良い場合もあるかもしれません。
しかし、当時のフルカイテンのサービスは、BIツールに近いイメージだったので、Webシステムとしては比較的シンプルな構造でした。そのため、「せっかくなら楽しい言語を選ぼう!」という意見も採用の背景にありました。
Rustを採用して良かった点
1. コード品質の安定化
Rustの厳格な型チェックにより、曖昧な部分が排除されるため、他のメンバーが読んでも不明確な箇所が少なく、シグネチャーを見るだけでも処理の概要が把握できるなどコード全体の可読性が向上していると感じます。
また、運用面でも、コンパイラによる厳密なチェックのおかげで改修における既存機能への影響が一定担保され、心理的安全性を確保出来ている部分が、大胆なリファクタリングを実施しやすくなっています。
実際、モノリスなアーキテクチャからモジュラモノリスへの移行を行った際は、通常であればディレクトリ構成など大胆な変更は、慎重になりがちですが、大きなトラブルなく進めることができました。
さらに、言語のバージョンアップを進める際も、ほぼ問題が発生せず、安定した運用が続けられています。こうしたRustの特性が、コード品質の向上とチーム開発の効率化に大きく貢献しています。
2. 処理が高速
弊社では大量のCSVデータ生成を行う処理があります。こういった処理は、Lambdaを通じたサーバレス環境で実装されていますが、メモリフットプリントが小さく、起動が速いため、高パフォーマンスを発揮しています。その結果、ユーザビリティやシステムの安定性という面でもメリットをもたらしています。
例えば、先日数GiB規模のCSVデータ生成をする要件がありましたが、オンメモリデータの削減を目的として、メンバーのBob(李)がストリーム処理を導入してくれました。このような大規模データの非同期処理は複雑さはあるものの、Rustは安定して実現してくれるので、とても役立っています。
3. コマンドラインが同一環境で作成できる
マイグレーションや保守運用などのコマンドラインツールでもRustを使用しています。こちらのツールでは、タスクランナーのcargo-makeを利用して環境ごとにパラメーター設定できるようにしています。その結果、Rustに慣れていないエンジニアでも操作できるツールを実現しています。
4. エンジニア採用におけるメリット
我々のようなまだ知名度が低いスタートアップにとって、エンジニアの採用は大きな課題です。しかし、Rustを実務で導入していることがきっかけで、Rustに興味を持つエンジニアから声をかけていただく機会が増え、大きな恩恵を受けています。
特にWebエンジニアでありながら、低レイヤーやメモリー管理に詳しい方々からの関心が高い印象です。また、フルカイテンのシステムとしては、大規模データ処理といった技術的なハードルを抱えていていますが、Joinしてくれたメンバーがとても力になりシステムの進化に貢献してくれました。
↓↓メンバーの在籍エントリ↓↓
Rustを採用して苦労した点
1. 言語仕様の難しさ
Rustは、所有権や借用、ライフタイムといった独自の概念を持っているため、学習コストが高い言語です。また、抽象化を行う際のTraitの使い方も静的ディスパッチや動的ディスパッチなど他言語とは異なり、理解のハードルが高いポイントでした。
一方で、標準ライブラリは必要最低限の機能をコンパクトにまとめているため、日時操作のように外部クレート(たとえばchrono)を導入して補うことになります。最初は「標準では用意されていないのか」と戸惑う場合もありましたが、豊富なクレートによって必要な機能を柔軟に選べるのはRustの魅力の一つだと感じています。
弊社のメンバーでも、他社から転職して初めてRustを扱うメンバーも、「慣れるまでは少し時間がかかる」と言います。ただし、最近では、CopilotやCusorなどAIエディタによりコーディングをサポートしてくれるため、習得のハードルが下がった印象です。(弊社でもAIエディタのビジネスライセンスを会社から付与するように支援しています)
2. 情報の少なさ
当時はRustに関する情報が少なく、「どのように書くのが適切か」「やりたいことをどのように実現するのがベストなのか」といった疑問に対して、手探りで試行錯誤せざるを得ませんでした。特に、アーキテクチャ設計において、コンポーネント間の依存関係を管理する際ための再利用性を保つための書き方が難しく「Javaではこう書くけれど、Rustではどう書くべきか」といった具体的な実装例が少なく、模索しながら進める場面が多かったと感じています。
その結果、将来を見越して行ったつもりが、かえって過剰に複雑化してしまったり、マクロを使いすぎてブラックボックスになってしまうケースもありました。これらの課題が原因となり、技術的負債が生まれたことも事実です。
3. ライブラリのバージョンアップ
ライブラリの進化が速く、移行に苦労した経験があります。例えば、4年前は、actix-web 3系を使用しており、非同期ランタイムは、tokioの0.25になっていました。(つまり、メジャーバージョンではなかった。)
その後、actix-web 4系にバージョンアップする際に、tokioがメジャーバージョンに移行し、破壊的変更が発生したため、マイグレーションに大きな労力を要しました。
弊社のメンバーが何度も挑戦しましたが、actix-webやtokioのバージョンアップに伴う依存関係の複雑さから、途中で諦めざるを得ない場面もありました。特に、Webアプリケーションだけでなく、Lambdaなどのコンテナで使用していた非同期ランタイムとの依存関係が影響し、移行作業がさらに難航しました。それでも最終的には時間をかけて、ようやくマイグレーションを完了することができました。
また、AWSへの操作は、当初Rusotoを使用していましたが、開発停止を受けて、AWS SDKに移行しました。こういった破壊的な対応は苦労を要しますが、Rustのコンパイラが影響範囲を特定してくれるので、置き換えやすい印象を受けています。
周辺ライブラリの更新や移行は、ある程度見越しておいた方がよいと思います。
最後に
Rustを導入して4年がたちましたので、改めて「良かったこと」、「苦労したこと」を振り返りました。言語の技術選定において新しい言語を選ぶことはリスクを伴うとされていますが、マイルストーンが短いなかでもRustを選定して良かったと思います。
弊社のWebアプリケーションでは、Rustを活用することで多くの恩恵を受けており、今後のビジネス展開においても大きなメリットをもたらすと考えています。現在、Rustのエコシステムは著しく進化し、情報も充実してきたため、導入がますます容易になっていると思います。
この記事が参考になれば幸いです。
フルカイテンでは一緒に働く仲間を募集中!
↓↓採用情報はこちらから
↓↓フルカイテンが分かる会社紹介動画はこちら