Home >アドベントカレンダー >Awesome Rustから学ぶRustのwebプログラミングのベストプラクティス
All struct definitions must be commented.
/// Serverpub struct Server { /// Name of the server pub name: String,}このように、構造体やそのフィールドに対して簡潔なコメントを付けることが推奨されています。
name
やvalue
など、一般的な名称が使われる場合は、文脈がなければその意味を誤解する恐れがあります。///
で始まるドキュメンテーションコメントを使用することで、自動的にrustdoc
によるHTML形式のAPIドキュメントが生成できます。プロジェクトのドキュメントが整備されることで、チーム内外での情報共有がスムーズになります。#[derive(...)]
アトリビュートを使ったトレイトの自動実装があります。ただし、これを構造体ごとに手動で記述すると、コードが冗長になる可能性があります。Revoltのリポジトリでは、カスタムマクロを活用してこの問題を解決しています。#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]pub struct Server { pub id: String, pub name: String,}
auto_derived! { /// サーバー pub struct Server { pub id: String, pub name: String, }}
macro_rules! auto_derived { ( $( $item:item )+ ) => { $( #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] $item )+ };}このようにマクロを使うことで、繰り返し作業を減らし、一貫性を保ちながらメンテナンス性の高いコードを書くことができます。
If special serialisation conditions are required, such as checking if a boolean is false, use the existing definitions for these functions from the crate root:
#[serde(skip_serializing_if = "crate::if_false", default)]引用されたスタイルガイドでは、
if_false
という関数を使用して、false
の場合にactive
フィールドをスキップする方法が推奨されています。None
である場合、Option
をスキップする設定などは、よく使うかもしれないですね。#[serde(skip_serializing_if = "Option::is_none")]
impl
ブロックを使用します。Revoltのスタイルガイドには、impl
ブロックの記述に関していくつかの指針が示されています。impl
blocks may be defined below the struct definitions and should be ordered in the same order of definition. Methods in the block must follow the same guidelines as traits where-in: methods are ordered in terms of CRUD, there are empty line breaks, and methods are commented.
impl
ブロックの位置impl
ブロックは、対応する構造体や列挙型の直下に配置することで、コード全体の構造が分かりやすくなります。impl
ブロックの例impl
ブロックの例を示します。impl Server { /// サーバー作成 pub fn create() -> Self { /* 実装 */ } /// サーバー情報取得 pub fn read(&self) { /* 実装 */ } /// サーバー情報更新 pub fn update(&mut self) { /* 実装 */ } /// サーバー削除 pub fn delete(self) { /* 実装 */ }}
lemmy/├── src/│ ├── api_routes_v3.rs│ ├── api_routes_v4.rs│ ├── code_migrations.rs│ ├── lib.rs│ ├── main.rs│ ├── prometheus_metrics.rs│ ├── scheduled_tasks.rs│ └── session_middleware.rs└── crates/ ├── api/ ├── api_common/ ├── api_crud/ ├── apub/ ├── db_perf/ ├── db_schema/ ├── db_views/ ├── db_views_actor/ ├── db_views_moderator/ ├── federate/ ├── routes/ └── utils/Lemmyのリポジトリを覗くと、複数のRustクレートを1つのリポジトリに集約した「モノレポ」構成を取っていることが分かります。
src/
ディレクトリにアプリケーション本体やルートエントリーポイントが置かれ、crates/
ディレクトリ配下にはapi/
、api_common/
、federate/
、utils/
といった、特定の機能や責任を担うクレートが整理されています。api_common/
やutils/
といった専用クレートにまとめることで、重複を削減し、プロジェクト全体で統一的な実装を保つことが可能です。api/
クレート: APIエンドポイント関連の実装apub/
、federate/
クレート: Fediverse対応や外部連携機能db_schema/
、db_perf/
、db_views/
: データベーススキーマや最適化、ビュー機能の分離Awesome Rust
の中からrevoltchat/backend
とLemmyNet/lemmy
を例に、RustでのWebバックエンド構築や大規模アプリケーション設計について紹介しました。