Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Cargo Workspaces のススメ
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
nawa
July 16, 2024
Programming
1.5k
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
430
Rust で型安全な SPA 開発
mnawa
0
890
Other Decks in Programming
See All in Programming
Optunaを作ったときにやりたかったこと、その後 (2026/10/16, Optuna Meetup #3)
iwiwi
2
1.2k
PumaからFalconに移行したRailsアプリケーションでの実践
falcon8823
0
190
當我們開始不讀 Code - AI Agent 時代,Code Review 與 Clean Code 還剩下什麼?
jame2408
1
290
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
180
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
270
Railsバージョンを4倍にした話
optim
0
520
npm との違いを手がかりにGo の依存管理を理解したい
optim
0
1k
🇪🇸 React Alicante 2026 (Workshop)
ythecombinator
PRO
0
100
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
370
半永久的に提供し続けられるプライベートクラウドを目指して ― 利用者の認知負荷を抑えるAPI抽象化とハードウェア世代交代の基盤設計
tomokon
0
510
Compiling a real-world CLI tool to native with Static Hermes
tmikov2023
0
130
見えないものを探る要求要件定義に必要な基本的思考 / invisible-requirement-thinking
minodriven
15
8.7k
Featured
See All Featured
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3.1k
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
870
Designing for humans not robots
tammielis
254
26k
First, design no harm
axbom
PRO
2
1.3k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
46k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
1k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
Navigating Team Friction
lara
192
16k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.8k
How to Think Like a Performance Engineer
csswizardry
28
2.9k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
Product Roadmaps are Hard
iamctodd
55
13k
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