Clean Code em Rust: princípios e exemplos para iniciantes
Rust é uma poderosa linguagem de programação de sistemas, conhecida por seu desempenho e segurança de memória. No entanto, como em qualquer outra linguagem, escrever código limpo (Clean Code) é uma habilidade criticamente importante. Código limpo é mais fácil de ler, manter e estender. Para desenvolvedores iniciantes em Rust, dominar os princípios do Clean Code desde o início ajuda a evitar erros típicos e torna seu código elegante e confiável. Neste artigo, vamos explorar os principais princípios de código limpo em Rust com exemplos concretos.
1. Nomenclatura de variáveis e funções
Um bom nome deve explicar a intenção do programador. Em Rust, é comum usar snake_case para variáveis, funções e módulos, e CamelCase para tipos e traits.
Exemplo ruim:
fn c(a: i32, b: i32) -> i32 { let x = a + b; x}Exemplo bom:
fn calculate_sum(first_number: i32, second_number: i32) -> i32 { let result = first_number + second_number; result}Use nomes significativos: user_name em vez de un, process_data em vez de pd. Evite abreviações, a menos que sejam amplamente aceitas (por exemplo, idx para índice).
2. Funções pequenas e responsabilidade única
O Princípio da Responsabilidade Única (Single Responsibility Principle) afirma: cada função deve fazer apenas uma coisa. Se uma função realiza várias ações, é difícil testá-la e modificá-la.
Exemplo ruim (função faz demais):
fn process_user(user_id: u32) { // Obter usuário do banco de dados // Validar dados // Enviar email // Registrar log println!("Processando usuário {}", user_id);}Exemplo bom (divisão em funções pequenas):
fn get_user(user_id: u32) -> User { // Lógica para obter usuário User { id: user_id }}
fn validate_user(user: &User) -> bool { // Lógica de validação user.id > 0}
fn send_email(user: &User) { // Lógica para enviar email println!("Email enviado para o usuário {}", user.id);}
fn process_user(user_id: u32) { let user = get_user(user_id); if validate_user(&user) { send_email(&user); }}Tente manter as funções com 10-20 linhas. Se for mais longa, divida-a.
3. Tratamento de erros: use Result e Option
Rust incentiva o tratamento explícito de erros através dos tipos Result<T, E> e Option<T>. Evite usar .unwrap() ou .expect() em código de produção — isso causa pânico em caso de erro.
Exemplo ruim (extração perigosa):
fn read_file(path: &str) -> String { let content = std::fs::read_to_string(path).unwrap(); // Pode falhar! content}Exemplo bom (tratamento de erro):
use std::fs;
fn read_file(path: &str) -> Result<String, std::io::Error> { let content = fs::read_to_string(path)?; // Operador ? para propagar erro Ok(content)}
fn main() { match read_file("data.txt") { Ok(data) => println!("Conteúdo do arquivo: {}", data), Err(e) => eprintln!("Erro ao ler arquivo: {}", e), }}Use o operador ? para concisão, mas sempre trate os erros no nível superior. Para seus próprios erros, crie enumerações com o trait std::error::Error.
4. Comentários e documentação
Código limpo deve ser autodocumentado. Comentários explicam o porquê, não o que. Para documentar APIs públicas, use /// (doc comments).
Exemplo ruim (comentário inútil):
// Incrementa o contador em 1counter += 1;