Enterprise C#: por que o código para um banco e o código para um projeto pessoal são dois universos diferentes
\n\nSe você já migrou de uma pequena web studio para uma grande corporação ou fintech, conhece aquela sensação de leve choque cultural. Ontem você podia commitar um "hot fix" sem testes e com um único comentário //TODO: refactor, e hoje recebe um review com 20 observações, onde cada método público exige documentação XML e qualquer dependência precisa ser registrada no contêiner DI.
Desenvolvimento em C# no enterprise não é sobre "fazer rápido", mas sobre "fazer de forma que não quebre daqui a três anos, quando o autor do código já tiver sido demitido". Trata-se de previsibilidade, escalabilidade e intermináveis code reviews. Vamos entender do que realmente consiste o desenvolvimento enterprise em C# e como não ser demitido na primeira semana.
\n\n1. Arquitetura: SOLID não é uma palavra da moda, é lei
\n\nEm uma startup, você pode se dar ao luxo de um monolito com strings "mágicas" e classes gigantescas de 2000 linhas. No enterprise, não. Aqui, cada princípio SOLID não é uma abstração, mas um guia para a ação.
\n\nPrincípio da Responsabilidade Única (SRP)
\nSua classe não deve saber como enviar e-mails, salvar no banco de dados e analisar XML ao mesmo tempo. Se você vir três ou mais "responsabilidades" em uma única classe, isso é um mau cheiro. No enterprise, esse código será rejeitado no code review com a justificativa "violação do SRP, reescrever". Exemplo de código ruim:
\n\npublic class OrderService\n{\n public void ProcessOrder(Order order)\n {\n // 1. Validação\n // 2. Salvamento no BD\n // 3. Envio de email\n // 4. Logging\n }\n}\n\nA abordagem correta é dividir em serviços separados e usar o padrão Mediator ou Pipeline:
\n\npublic class ProcessOrderCommandHandler : IRequestHandler<ProcessOrderCommand, bool>\n{\n private readonly IOrderRepository _repo;\n private readonly IEmailService _email;\n private readonly ILogger<ProcessOrderCommandHandler> _logger;\n\n public ProcessOrderCommandHandler(IOrderRepository repo, IEmailService email, ILogger<ProcessOrderCommandHandler> logger)\n {\n _repo = repo;\n _email = email;\n _logger = logger;\n }\n\n public async Task<bool> Handle(ProcessOrderCommand request, CancellationToken cancellationToken)\n {\n var order = await _repo.GetByIdAsync(request.OrderId);\n // lógica\n await _email.SendAsync(order.CustomerEmail, "Order processed");\n _logger.LogInformation("Order {Id} processed", order.Id);\n return true;\n }\n}\n\nObserve: cada serviço faz exatamente uma coisa. Testar esse código é muito mais fácil.
\n\n2. Dependency Injection — seu melhor amigo
\n\nEm projetos enterprise em C#, você quase nunca verá new MyService() dentro de uma classe. Em vez disso, usa-se um contêiner DI (geralmente Autofac ou o embutido Microsoft.Extensions.DependencyInjection).
A regra é simples: se uma classe cria suas próprias dependências, ela viola o Dependency Inversion Principle. No enterprise, isso é considerado um erro de arquitetura. Exemplo:
\n\n// ❌ Ruim: acoplamento rígido\npublic class ReportGenerator\n{\n private readonly PdfExporter _exporter = new PdfExporter();\n public byte[] Generate() => _exporter.Export();\n}\n\n// ✅ Bom: inversão de dependências\npublic class ReportGenerator\n{\n private readonly IExporter _exporter;\n public ReportGenerator(IExporter exporter) => _exporter = exporter;\n public byte[] Generate() => _exporter.Export();\n}\n\nRegistro na inicialização:
\nservices.AddScoped<IExporter, PdfExporter>();\nservices.AddScoped<ReportGenerator>();\n\nPor que isso é necessário? Primeiro, para testes: você pode simular o IExporter e não ger