Clean Code em C#: Caminho para o código profissional
Todo desenvolvedor sonha em escrever código que não apenas funcione, mas que também seja fácil de ler, manter e estender. O conceito de "código limpo" (Clean Code), popularizado por Robert Martin, não é apenas um conjunto de regras, mas uma filosofia de profissionalismo. Neste artigo, vamos explorar os princípios-chave do Clean Code aplicados à linguagem C# e à plataforma .NET, usando exemplos simples e compreensíveis para iniciantes. Você aprenderá como transformar código "sujo" em uma solução elegante e confiável.
1. Nomes significativos: O primeiro passo para a limpeza
A parte mais importante do código limpo é a nomenclatura. O nome de uma variável, método, classe ou interface deve responder às perguntas "O que é isso?" ou "O que ele faz?". Bons nomes eliminam a necessidade de escrever comentários.
Exemplos ruins e bons
Evite abreviações de uma letra (exceto para contadores de loop) e nomes abstratos.
// RUIM: Nomes confusosint d; // elapsed time in daysList<string> l = new List<string>();
public void Proc(int x) { // ...}
// BOM: Nomes significativosint elapsedTimeInDays;List<string> customerNames = new List<string>();
public void ProcessOrder(int orderId){ // ...}Regras para C#:
- Classes e métodos —
PascalCase(por exemplo,OrderService,CalculateTotal). - Variáveis locais e parâmetros —
camelCase(por exemplo,orderId,customerName). - Interfaces — começam com a letra
I(por exemplo,IRepository). - Evite a "notação húngara" (tipo
strName). O tipo da variável deve ser óbvio pelo contexto.
2. Funções: Pequenas e fazendo uma única coisa
Uma função (ou método) deve ser pequena e executar apenas uma tarefa (Princípio da Responsabilidade Única no nível de métodos). Se uma função faz várias coisas, ela precisa ser dividida em funções menores.
Refatoração de uma função grande
Imagine que precisamos salvar um pedido e enviar uma notificação. O código ruim faz tudo de uma vez.
// RUIM: Função faz demaispublic void SaveOrderAndNotify(Order order){ // 1. Validação if (order.Items.Count == 0) throw new Exception("Empty order");
// 2. Salvando no BD (hipoteticamente) Console.WriteLine($"Order {order.Id} saved.");
// 3. Enviando email Console.WriteLine($"Notification sent to {order.CustomerEmail}.");}
// BOM: Divisão em funções pequenaspublic void ProcessOrder(Order order){ ValidateOrder(order); SaveOrder(order); SendOrderConfirmation(order);}
private void ValidateOrder(Order order){ if (order.Items.Count == 0) throw new InvalidOperationException("Cannot process an empty order.");}
private void SaveOrder(Order order){ // Lógica de salvamento Console.WriteLine($"Order {order.Id} saved.");}
private void SendOrderConfirmation(Order order){ // Lógica de envio Console.WriteLine($"Notification sent to {order.CustomerEmail}.");}Dica: Tente manter o mesmo nível de abstração dentro de uma função. Não misture operações de banco de dados com formatação de texto no mesmo método.
3. Gerenciamento de erros e exceções
Código limpo lida com erros de forma previsível. Em C#, usamos exceções para isso. Evite retornar "números mágicos" (como -1) ou null para indicar um erro.
// RUIM: Retornar null em caso de erropublic User FindUser(int id){ if (id <= 0) return null; // O que o código chamador deve fazer? // ... busca return n