Upgrade to Pro — share decks privately, control downloads, hide ads and more …

駆け出しでもできた!Rust と始める OSS コントリビューション

tomoikey
December 02, 2024

駆け出しでもできた!Rust と始める OSS コントリビューション

Rustプログラマに向けて、新卒エンジニアの私が実体験をもとにその一歩を支援します。 OSS貢献を通じて得た喜びや課題、Rustの特徴を具体的に紹介し、参加者が恐怖心を克服し挑戦できるようサポートします。 また、自作OSS refined_type の紹介を通じて、型を活用した実行時安全性の向上と効率的なバリデーション処理の方法も共有し、Rustの活用の幅を広げる内容にしています。

tomoikey

December 02, 2024
Tweet

Other Decks in Programming

Transcript

  1. • 名前 ◦ tomoikey • 生年月日 ◦ 2000-12-31 (23歳) •

    Name ◦ tomoikey • Birthday ◦ 2000-12-31 (23 years old) 自己紹介(self-introduction)
  2. • 対象聴衆 ◦ Rust に興味がある開発者 ◦ OSS に怯えてる方 • Who

    is this for? ◦ Developers interested in Rust ◦ Those who are intimidated by OSS 始まりのことば (introduction)
  3. 挑戦してみた Rust OSS (Rust OSS projects I’ve contributed to) async-graphql

    Zed 高速で軽量なRust製エディター 「Code at the speed of thought」がキャッチコピー Rust製のGraphQL crate Code firstな開発手法を採用している
  4. • GraphQL ライブラリ • マクロ機能を酷使する開発 ◦ GraphQL schemaの定義 ◦ Resolverの定義

    ◦ Directiveの定義 • Development using Rust’s macro features ◦ Definition of GraphQL schema ◦ Definition of resolver ◦ Definition of directive async-graphql
  5. • Type Directive (≒ Schema につけておくラベルのようなもの ) ◦ ほぼ全ての機能を実装した ▪

    ARGUMENT_DEFINITION ▪ ENUM ▪ ENUM_VALUE ▪ INPUT_FIELD_DEFINITION ▪ INPUT_OBJECT ▪ INTERFACE どんな機能を作ったの?
  6. @directive foo(description: String!) on ARGUMENT_DEFINITION type School { principle: Human!

    classes: [Class!]! teacher(id: ID! @foo(“hello”)): Human } type Human { name: String! age: Int! } type Class { teacher: Human! students: [Human!]! } どんな機能を作ったの?
  7. @directive foo(description: String!) on ARGUMENT_DEFINITION type School { principle: Human!

    classes: [Class!]! teacher(id: ID! @foo(“hello”)): Human } type Human { name: String! age: Int! } type Class { teacher: Human! students: [Human!]! } どんな機能を作ったの?
  8. • どんなアプリケーションなの? ◦ Rust製エディタ ◦ 軽量で高速に動作する ◦ 独自のGUIライブラリを利用 • What

    kind of application? ◦ An editor made with Rust ◦ A lightweight and fast-performance app ◦ Utilizes a custom GUI library Zed
  9. • 関数・構造体などのシグネチャ情報をポップアップで表示する機能 ◦ 引数・フィールドの名前 / 型はなにか? ◦ 自分はいま第何引数にいるのか? ◦ Language

    Server を叩く処理系から、UIの設計・実装までやった! • シグネチャ情報を表示できるエリアに入った時に自動でシグネチャ情報をポップアップで表示 する機能 ◦ その ON / OFF を切り替える設定機能も作った! • それらの細かい設定を JSON から定義できるようにした! ◦ 関数の予測変換候補から選んで、確定した瞬間にポップアップするかどうか? ◦ シグネチャ情報を表示できるエリアに入った時に自動でシグネチャ情報をポップアップするかどうか? どんな機能を作ったの?
  10. Good First Issue が個人的に合わなかった話 • 意外と内容の理解に時間がかかる ◦ Good First Issue

    から漁るのでその OSS が何者なのか・何を解決したいのか分からな い ◦ どこの馬の骨かも分からない OSS の Issue 読んでも分からんのは当たり前 ◦ Good First Issue だからといってすぐに理解できてすぐに実装が完了するというのは きっと強い人だけ • モチベーションが沸きにくい ◦ 愛がないと、レビューが長引いたときに MERGE までの道のりが遠く感じて辛い ◦ 検索のキーが Good First Issue だからそんなに思い入れがない
  11. Good First Issue が個人的に合わなかった話 • 数が少ない ◦ 原因不明... ◦ 簡単だからすぐ取られてる?

    ◦ そもそも新規参入を支援する体制が整ってない? • 古いのが多い ◦ 体感的には 2019~2020 につくられた Issue がそのまま放置されてるのが多い ◦ 放置されてるということは地雷系 Issue …!?
  12. • Forkしてとりあえず自分のリポジトリに対してPull Request を作ってみよう ◦ Fork元リポジトリに対して Pull Request を出す前の準備などなどする ◦

    説明文を綺麗にしたり ◦ 変な差分が混ざってないか確認したり ◦ 考慮漏れがないか確認したり ◦ コードが綺麗に書けているか確認したり • その Pull Request が完璧な状態になったら、次は親リポジトリに対して Pull Request を OPEN しよう ◦ どきどきレビュー待ちタイム • メンテナーによっては反応が遅いので 3 週間くらい は辛抱強く待とう ◦ たまにメンテナーでもなんでもない無関係の謎人物が絡んでくるコトも...!? Fork してコミットして Pull Request 作成
  13. • 責任感のあるお掃除屋さんとしての役割 ◦ 所有権を持つ変数がスコープを抜けるとお掃除関数を自動で呼び出してくれる ◦ => メモリの二重解放が起きない ▪ 人間は愚かなので、 必ず同一メモリ領域を

    2回 3回 解放をする ▪ GCがない言語だけど、メモリを安全に扱えるね ◦ => Mutex などの UnLock 忘れが起きない • MutexGuard (今ロック中ですよ型 ) がスコープを抜けた時に自動で UnLock してくれる ◦ 余談) Rust の Mutex はロック機構と保護対象データがセットで格納されてて便利 • データ競合が起きない ◦ 厳しい借用規則によってデータ競合が起きるための条件を作り出せない ◦ また、Send / Sync マーカートレイトによって、スレッド間のやりとりも安全! ▪ 例) 生ポインタとか Reference Count を間違って他のスレッドに Send できない Rustの所有権システムは神
  14. • ステータス ◦ 57 stars, 1 fork, 32,949 downloads (11/29

    現在) ◦ GitHub: https://github.com/tomoikey/refined_type • 使うとどう嬉しくなれるの??? ◦ 簡単に範囲の狭い型を作ることができる! ◦ 型を書くだけで簡単にバリデーション ができる! ◦ 型同士を組み合わせて複雑な条件を持つ型を簡単に作れる! refined_type
  15. { "name": "tomoikey", "age": 23, "friends": ["daichi", "yuto"] } JSONバリデーション例

    空ではない文字列が欲しい... 80未満の整数が欲しい... 空ではない文字列の要素が1つ以上ある配列が欲しい...
  16. #[derive(Debug, Deserialize)] struct Person { name: NonEmptyString, age: LessU8<80>, friends:

    NonEmptyVec<NonEmptyString> } fn main() { let json = r#"{ "name": "tomoikey", "age": 23, "friends": ["daichi", "yuto"] }"#; let data = serde_json::from_str::<Person>(json); println!("{data:#?}"); } JSONバリデーション例
  17. #[derive(Debug, Deserialize)] struct Person { name: NonEmptyString, age: LessU8<80>, friends:

    NonEmptyVec<NonEmptyString> } fn main() { let json = r#"{ "name": "tomoikey", "age": 90, "friends": ["daichi", "yuto"] }"#; let data = serde_json::from_str::<Person>(json); println!("{data:#?}"); } JSONバリデーション例
  18. type Age = Refined<And![ EvenRuleU8, MinMaxRuleU8<10, 100> ]>; fn main()

    { let target = Age::new(9); assert!(target.is_err()); let target = Age::new(10); assert!(target.is_ok()); let target = Age::new(11); assert!(target.is_err()); let target = Age::new(100); assert!(target.is_ok()); let target = Age::new(102); assert!(target.is_err()); } 条件の合成 (And) 偶数でかつ 10–100のu8が欲しい ...
  19. type Age = Refined<Or![ EvenRuleU8, MinMaxRuleU8<10, 100> ]>; fn main()

    { let target = Age::new(9); assert!(target.is_err()); let target = Age::new(10); assert!(target.is_ok()); let target = Age::new(11); assert!(target.is_ok()); let target = Age::new(100); assert!(target.is_ok()); let target = Age::new(102); assert!(target.is_ok()); } 条件の合成 (Or) 偶数あるいは 10–100のu8が欲しい ...
  20. type Age = Refined<Not<EvenRuleU8>>; fn main() { let target =

    Age::new(1); assert!(target.is_ok()); let target = Age::new(2); assert!(target.is_err()); } 条件の合成 (Not) 偶数以外の u8が欲しい ...
  21. • 合成系 ◦ And, Or, Not, Equiv, IfElse, Imply (If),

    Nand, Nor, Xor • コレクション系 ◦ Exists, ForAll, Head, Index, Init, Last, Nothing, Reverse, Skip, Tail, Count • 長さ系 ◦ LengthEqual, LengthGreater, LengthLess, LengthMinMax • 空ではない系 ◦ NonEmptyHashMap, NonEmptySet, NonEmptyString, NonEmptyVec, NonEmptyVecDeque • 数字系 ◦ Equal, Even, Greater, GreaterEqual, Less, LessEqual, MinMax, Odd, Range • 文字列系 ◦ AlphaDigit, Alphabet, Digit, Email, IPv4, IPv6, Regex 他にも...
  22. • And, Or, Not の表現が豊か ◦ 大体のものは And, Or, Not

    の合成で表すことができた ◦ 最低限の根幹となる定義のみで幅広く拡張できた • 特に個人的にいじってて楽しかったのは ◦ If ◦ IfElse ◦ Exists 作っていて面白かった部分
  23. • 論理包含 / Implication (P => Q) ◦ 条件文とほぼ同じものとされている ◦

    プログラミングの文脈で If-Then に相当するらしい • 第一命題が偽、あるいは第二命題が真の時に真となる論理演算 • refined_type 内部で表すとこんな感じ (※一部記法省略) ◦ Imply<R1, R2> = Or<Not<COND>, RULE> ◦ If<COND, RULE> = Or<Not<COND>, RULE> (= Imply<COND, RULE>) 作っていて面白かった部分 (If型)
  24. • IfElse ◦ 条件 (Condition) が真であるときに、THEN を適用 ◦ 条件 (Condition)

    が偽であるときに、ELSE を適用 • refined_type 内部で表すとこんな感じ (※一部記法省略) ◦ IfElse<COND, T, E> = Or<And<COND, T>, And<Not<COND>, E>> 作っていて面白かった部分 (IfElse型)
  25. • Exist ◦ Rule を満たす要素が、配列の中に 1つ以上ある場合に真となる型 • ForAll ◦ 配列内の全ての要素が

    Rule を満たしている場合に真となる • ForAll と Not の組み合わせで Exist を表現可能 ◦ Not(少なくとも1つ以上) = 1つもない = 全ての要素が RULE を満たさない = ForAll<Not<RULE>> ◦ Not(Not(少なくとも1つ以上)) = Not<ForAll<Not<RULE>>> • Exist<RULE> = Not<ForAll<Not<RULE>>> 作っていて面白かった部分 (Exist型)
  26. 良かったら使ってみてください GitHub : https://github.com/tomoikey/refined-type crates.io: https://crates.io/crates/refined_type docs : https://docs.tomoikey.com/introduction 他にも...

    • Equiv, Nand, Nor, Xor • Head, Index, Init, Last, Reverse, Tail • Equal, Greater, MinMax, Odd, Range • AlphaDigit, Alphabet, Digit, Email, Ipv4, Ipv6, Regex • NonEmptySet, NonEmptyHashMap, NonEmptyVecDeque • などなど...
  27. CREDITS: This presentation template was created by Slidesgo, incluiding icons

    by Flaticon, and infographics & images by Freepik. THANKS! ご清聴ありがとうございました GitHub: https://github.com/tomoikey Qiita: https://qiita.com/tomoikey