Refactorización de Código Heredado en Kotlin: Estrategia y Ejemplos
Trabajar con código heredado es una parte inevitable de la vida de cualquier desarrollador. A menudo, dicho código está escrito en Java, pero incluso proyectos en versiones tempranas de Kotlin pueden contener code smells y errores arquitectónicos. En este artículo, analizaremos una estrategia paso a paso para refactorizar código heredado en Kotlin, proporcionaremos ejemplos concretos de transformación y explicaremos cómo evitar errores típicos.
1. Preparación para la Refactorización: Primero la Seguridad
La primera y más importante etapa es garantizar la seguridad de los cambios. Sin una buena cobertura de pruebas, cualquier refactorización se convierte en un juego de ruleta rusa.
- Agregar pruebas unitarias. Si no hay pruebas, escríbelas para las secciones críticas del código. Usa los frameworks
JUnit 5yMockKpara Kotlin. - Congelar el comportamiento. Escribe pruebas que verifiquen el comportamiento actual del sistema (pruebas de caracterización), incluso si parece incorrecto. Esto te permitirá no romper la lógica durante la refactorización.
- Usar un sistema de control de versiones. Haz commits después de cada paso lógicamente completado para poder revertir los cambios.
Ejemplo de una prueba simple para una función heredada en Kotlin:
import org.junit.jupiter.api.Testimport kotlin.test.assertEquals
class LegacyServiceTest { @Test fun `test calculateTotal`() { val service = LegacyService() val result = service.calculateTotal(listOf(10.0, 20.0, 30.0)) assertEquals(60.0, result) }}2. Migración Gradual de Java a Kotlin
Si tu código heredado está escrito en Java, no intentes reescribir todo de una vez. Usa convertidores automáticos (por ejemplo, el integrado en IntelliJ IDEA: Code → Convert Java File to Kotlin File), y luego mejora manualmente el resultado.
Puntos clave a tener en cuenta después de la conversión:
- Seguridad nula. Reemplaza
@Nullabley@NonNullcon los operadores?y!!(este último solo si estás seguro de que no hay null). - Clases de datos. En lugar de clases Java con
equals()yhashCode(), usadata class. - Funciones de extensión. Extrae métodos estáticos de utilidad en funciones de extensión.
Ejemplo de conversión de una clase Java a Kotlin:
// Javapublic class User { private String name; private int age;
public User(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; } public int getAge() { return age; }}
// Kotlin (después de la refactorización)data class User(val name: String, val age: Int)3. Mejorando la Arquitectura: Eliminando el Código Espagueti
El código heredado a menudo sufre violaciones de los principios SOLID. Aquí hay tres técnicas específicas que ayudarán a ordenar el código:
3.1. Separación de Responsabilidades (Responsabilidad Única)
Encuentra clases que hacen demasiado. Por ejemplo, un "God Object" que almacena datos, valida y envía solicitudes. Divídelo en varias clases con un área clara de responsabilidad.
3.2. Reemplazar Cadenas Largas de if-else con when
Kotlin proporciona un poderoso operador when, que hace que el código sea más legible:
// Antes de la refactorizaciónfun getStatusText(status: Int): String { if (status == 0) return "Pending" else if (status == 1) return "Active" else if (status == 2) return "Blocked" else return "Unknown"}
// Después de la refactorizaciónfun getStatusText(status: Int): String = when (status) { 0 -> "Pending" 1 -> "Active" 2 -> "Blocked" else -> "Unknown"}