Introdução: Por que o Clean Code é importante em Rust
\nRust é famoso por seu desempenho e segurança de memória, mas sem seguir os princípios de código limpo, até o projeto mais rápido pode se tornar um pesadelo de manutenção. Clean Code não é apenas estética, é a base que permite que as equipes façam alterações rapidamente, encontrem bugs e escalem aplicações. Neste artigo, vamos analisar os princípios-chave para escrever código limpo em Rust com exemplos reais que ajudarão você a escrever programas fáceis de ler e modificar.
\nVamos nos concentrar em quatro aspectos: nomes significativos, trabalho com tipos e traits, tratamento de erros e refatoração. Cada princípio será ilustrado com código que você pode aplicar imediatamente em seus projetos.
\n\nPrincípio 1: Nomes significativos e estrutura
\nO primeiro passo para um código limpo são nomes corretos. Em Rust, onde o sistema de tipos já fornece muitas informações, os nomes de variáveis, funções e módulos devem complementar o contexto, não duplicá-lo.
\n\nNomes de variáveis e funções
\nEvite nomes de uma letra (exceto para índices em loops curtos). Use verbos para funções e substantivos para variáveis.
\n// Ruim\nfn c(a: &[i32]) -> i32 {\n a.iter().sum()\n}\n\n// Bom\nfn calculate_sum(numbers: &[i32]) -> i32 {\n numbers.iter().sum()\n}\n\nEm Rust, é comum usar snake_case para funções e variáveis, e CamelCase para tipos e traits. Siga esse estilo de forma consistente.
Estruturas e módulos
\nAgrupe dados relacionados em estruturas. Isso melhora a legibilidade e permite que o compilador verifique a correção.
\n// Ruim: variáveis dispersas\nlet user_name = String::from("Alice");\nlet user_age = 30;\nlet user_email = String::from("alice@example.com");\n\n// Bom: estrutura com campos claros\nstruct User {\n name: String,\n age: u8,\n email: String,\n}\nlet user = User {\n name: String::from("Alice"),\n age: 30,\n email: String::from("alice@example.com"),\n};\n\nUse módulos para separar o código logicamente. Cada módulo deve ser responsável por uma área de responsabilidade (Princípio da Responsabilidade Única).
\n\nPrincípio 2: Uso do sistema de tipos e traits
\nO sistema de tipos do Rust é uma ferramenta poderosa para escrever código autodocumentado. Em vez de comentários, use tipos para expressar intenções.
\n\nPadrão Newtype (padrão "novo tipo")
\nEncapsular tipos primitivos em uma estrutura evita confusão e adiciona semântica.
\n// Ruim: fácil confundir a ordem dos argumentos\nfn set_coordinates(x: f64, y: f64) { /* ... */ }\n\n// Bom: os tipos indicam claramente o significado\nstruct Latitude(f64);\nstruct Longitude(f64);\n\nfn set_coordinates(lat: Latitude, lon: Longitude) { /* ... */ }\n\n\nTraits como contratos
\nTraits definem comportamentos. Nomeie-os de forma que fique claro qual funcionalidade eles fornecem.
\n// Ruim: nome abstrato\ntrait Process {\n fn handle(&self);\n}\n\n// Bom: o nome reflete a ação\ntrait Serialize {\n fn to_json(&self) -> String;\n}\n\n// Implementação para a estrutura\nstruct Config {\n version: u8,\n}\n\nimpl Serialize for Config {\n fn to_json(&self) -> String {\n format!("{{\\"version\\": {}}}", self.version)\n }\n}\n\nUse programação genérica (generics) com limites de traits apenas quando realmente necessário. Isso torna o código flexível, mas não sobrecarregado.
\n\nPrincípio 3: Tratamento adequado de erros
\nEm Rust, não há exceções, mas há um sistema poderoso com Result e Option. O código limpo os usa de forma idiomática, evitando pânico e unwrap() desnecessários.
Evite unwrap() em código de produção
\nunwrap() e expect() são apropriados apenas em protótipos ou testes