Introducción: ¿Por qué tu código provoca un tic al senior?
\n\nEnviaste un pull-request. Pasaron cinco minutos. En el chat llega: «¿Y si reescribimos este bloque?» y una decena de comentarios debajo de cada segunda línea. ¿Te suena? Si escribes en C# y trabajas en equipo, la code review no es solo una casilla de verificación en Jira. Es el momento de la verdad.
\n\nHe recopilado las observaciones típicas que los seniors dejan en las revisiones de código C#. No se trata de sintaxis, sino de pensamiento. De cómo convertir «código que simplemente funciona» en código que no quieras reescribir el primer viernes.
\n\nVamos a analizar los antipatrones de C# que enfurecen incluso a los líderes de equipo más tranquilos.
\n\n1. Números y cadenas mágicas: «¿Y esto qué significa?»
\n\nEl comentario más frecuente en una revisión de código C# es la pregunta sobre los números. Escribes if (status == 3), y el senior pregunta de inmediato: «¿Qué es 3? ¿Es el estado “En proceso” o “Eliminado”?».
Mal:
\nif (order.Status == 3 && days > 7)\n{\n CancelOrder(order);\n}\n\n\nBien:
\nprivate const int OrderStatusCancelled = 3;\nprivate const int MaxDaysBeforeAutoCancel = 7;\n\nif (order.Status == OrderStatusCancelled && days > MaxDaysBeforeAutoCancel)\n{\n CancelOrder(order);\n}\n\n\nAún mejor: extraerlo a un enum. Los seniors adoran el código legible donde no sea necesario consultar la base de datos para entender la lógica de negocio. Esta es una regla básica de code review en C#: el código debe hablar por sí mismo.
\n\n2. Async void — el asesino silencioso de aplicaciones
\n\nSi escribes async void en algún lugar que no sean controladores de eventos (por ejemplo, en WPF o WinForms), prepárate para un gran punto en contra. Async void no se puede rastrear: la excepción caerá en la nada y derribará el proceso.
Mal:
\npublic async void LoadData()\n{\n var data = await _repository.GetDataAsync();\n // Si falla aquí — la aplicación caerá sin mensaje de error\n}\n\n\nBien:
\npublic async Task LoadDataAsync()\n{\n var data = await _repository.GetDataAsync();\n}\n\n\nEn una revisión de código C#, el senior señalará esto sin falta. Recuerda: async Task es tu amigo, async void es tu enemigo (excepto en eventos).
3. Clases Godzilla: Principio de Responsabilidad Única
\n\nAbres un archivo y tiene 2000 líneas. Una sola clase lo hace todo: accede a la base de datos, envía correos electrónicos, genera informes y hasta prepara café. Este es un antipatrón clásico de C#: el God Object.
\n\nEl senior en la code review de C# dirá: «Vamos a dividirlo en varias clases». Y tendrá razón.
\n\nEjemplo de violación:
\npublic class OrderService\n{\n public void ProcessOrder(Order order)\n {\n // 1. Validación\n // 2. Guardar en BD\n // 3. Enviar email\n // 4. Registro en log\n }\n}\n\n\nCómo debería ser:
\npublic class OrderProcessor\n{\n private readonly IOrderValidator _validator;\n private readonly IOrderRepository _repository;\n private readonly INotificationService _notificationService;\n\n public OrderProcessor(\n IOrderValidator validator,\n IOrderRepository repository,\n INotificationService notificationService)\n {\n _validator = validator;\n _repository = repository;\n _notificationService = notificationService;\n }\n\n public async Task ProcessOrderAsync(Order order)\n {\n _validator.Validate(order);\n await _repository.SaveAsync(order);\n await _notificationService.SendConfirmationAsync(order);\n }\n}\n\n\nEsto no es solo «bonito». Es comprobable. Puedes simular el repositorio y verificar solo la lógica de procesamiento. La refactorización de C# con este estilo es imprescindible para cualquier proyecto.
\n\n4. Excepciones como estructuras de control
\n\n