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
350
Rust で型安全な SPA 開発
mnawa
0
860
Other Decks in Programming
See All in Programming
TAKTでAI駆動開発の品質を設計する
j5ik2o
7
1.6k
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
990
Datadog LLM Observabilityで実現する 安全なLLM Usage 管理
3150
0
130
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
180
AIで効率化できた業務・日常
ochtum
0
150
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
250
Make SRE Operations Easier with Azure SRE Agent
kkamegawa
0
9.1k
JavaDoc 再入門
nagise
1
430
鹿野さんに聞く!『TypeScriptコードレシピ集』で磨く実践力
tonkotsuboy_com
4
900
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
810
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
610
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
270
Featured
See All Featured
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
30k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.1k
Site-Speed That Sticks
csswizardry
13
1.2k
How to Talk to Developers About Accessibility
jct
2
270
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
72
40k
Why Our Code Smells
bkeepers
PRO
340
58k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
370
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
150
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
62
44k
How to train your dragon (web standard)
notwaldorf
97
6.7k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.2k
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