Módulo 1 · C# — Capítulo 14

Boas Práticas e Clean Code

Fechando o módulo: como organizar tudo que você viu — OOP, LINQ, async, padrões — de um jeito que continua legível conforme o projeto cresce.

1. SOLID, em uma frase cada

SOLID é um acrônimo de cinco princípios de design que já apareceram, na prática, em vários exemplos deste módulo:

PrincípioEm uma fraseOnde você já viu
Single ResponsibilityUma classe deveria ter um único motivo para mudarIClienteRepository só cuida de acesso a dados; ClienteService só de regra de negócio
Open/ClosedAberta para extensão, fechada para modificaçãoStrategy (capítulo 12) — nova estratégia sem alterar código existente
Liskov SubstitutionUma subclasse deve poder substituir a classe base sem quebrar o comportamento esperadoQualquer FormaGeometrica do capítulo 6 funciona onde a base é esperada
Interface SegregationVárias interfaces pequenas e específicas > uma interface giganteINotificavel/IAuditavel separadas (capítulo 6), em vez de uma única interface "faz tudo"
Dependency InversionDependa de abstrações (interfaces), não de implementações concretasDependency Injection (capítulo 12) — ClienteService depende de IClienteRepository, não de ClienteRepository

2. Nomenclatura — convenções C# que valem a pena fixar

ElementoConvençãoExemplo
Classes, métodos, propriedadesPascalCaseClienteRepository, ObterPorId
Variáveis locais, parâmetroscamelCaseclienteId, nomeCompleto
Campos privados_camelCase_connectionString
InterfacesPrefixo IIClienteRepository
Métodos assíncronosSufixo AsyncObterClienteAsync
ConstantesPascalCase (não SCREAMING_CASE como em JS)const int TamanhoMaximo = 100;
Vindo do JavaScript

A diferença mais perceptível: métodos e propriedades públicas usam PascalCase em C# (ObterCliente), não camelCase (obterCliente) como em JS. É puramente convenção, mas seguir o padrão da comunidade C# facilita a leitura para qualquer outro desenvolvedor .NET que olhar seu código — inclusive seus futuros alunos.

3. Métodos pequenos, com um único nível de abstração

C# antes — faz tudo misturado
public async Task ProcessarPedidoAsync(Pedido pedido)
{
    if (pedido.Itens.Count == 0)
        throw new ArgumentException("Pedido vazio");
    decimal total = 0;
    foreach (var item in pedido.Itens)
        total += item.Preco * item.Quantidade;
    pedido.ValorTotal = total;
    await _repositorio.SalvarAsync(pedido);
    await _emailService.EnviarConfirmacaoAsync(pedido.ClienteEmail);
}
C# depois — cada método, uma responsabilidade
public async Task ProcessarPedidoAsync(Pedido pedido)
{
    ValidarPedido(pedido);
    CalcularTotal(pedido);
    await _repositorio.SalvarAsync(pedido);
    await _emailService.EnviarConfirmacaoAsync(pedido.ClienteEmail);
}

private void ValidarPedido(Pedido pedido)
{
    if (pedido.Itens.Count == 0)
        throw new ArgumentException("Pedido vazio");
}

private void CalcularTotal(Pedido pedido)
    => pedido.ValorTotal = pedido.Itens.Sum(i => i.Preco * i.Quantidade);

A segunda versão lê quase como uma lista de passos em português: validar, calcular, salvar, notificar. Cada detalhe de como fazer cada passo fica isolado em seu próprio método, no mesmo espírito das funções locais do capítulo 4.

4. Evite números e strings mágicos

C# antes
if (produto.Estoque < 10)
    NotificarReposicao(produto);

if (pedido.Status == "3")
    CancelarPedido(pedido);
C# depois — nomeado e tipado
const int EstoqueMinimo = 10;

if (produto.Estoque < EstoqueMinimo)
    NotificarReposicao(produto);

if (pedido.Status == StatusPedido.Cancelado)
    CancelarPedido(pedido);
Dica

"3" como status não diz nada para quem lê o código seis meses depois. Um enum StatusPedido {'{'} Pendente, Confirmado, Cancelado {'}'} transforma um número mágico numa palavra que se explica sozinha — e o compilador ainda impede valores inválidos.

5. Nullable Reference Types — deixando "pode ser null" explícito

Desde o C# 8, o compilador pode avisar quando uma referência potencialmente null é usada sem checagem — mas só se o recurso estiver habilitado no projeto:

C# habilitando (padrão em projetos novos) e usando
// no .csproj: <Nullable>enable</Nullable>

public class Cliente
{
    public string Nome { get; set; } = string.Empty; // nunca null
    public string? Telefone { get; set; }             // pode ser null — explícito
}

Cliente? cliente = await repositorio.ObterPorIdAsync(id);
Console.WriteLine(cliente.Nome); // aviso do compilador: cliente pode ser null aqui
if (cliente is not null)
    Console.WriteLine(cliente.Nome); // agora sem aviso

6. Comentários: explique o "porquê", não o "o quê"

C# comentário inútil
// incrementa o contador
contador++;
C# comentário que agrega
// XACT_ABORT é necessário aqui porque a procedure de origem
// não reverte a transação sozinha em erros de constraint
SET XACT_ABORT ON;

7. Onde isso te leva

Com fundamentos, OOP, LINQ, async e Clean Code cobertos, falta uma última peça antes de fechar o módulo: o capítulo 15 aprofunda ADO.NET puro — como falar com o SQL Server sem Entity Framework nem Dapper, só com as classes base do .NET. É um complemento importante ao que o capítulo 13 já mostrou, e a base de tudo que os módulos seguintes (MVC, APIs, Worker Services, Desktop) fazem por baixo dos panos.

📌 Resumo do capítulo

  • SOLID resume cinco princípios de design que já apareceram em exemplos práticos ao longo do módulo.
  • Siga as convenções de nomenclatura da comunidade C# (PascalCase para membros públicos, Async em métodos assíncronos, I em interfaces).
  • Métodos pequenos com uma responsabilidade cada são mais fáceis de ler, testar e reaproveitar.
  • Evite números/strings mágicos — nomeie constantes e use enum para conjuntos fixos de valores.
  • Nullable Reference Types tornam "pode ser null" parte do tipo, não uma suposição implícita.
  • Comentários deveriam explicar o porquê de uma decisão não óbvia, não repetir o que o código já diz.

✏️ Praticando

  1. Pegue o método usp_PedidoCheckout convertido para C# (ou qualquer método longo que você já escreveu neste curso) e refatore-o em métodos menores, cada um com uma única responsabilidade.
  2. Substitua qualquer string usada como status/categoria no seu código por um enum.
  3. Habilite <Nullable>enable</Nullable> num projeto de teste e corrija os avisos que aparecerem.