Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Cargo Workspaces のススメ
Search
nawa
July 16, 2024
Programming
1.1k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Cargo Workspaces のススメ
https://uniquevision.connpass.com/event/323686/
の発表スライドです。
nawa
July 16, 2024
More Decks by nawa
See All by nawa
大規模プロダクトのための Cargo Workspaces ベストプラクティス
mnawa
0
340
Rust で型安全な SPA 開発
mnawa
0
860
Other Decks in Programming
See All in Programming
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
190
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
560
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.5k
Why Laravel apps break—Mastering the fundamentals to keep them maintainable
kentaroutakeda
1
340
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
110
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
1.6k
GitHub Copilot CLIのいいところ
htkym
2
1.3k
3Dシーンの圧縮
fadis
1
650
TypeSpec で繋ぐ複数プロダクトの型安全
maroon8021
1
400
決定論的オーケストレーションの設計と実装 / Design and Implementation of Deterministic Orchestration
nrslib
3
1.1k
さぁV100、メモリをお食べ・・・
nilpe
0
130
Composerを使ったサプライチェーン攻撃の様子を眺めてみる #phpstudy
o0h
PRO
2
220
Featured
See All Featured
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
71
40k
The Limits of Empathy - UXLibs8
cassininazir
1
350
How GitHub (no longer) Works
holman
316
150k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
300
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
GraphQLとの向き合い方2022年版
quramy
50
15k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
160
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
220
Principles of Awesome APIs and How to Build Them.
keavy
128
17k
Visualization
eitanlees
152
17k
KATA
mclloyd
PRO
35
15k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
860
Transcript
Cargo Workspaces のススメ UV Study : Rust LT会 2024-07-17 Fairy
Devices株式会社 nawa ※ https://speakerdeck.com/mnawa/cargo-workspaces-nosusume
Cargo Workspaces 使ってますか? Cargo Workspaces ってなんや?って話があります。 詳しくは https://doc.rust-jp.rs/book-ja/ch14-03-cargo-workspaces.html に書いてるの でツラーっと読んでいきますと。
2
Cargo Workspaces 使ってますか? Cargo Workspaces ってなんや?って話があります。 詳しくは https://doc.rust-jp.rs/book-ja/ch14-03-cargo-workspaces.html に書いてるの でツラーっと読んでいきますと。
「ワークスペースの作り方」はあるけど、なにができるのか、なにがうれしい のか、がない!?!? 3 ※ "The Cargo Book" にも Workspaces のページがありますが、似たように設定項目の説明です : https://doc.rust-lang.org/cargo/reference/workspaces.html
「まとめ」を先出し (多い) • Cargo Workspaces を使うとモノレポ的に複数クレートを管理できます • 責務をクレートで分けるとわかりやすいです • 複数クレートあるあるの
Orphan Rule の回避法は book に載ってます • レイヤードアーキテクチャーとかいろんな種類のツールとか作りやすいです • プライベートなクレートに依存するときに、依存の依存を減らせます • Cargo.toml の値を共通で指定できます • サブクレートを 1 つのディレクトリーに入れると指定しやすいです • クレート名に共通の接頭辞をつけると、Docker レイヤーキャッシュを効かせやすい です 4
book の概説を使った Cargo Workspaces の説明 (1/4) add/ ├── Cargo.lock ├──
Cargo.toml ├── add-one/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── adder/ │ ├── Cargo.toml │ └── src/ │ └── main.rs └── target/ 要は「外側のクレート」の中に「内側のクレート (サブクレート)」を分けること ができる機能です。 5 ※ `add` 自体は src/ を持たない ([package] を持たない) から virtual workspace というやつ (src/ を持つこともできる): https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace
book の概説を使った Cargo Workspaces の説明 (2/4) add/ ├── Cargo.lock ├──
Cargo.toml ├── add-one/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── adder/ │ ├── Cargo.toml │ └── src/ │ └── main.rs └── target/ 要は「外側のクレート」の中に「内側のクレート (サブクレート)」を分けること ができる機能です。 `add` の中で、`add_one` と `adder` という複数の異なるクレートを管理で きます。つまりモノレポです。 6 ※ `add` 自体は src/ を持たない ([package] を持たない) から virtual workspace というやつ (src/ を持つこともできる): https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace
book の概説を使った Cargo Workspaces の説明 (3/4) add/ ├── Cargo.lock ├──
Cargo.toml ├── add-one/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── adder/ │ ├── Cargo.toml │ └── src/ │ └── main.rs └── target/ 要は「外側のクレート」の中に「内側のクレート (サブクレート)」を分けること ができる機能です。 `add` の中で、`add_one` と `adder` という複数の異なるクレートを管理で きます。つまりモノレポです。 `add_one` と `adder` それぞれに Cargo.toml があって、クレートごとに依 存を管理できます。 7 ※ `add` 自体は src/ を持たない ([package] を持たない) から virtual workspace というやつ (src/ を持つこともできる): https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace
book の概説を使った Cargo Workspaces の説明 (4/4) add/ ├── Cargo.lock ├──
Cargo.toml ├── add-one/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── adder/ │ ├── Cargo.toml │ └── src/ │ └── main.rs └── target/ 要は「外側のクレート」の中に「内側のクレート (サブクレート)」を分けること ができる機能です。 `add` の中で、`add_one` と `adder` という複数の異なるクレートを管理で きます。つまりモノレポです。 `add_one` と `adder` それぞれに Cargo.toml があって、クレートごとに依 存を管理できます。 クレートは複数ありますが、中間生成物とか実行可能バイナリーは単一の `target/` ディレクトリーに入ります。 8 ※ `add` 自体は src/ を持たない ([package] を持たない) から virtual workspace というやつ (src/ を持つこともできる): https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace
責務を分けやすい 9
別のクレートになるので責務を分けやすい 10 Web アプリケーションを作るときなどを考えると、 HTTP な部分、DB な部分、コア部分、とか分かれている方が 見通しが良いです。HTTP 部分が分かれてると、 CLI
のツールを作るとかもやりやすいです。 foo-core foo-server 色々 foo-db foo-auth0 foo-tools (CLI) ↳clap ↳serde, axum ↳serde, reqwest ↳diesel
クレートが分かれると Orphan Rule がつらい 11 Orphan Rule: 外部のクレートの型に impl できないやつ
→ newtype idiom で回避できます impl foo_core::TypeX { fn some_method(&self) -> i32 { todo!() } } ※1 book の Orphan Rule の説明: https://doc.rust-jp.rs/book-ja/ch10-02-traits.html?highlight=orphan#...... ※2 解消方法: https://doc.rust-jp.rs/book-ja/ch19-03-advanced-traits.html#........ struct TypeX(foo_core::TypeX); impl TypeX { fn some_method(&self) -> i32 { todo!() } } できないやつ newtype idiom で自分のクレートの型にする
すべてが依存するデータ型用のクレートがあると良い? 12 クレート間ごとに色々な From<T> を実装することになる?データ型用のクレートを作って、すべてのクレートか ら依存させ、それぞれの newtype 同士は中身だけ渡す。とかできると From<T> の実装が薄くなって嬉しそう。
foo-core foo-server 色々 foo-db foo-auth0 foo-tools (CLI) foo-types ※ diesel の FromSql / ToSql など、db でも types でも要りそうな型は、 types で実装して features で出し分けできると良さそう。
設計の話 13
レイヤードアーキテクチャを作りやすい レイヤードアーキテクチャーみたいな標準的な設計パターンを上手く当てはめられます。 14 ※ https://medium.com/swlh/clean-architecture-a-little-introduction-be3eac94c5d1
依存方向がこうなってますが…… 15 DIP (依存性逆転の原則) を考えると、 foo-core foo-server 色々 foo-db foo-auth0
foo-tools (CLI)
依存方向は本来はこうであるべき……? 16 DIP (依存性逆転の原則) を考えると、core から外に依存するのは良くないのでは? (弊社の問題です。) foo-core foo-server 色々
foo-db foo-auth0 foo-tools (CLI)
そうは言っても、core から分けたサブクレートへ依存したい状況もある 17 すべての SDK が crate.io にあるわけではないので (e.g. Auth0、社内の別システム
)、自分である程度の実装 が必要なものは lib 層、DIP 層とかに分ける必要がある。 (types クレートを用意していた場合でも、 types と lib の依存が必要。) foo-core foo-server foo-auth0-lib foo-auth0-dip データ型だけ依存したい 特化処理だけ依存したい core が要求する処理 (trait) を impl する DIP 層 システムに特化した処理を実装 する lib 層 ※ 社内の別システムも Rust で書かれているなら、そのシステムのサブクレートとしてクライアントライブラリーがあると便利そう
余談 18
余談: Workspaces に git 依存する 19 社内のクレートなどに git で依存するときは、個々のクレートに依存できます。 サーバーアプリケーションだと、クライアントライブラリーを
Workspaces でクレートとして用意して、別のシステ ムから依存するのがやりやすいです。 (単一のクレートになっていると、こういうときに依存ライブラリーが爆発的 に増えます。) [dependencies] foo-types = { git = "
[email protected]
/FairyDevices/foo.git" } foo-client = { git = "
[email protected]
/FairyDevices/foo.git" } Cargo.toml ※ https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-dependencies-from-git-repositories ※※ path 依存するときは個々のクレートへのパスを指定します。
共通の Cargo.toml の設定ができる 20
共通の Cargo.toml の設定ができる: 例1: 依存クレート 21 例えば serde のような、いろんなクレートから依存するクレートのバージョンや features
を 1 箇所で管理できる [workspace.dependencies] my-crate = { path = "my-crate/" } serde = { version = "1.0.203", features = ["derive"] } [dependencies] serde.workspace = true ./Cargo.toml 各クレートの Cargo.toml ※ https://doc.rust-lang.org/cargo/reference/workspaces.html の各項目が便利だよくらいの話が続きます。
共通の Cargo.toml の設定ができる: 例2: [packages] 22 crate.io に publish するクレートでより便利ではありますが、以下みたいな使い方もあります。
- version を個々に書かなくて良くなる - rust-version (Rust 処理系の最小バージョン ) が一箇所になる [workspace.packages] version = "0.1.0" rust-version = "1.79.0" [packages] version.workspace = true rust-version.workspace = true ./Cargo.toml 各クレートの Cargo.toml
Workspaces のオススメの使い方 23
サブクレートを一つのディレクトリーに入れよう 24 [workspace.members] では `*` が使えるので、サブクレートをすべて同じディレクトリーにおいておくと記述が楽 になります。 [workspace] members =
[ "./crates/*/", ] ./Cargo.toml my-crate/ ├── Cargo.lock ├── Cargo.toml ├── crates/ │ ├── sub_crate_a/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── lib.rs │ └── sub_crate_b/ │ ├── Cargo.toml │ └── src/ │ └── main.rs └── target ディレクトリー構造
クレート名に同一の接頭辞を付けよう 25 Docker Image をビルドするときに、依存クレートだけレイヤーにするとかがやりやすくなります。 FROM rust:1-bookworm AS builder COPY
Cargo.toml ./ COPY crates/my-crates-foo/Cargo.toml ./crates/my-crates-foo/ RUN mkdir ./crates/my-crate-foo/src/ \ && touch ./crates/my-crate-foo/src/lib.rs \ && cargo build --release \ && rm -r ./crates/my-crate-foo/src/ \ ./target/release/deps/my_crate* \ ./target/release/deps/libmy_crate_*.rlib COPY ./crates/my-crate-foo/src ./crate/my-crate-foo/src RUN cargo build --release Dockerfile 中間生成物の削除が楽
まとめ • Cargo Workspaces を使うとモノレポ的に複数クレートを管理できます • 責務をクレートで分けるとわかりやすいです • 複数クレートあるあるの Orphan
Rule の回避法は book に載ってます • レイヤードアーキテクチャーとかいろんな種類のツールとか作りやすいです • プライベートなクレートに依存するときに、依存の依存を減らせます • Cargo.toml の値を共通で指定できます • サブクレートを 1 つのディレクトリーに入れると指定しやすいです • クレート名に共通の接頭辞をつけると、Docker レイヤーキャッシュを効かせやすい です 26
終 27