Slide 1

Slide 1 text

満を持して始める Rust 2023/02/09 @kenkoooo 株式会社 estie

Slide 2

Slide 2 text

ようこそ! ● 今日から Rust を始める人

Slide 3

Slide 3 text

自己紹介 ● @kenkoooo ● 株式会社 estie ● ソフトウェアエンジニア

Slide 4

Slide 4 text

@kenkoooo 1. ニート (自宅警備) 2. 国立情報学研究所 (アルゴリズム研究補佐) 3. リクルート (リアルタイム広告配信) 4. SoundHound (車載 AI スピーカー) 5. Indeed (求人検索サービス) 6. estie (商業用不動産 SaaS )

Slide 5

Slide 5 text

@kenkoooo 競プロやってます!

Slide 6

Slide 6 text

@kenkoooo 競プロサイト作ってます! https://kenkoooo.com/atcoder/

Slide 7

Slide 7 text

estie ● estie = 商業用不動産テック ● 新しく不動産業務用サービスを開発中 ● フロントエンド : Next.js ● バックエンド : Rust

Slide 8

Slide 8 text

Rust とは

Slide 9

Slide 9 text

Rust とは? ● Mozilla で開発開始したプログラミング言語 ● コンパイラがメモリ安全性を保証 ● 1.0 リリースから 8 年弱 ● 広く使われるようになってきた

Slide 10

Slide 10 text

Firefox では Rust の初期の使用例のひとつ https://hacks.mozilla.org/2016/07/shipping-rust-in-firefox/

Slide 11

Slide 11 text

Dropbox が同期エンジン Nucleus を Rust で実装 https://dropbox.tech/infrastructure/rewriting-the-heart-of-our-sync-engine

Slide 12

Slide 12 text

AWS のコンテナホスト用 Linux ディストリビューション https://aws.amazon.com/blogs/opensource/announcing-the-general-availability-of-bottlerocket-an- open-source-linux-distribution-purpose-built-to-run-containers/

Slide 13

Slide 13 text

Windows の一部を Rust で実装 https://msrc-blog.microsoft.com/2019/11/07/using-rust-in-windows/

Slide 14

Slide 14 text

Android の一部を Rust で実装 https://security.googleblog.com/2022/12/memory-safe-languages-in-android-13.html

Slide 15

Slide 15 text

Linux カーネル

Slide 16

Slide 16 text

乗るしかない、このビッグウェーブに!

Slide 17

Slide 17 text

Rust を始めよう! Q. でも難しいでしょ? A. 大丈夫!

Slide 18

Slide 18 text

そもそもプログラミングが難しい!

Slide 19

Slide 19 text

そもそもプログラミングが難しい! class Foo: def __init__(self, a): self.a = a def foo(self): self.a.append("Foo") class Bar: def __init__(self, a): self.a = a def bar(self): self.a.append("Bar") a = [] foo = Foo(a) bar = Bar(a) foo.foo() # a = ["Foo"] bar.bar() # a = ["Foo", "Bar"] ● Foo: ○ a を変数にとる ○ a に要素を追加する ● Bar: ○ a を変数にとる ○ a に要素を追加する

Slide 20

Slide 20 text

そもそもプログラミングが難しい! class Foo: def __init__(self, a): self.a = a def foo(self): self.a.append("Foo") class Bar: def __init__(self, a): self.a = a def bar(self): self.a.append("Bar") a = [] foo = Foo(a) bar = Bar(a) foo.foo() # a = ["Foo"] bar.bar() # a = ["Foo", "Bar"] ● Foo: ○ a を変数にとる ○ a に要素を追加する ● Bar: ○ a を変数にとる ○ a に要素を追加する Rust ではコンパイルが通らない

Slide 21

Slide 21 text

そもそもプログラミングが難しい! class Foo: def __init__(self, a): self.a = a def foo(self): self.a.append("Foo") class Bar: def __init__(self, a): self.a = a def bar(self): self.a.append("Bar") a = [] foo = Foo(a) bar = Bar(a) foo.foo() # a = ["Foo"] bar.bar() # a = ["Foo", "Bar"] ● Foo は a を更新する ● Bar も a を更新する → メンバ変数が勝手に更新される

Slide 22

Slide 22 text

そもそもプログラミングが難しい! class Foo: def __init__(self, a): self.a = a def foo(self): self.a.append("Foo") class Bar: def __init__(self, a): self.a = a def bar(self): self.a.append("Bar") a = [] foo = Foo(a) bar = Bar(a) foo.foo() # a = ["Foo"] bar.bar() # a = ["Foo", "Bar"] ● Foo は a を更新する ● Bar も a を更新する → メンバ変数が勝手に更新される Foo も Bar も a も、 どのタイミングで更新されるか、 把握する必要がある。

Slide 23

Slide 23 text

そもそもプログラミングが難しい! こういった状況に陥らないために…… ● 「この変数は書き換えて良い?」を確認する ○ 誰も参照していなければ OK ● 人力で確認するのは大変 ● コンパイラ!何とかしてくれ!

Slide 24

Slide 24 text

コンパイラが強い ● Rust ではコンパイラが何とかしてくれる ● コンパイル時に弾く → 実行時は安心 ● " 所有権 " によって解決 ● 「一生コンパイルが通らない」 ● コンパイラに概念を教えてもらえる

Slide 25

Slide 25 text

所有権 所有権も難しくない(普通に使う分には) ● 自分が持っている変数 ○ 好きにしていい ● 他人から借りている変数 ○ 複数人で参照できる、かつ、誰も書き換えられない ○ 1 人しか参照できない、かつ、書き換えられる → コンパイラが自動でチェックしてくれる

Slide 26

Slide 26 text

Rust は難しい? ● そもそもプログラミングが難しい! ● " 所有権 " によって解決 ● コンパイラが教えてくれる

Slide 27

Slide 27 text

Rust を始めよう! Q. でも OS もブラウザも作らないしなぁ…… A. 普通に便利な機能がたくさん!

Slide 28

Slide 28 text

Rust の便利機能 ● Result ○ エラーハンドリングをシュッとできる ● enum ○ パターンマッチをシュッとできる ● trait ○ ジェネリック関数をシュッとできる

Slide 29

Slide 29 text

Rust の便利機能 ● Result ○ エラーハンドリングをシュッとできる ● enum ○ パターンマッチをシュッとできる ● trait ○ ジェネリック関数をシュッとできる

Slide 30

Slide 30 text

よくある Java いかにも例外を投げそう! String readFile() throws IOException { ...

Slide 31

Slide 31 text

よくある Java 例外を投げなそう……? String readFile() { ...

Slide 32

Slide 32 text

よくある Java 残念!例外を投げます! インターフェースから判断がつかない! - 中身を読むしかない - 最悪、本番で踏むことに…… String readFile() { ... throw new RuntimeException(ioException); }

Slide 33

Slide 33 text

Rust では エラーを返すかもしれない関数は Result を返す エラーを返すかどうか、 インターフェースから判断できる! fn read_file() -> Result { ...

Slide 34

Slide 34 text

よくある Go インターフェースから判断できる func ReadFile() (string, error) { ...

Slide 35

Slide 35 text

よくある Go 型でエラーハンドリング忘れを防ぐ result, err := ReadFile() if err != nil { // ... }

Slide 36

Slide 36 text

よくある Go よくある早期 return result, err := ReadFile() if err != nil { return nil, err }

Slide 37

Slide 37 text

よくある Go これメッチャ書く if err != nil { return nil, err }

Slide 38

Slide 38 text

Rust では Rust では "?" で早期 return できる "?" をつけた Result が Err なら、そのまま return let result = read_file()?;

Slide 39

Slide 39 text

Result まとめ ● 失敗しうる関数は Result を返す ○ エラーハンドリングを見落とさない ● "?" で早期 return できる ○ if err != nil: からの解放 Result 以外にも便利な機能がいっぱい!

Slide 40

Slide 40 text

簡単に始める Rust 〜ライブラリ紹介〜

Slide 41

Slide 41 text

Rust を始める Web フレームワーク "actix-web" 他の言語と同じ感覚で作れる use actix_web::{get, web, Responder}; #[get("/hello/{name}")] async fn greet(name: web::Path) -> impl Responder { format!("Hello {name}!") }

Slide 42

Slide 42 text

Rust を始める フロントエンド "yew" ● ほぼ React ● Wasm に変換される use yew::prelude::*; #[function_component] fn App() -> Html { let counter = use_state(|| 0); let onclick = { let counter = counter.clone(); move |_| { let value = *counter + 1; counter.set(value); } }; html! {
{ "+1" }

{ *counter }

} } fn main() { yew::Renderer::::new().render(); }

Slide 43

Slide 43 text

Rust を始める デスクトップアプリ "tauri" ● Electron のように JavaScript で実装する ● Rust でモジュールも書ける

Slide 44

Slide 44 text

今日から Rust 生活!

Slide 45

Slide 45 text

今から始める Rust 2023/02/09 @kenkoooo 株式会社 estie

Slide 46

Slide 46 text

Rust 導入事例 2023/02/09 @kenkoooo 株式会社 estie

Slide 47

Slide 47 text

estie でのウェブサービス開発事情 ● 商業用不動産市場の課題を解決したい! ● 深く複雑な課題 → 単一プロダクトでは解決しきれない

Slide 48

Slide 48 text

estie でのウェブサービス開発事情 ● どんどん新しいプロダクトを作る ● 共通ライブラリ等そんなにない ○ プロダクトごとに、ユーザーの業態が違う ○ マイクロサービス化 ● 内側の言語は気にならない ○ API 越しに話す

Slide 49

Slide 49 text

estie でのウェブサービス開発事情

Slide 50

Slide 50 text

estie での Rust 選定理由 ● エラー処理・ Null 処理に強い ○ Result / Option で型レベルでチェック ○ 本番 try-catch 忘れ・ NullPointerException 回避 ○ 人間が気をつける必要なし ● コンパイラが厳しい ○ チーム開発でコードの品質を担保 ● 豊富な公式開発支援ツール ○ clippy: Linter ○ rust-analyzer: エディタを Rust IDE 化する

Slide 51

Slide 51 text

すごいぜ clippy clippy の提案で Rust を勉強できる

Slide 52

Slide 52 text

開発者事情

Slide 53

Slide 53 text

estie の Rust 開発者 ● estie で初めて Rust に触るという人が多い ○ 前々から興味があった ○ たまたま配属先が Rust を使ってた ● バックグラウンド様々 ○ JavaScript などフロントエンド ○ Ruby on Rails など動的型付け言語 ○ C++ (競技プログラマ)

Slide 54

Slide 54 text

estie の Rust 入門 ● Rust 研修なし ● ハマるポイントが人それぞれ ● 稼働中のサービス ○ 動かしながら学ぶ ● ペアプロ・モブプロ ● コードレビュー

Slide 55

Slide 55 text

ハマりポイント ● Result / Option ● マクロ ● 非同期処理 ● 文字列操作 ● 所有権

Slide 56

Slide 56 text

Result / Option ● Result ○ 失敗しうる関数を try-catch しない ○ 戻り値が成功 or 失敗の情報を持つ ● Option ○ nullable な値 ○ 型レベルで定義 ○ null check 忘れを防ぐ

Slide 57

Slide 57 text

マクロ ● コンパイル時にコードを生成する #[derive(Clone)] struct A { x: i64, s: String, } struct A { x: i64, s: String, } impl Clone for A { fn clone(&self) -> A { A { x: Clone::clone(&self.x), s: Clone::clone(&self.s), } } } マクロ展開

Slide 58

Slide 58 text

マクロ ● コンパイル時にコードを生成する ● 「いったん理解せずにコピペ」になりがち ○ 必要になったら勉強する

Slide 59

Slide 59 text

Rust に入門してみて ● 「目が慣れたら分かる」 ○ "?" とかは最初は見慣れない ● 「 Result / Option は慣れるまで難しい」 ○ 関数型言語の経験があると違うかも ● 「オブジェクト指向の考え方は通用する」 ○ 「継承」ができないくらい ● 「難しい印象を持っていたが、そうでもない」 ○ 直感的に書ける ○ 色々な書き方があるので、動くものは書ける

Slide 60

Slide 60 text

会社で Rust !

Slide 61

Slide 61 text

ありがとうございました!