Clean Code на Rust: مبادئ وأمثلة
كتابة كود نظيف ليست مجرد اتباع موضة عابرة، بل هي مهارة أساسية تميز المحترف عن الهاوي. في عالم برمجة الأنظمة، حيث تكتسب Rust شعبية متزايدة، تصبح القدرة على كتابة كود مفهوم، قابل للصيانة، وآمن أمرًا بالغ الأهمية. في هذا المقال، سنقوم بتحليل المبادئ الرئيسية لـ Clean Code كما تُطبق على Rust، مدعومة بأمثلة عملية.
1. التسمية: قل ما يفعله المتغير
التسمية الصحيحة هي أساس الكود القابل للقراءة. في Rust، حيث توفر الكتابة القوية ونظام الملكية الكثير من المعلومات، الأسماء الجيدة تجعل الكود يوثق نفسه بنفسه.
مثال سيء:
fn calc(x: &[i32]) -> i32 { let mut r = 0; for i in x { r += i; } r}مثال جيد (Clean Code):
fn calculate_sum(numbers: &[i32]) -> i32 { let mut total = 0; for number in numbers { total += number; } total}استخدم الأفعال للدوال (calculate, fetch, validate) والأسماء للمتغيرات (total, user_name, config). تجنب الاختصارات مثل tmp, res, أو val — فهي لا تخبرنا شيئًا عن الغرض.
2. الدوال: صغيرة وبمسؤولية واحدة
مبدأ المسؤولية الواحدة لا ينطبق فقط على الكلاسات ولكن أيضًا على الدوال. يجب أن تقوم كل دالة بشيء واحد بالضبط وأن تفعله جيدًا.
مثال سيء (الدالة تفعل أكثر من اللازم):
fn process_user_data(user: &User) -> Result<(), String> { // Validation if user.name.is_empty() { return Err("Name is empty".to_string()); } // Logging println!("Processing user: {}", user.name); // Saving to DB save_to_database(user)?; // Sending email send_welcome_email(user.email)?; Ok(())}مثال جيد (مقسم إلى دوال صغيرة):
fn process_user_data(user: &User) -> Result<(), AppError> { validate_user(user)?; log_user_processing(user); save_user_to_db(user)?; send_welcome_email(&user.email)?; Ok(())}
fn validate_user(user: &User) -> Result<(), AppError> { if user.name.is_empty() { return Err(AppError::Validation("Name is required".into())); } Ok(())}
fn log_user_processing(user: &User) { println!("Processing user: {}", user.name);}لاحظ: الآن كل دالة لها مسؤولية واضحة، وأصبح الكود أسهل في الاختبار والتعديل.
3. معالجة الأخطاء: استخدم Result وأنواع الأخطاء الخاصة بك
Rust ليس لديها استثناءات، وهذا شيء رائع. Clean Code في Rust يعني معالجة أخطاء صريحة من خلال أنواع Result<T, E> و Option<T>. تجنب حالات الذعر (unwrap(), expect()) في كود الإنتاج.
مثال سيء (الذعر عند الخطأ):
fn read_config(path: &str) -> Config { let content = std::fs::read_to_string(path).unwrap(); serde_json::from_str(&content).unwrap()}مثال جيد (معالجة أخطاء نظيفة):
#[derive(Debug, thiserror::Error)]pub enum ConfigError { #[error("Failed to read file: {0}")] IoError(#[from] std::io::Error), #[error("Failed to parse config: {0}")] ParseError(#[from] serde_json::Error),}
fn read_config(path: &str) -> Result { let content = std::fs::read_to_string(path)?; let config: Config = serde_json::from_str(&content)?; Ok(config)}
```