Clean Code em C#: como escrever código que dá vontade de ler
Todo desenvolvedor .NET já passou pela situação em que, depois de um ou dois meses, o próprio código se torna ilegível. Para evitar isso, existe a filosofia Clean Code, popularizada por Robert Martin. Neste artigo, vamos analisar os principais princípios do código limpo em C# com exemplos concretos que ajudarão você a escrever aplicações sustentáveis e escaláveis.
Por que Clean Code é importante para o desenvolvedor C#?
Código limpo não é apenas uma formatação bonita. É um conjunto de práticas que tornam o código:
- Legível — qualquer desenvolvedor entenderá rapidamente a lógica;
- Sustentável — fácil de fazer alterações sem risco de quebrar o sistema;
- Testável — o código é facilmente coberto por testes unitários;
- Eficiente — sem abstrações desnecessárias e duplicação.
Em C#, com sua tipagem forte e recursos poderosos do .NET (LINQ, async/await, Records), seguir os princípios do Clean Code é especialmente importante. Código ruim em C# pode levar a bugs não óbvios e problemas de desempenho.
Princípio 1: Nomenclatura de variáveis e métodos
O nome de uma variável ou método deve responder à pergunta "o que é isso?" ou "o que faz?". Evite abreviações de uma letra (exceto para índices de loops).
Exemplo ruim
public class Data{ public int a; // o que é isso? public string b; // não está claro
public void Do(int x, int y) // o que o método faz? { var r = x + y; Console.WriteLine(r); }}Exemplo bom (Clean Code)
public class Customer{ public int Id { get; set; } public string FullName { get; set; }
public void PrintCustomerSummary(int customerId, int orderCount) { var totalOrders = customerId + orderCount; Console.WriteLine($"Customer {customerId} has {totalOrders} orders"); }}Regra: Os nomes devem ser expressivos. Se uma variável se chama data, isso quase sempre é ruim. Use customerData, orderList, invoiceTotal.
Princípio 2: Métodos pequenos com uma única responsabilidade
Cada método deve fazer exatamente uma coisa. Se um método contém mais de 10-15 linhas, provavelmente precisa ser dividido. Esta é a base do princípio Single Responsibility (do SOLID).
Exemplo ruim (método faz tudo)
public void ProcessOrder(int orderId){ // 1. Validação if (orderId <= 0) throw new ArgumentException("Invalid ID"); // 2. Obter dados do banco var order = _db.Orders.Find(orderId); // 3. Calcular desconto decimal discount = 0; if (order.Total > 1000) discount = order.Total * 0.1m; // 4. Enviar email var email = new MailMessage(); email.To.Add(order.CustomerEmail); email.Subject = "Order processed"; // 5. Logging _logger.LogInformation("Order {Id} processed", orderId);}Exemplo bom (refatoração)
public void ProcessOrder(int orderId){ ValidateOrderId(orderId); var order = GetOrderFromDatabase(orderId); var discount = CalculateDiscount(order); SendConfirmationEmail(order, discount); LogOrderProcessing(orderId);}
private void ValidateOrderId(int orderId){ if (orderId <= 0) throw new ArgumentException("Order ID must be positive", nameof(orderId));}
private Order GetOrderFromDatabase(int orderId){ return _db.Orders.Find(orderId) ?? throw new InvalidOperationException("Order not found");}
private decimal CalculateDiscount(Order order){ return order.Total > 1000 ? order.Total * 0.1m : 0;}
private void SendConfir