Refactorización de React Native: de 800 líneas a 100 líneas
Hay un momento en el que abres un archivo y sientes físicamente el peso de la deuda técnica. Mi pantalla principal tenía 800 líneas. Un solo archivo. Lógica de negocio, renderizado de UI, gestión de estado, llamadas a la API, todo mezclado en un componente monolítico imposible de mantener. Y no era un caso aislado: tenía 16 pantallas en el mismo estado.
Lo que te voy a contar aquí es cómo transformé una base de código caótica en una arquitectura limpia. No con una revolución espectacular, sino con una refactorización metódica, pantalla por pantalla, error por error.
Puntos clave a recordar:
- Un hook personalizado por pantalla separa la lógica de negocio del renderizado de la UI
- El patrón "orquestador + subcomponentes" reduce los archivos de 800 a 100 líneas
- ESLint con reglas estrictas (ceroany, promesas awaited) elimina errores silenciosos
- La deuda técnica es un costo real medible en tiempo, errores y motivación
- Refactorizar pantalla por pantalla permite entregar continuamente sin romper lo existente
¿Por qué un componente de 800 líneas es un problema?
La respuesta obvia: es ilegible. Pero el verdadero problema es más insidioso. Un componente monolítico:
- Oculta errores: cuando todo está en el mismo archivo, los efectos secundarios son impredecibles. Modificar la lógica de filtro puede romper la animación de transición sin que entiendas por qué.
- Ralentiza el desarrollo: cada modificación requiere comprender todo el archivo. Pasas 20 minutos "leyendo" antes de poder escribir 5 líneas.
- Hace imposible la depuración: cuando surge un error, tienes 800 líneas de sospechosos. No hay una frontera clara entre las responsabilidades.
- Deteriora la motivación: abrir un archivo monstruoso cada mañana, eso pesa. Es el tipo de fricción invisible que ralentiza un proyecto indie.
"Estás solo, ¿quién va a leer este código?" Yo. Yo dentro de tres meses cuando haya olvidado por qué esta pantalla hace lo que hace. La deuda técnica no es una metáfora. Es un costo real que se paga en tiempo, errores y motivación.
¿Qué estrategia de división adoptar?
Refactoricé las 16 pantallas siguiendo una estructura consistente. El patrón es simple pero potente:
1. Un hook personalizado para la lógica de negocio
Cada pantalla tiene su hook: useTaskDetail, useFeedScreen, useGroupScreen... El hook encapsula toda la lógica: carga de datos, gestión de estado, callbacks. El componente solo se encarga de renderizar JSX.
Antes:
// TaskDetailScreen.tsx - 800 líneas
const TaskDetailScreen = () => {
const [task, setTask] = useState(null);
const [loading, setLoading] = useState(true);
const [editing, setEditing] = useState(false);
// ... 50 otros useState
// ... 200 líneas de useEffect
// ... 300 líneas de handlers
// ... 250 líneas de JSX
}
Después:
// TaskDetailScreen.tsx - 100 líneas
const TaskDetailScreen = () => {
const { task, loading, editing, handlers } = useTaskDetail();
return (
<TaskDetailHeader task={task} onEdit={handlers.edit} />
<TaskDetailBody task={task} />
<TaskDetailActions handlers={handlers} />
);
}
El hook useTaskDetail tiene 200 líneas. Los subcomponentes tienen de 50 a 100 líneas cada uno. En total, son más líneas que antes, pero cada archivo es comprensible de forma aislada.
2. Subcomponentes para el renderizado
Cada sección visual de la pantalla se convierte en un componente dedicado: TaskDetailHeader, TaskDetailBody, TaskDetailActions. Cada uno recibe sus props y solo conoce su responsabilidad.
Este patrón está directamente inspirado en el Thinking in React oficial. No es nuevo, pero es increíble lo mucho que se olvida cuando se tiene prisa por entregar.
3. Un componente principal para la orquestación
El componente principal se convierte en un director de orquesta de 100 líneas: llama al hook, distribuye las props a los subcomponentes y gestiona el diseño global. Nada más.
¿Cómo pasar de 71 a 0 errores de ESLint?
Paralelamente a la refactorización de las pantallas, lancé ESLint en el backend con reglas estrictas. Resultado: 71 errores.
La tentación: desactivar las reglas que generan más errores. Eso es lo que hacen el 90% de los desarrolladores. Yo hice lo contrario: corregí cada error individualmente.
Las correcciones más impactantes
Eliminación de any: cada any en TypeScript es una bomba de tiempo. Compila, pasa las pruebas, pero falla en producción cuando llega un valor inesperado. Reemplacé cada any por un tipo explícito. Algunos casos requirieron crear interfaces dedicadas, pero el resultado es un código autodocumentado.
Promesas correctamente awaited: llamadas asíncronas sin await que fallaban silenciosamente. Sin error, sin advertencia, solo un comportamiento incorrecto en producción. ESLint detectó 12 casos de promesas no awaited. 12 errores potenciales eliminados en una hora.
Variables no utilizadas: importaciones olvidadas, variables declaradas y luego nunca utilizadas. No son errores, sino ruido que hace que el código sea más difícil de leer. Cada línea inútil es una distracción para el "tú del futuro" que intenta comprender el código.
¿Hay que refactorizar todo de golpe o progresivamente?
Progresivamente. Siempre progresivamente. Un "big bang refactoring" donde reescribes todo en una semana es la receta del desastre para un desarrollador en solitario. Rompes todo, ya no puedes entregar, y si surge un error crítico en producción, no puedes corregirlo rápidamente.
Mi método:
- Elegir la pantalla más dolorosa (la que te da pereza abrir)
- Extraer el hook personalizado primero (la lógica, no el renderizado)
- Probar que todo sigue funcionando exactamente igual que antes
- Extraer los subcomponentes uno por uno
- Entregar la pantalla refactorizada, pasar a la siguiente
Cada pantalla refactorizada tomaba entre 2 horas y medio día. Las más complejas (el Feed, la pantalla de grupo) tomaron un día completo. Pero en cada etapa, la aplicación seguía siendo funcional y entregable.
Este flujo de trabajo es similar a lo que Martin Fowler describe en su libro sobre refactorización: transformaciones pequeñas, incrementales y siempre reversibles.
¿Qué beneficios concretos después de la refactorización?
Después de dos semanas de trabajo:
- 16 pantallas refactorizadas: cada una sigue el mismo patrón (hook + subcomponentes + orquestador)
- 0 errores de ESLint en el backend (frente a 71 antes)
- Tiempo de comprensión dividido por 3: abrir una pantalla y entender lo que hace lleva 2 minutos en lugar de 10
- Errores reducidos: las 3 semanas siguientes fueron las más estables del proyecto
- Motivación recuperada: abrir un archivo limpio por la mañana lo cambia todo
La ganancia menos medible pero la más importante: la confianza. Después de la refactorización, ya no tenía miedo de modificar una pantalla. Sabía exactamente dónde estaba cada cosa, cuáles eran las dependencias y qué impacto tendría un cambio.
¿Cómo afecta la deuda técnica a un proyecto en solitario?
La deuda técnica en un proyecto en solitario tiene efectos específicos que no se encuentran en un equipo:
Sin red de seguridad. En un equipo, un colega puede revisar tu código, detectar una regresión o corregir un error cuando estás ausente. Solo, si tu código es incomprensible, eres tú, y solo tú, quien paga el precio.
El efecto compuesto. Cada atajo que tomas hoy se multiplica. Un any aquí, un // TODO: fix later allá, y en unos meses, tienes una base de código donde cada modificación lleva 3 veces más tiempo de lo que debería.
La espiral de desmotivación. Código sucio → errores → frustración → parches rápidos → código aún más sucio. He visto esta espiral en otros proyectos. La refactorización la rompió de golpe.
Es la misma lógica que aplico a la reestructuración de la base de datos y a la auditoría de seguridad: invertir tiempo ahora para ganar exponencialmente más tarde.
¿Qué reglas de ESLint recomendar para un proyecto de React Native?
Aquí están las reglas que tuvieron el mayor impacto en la calidad del código de TAMSIV:
@typescript-eslint/no-explicit-any: prohíbe losany. No negociable.@typescript-eslint/no-floating-promises: detecta promesas no awaited. Crítico para evitar errores silenciosos.@typescript-eslint/no-unused-vars: elimina el ruido del código muerto.react-hooks/exhaustive-deps: verifica las dependencias de los hooks. Esencial en React Native.no-console: obliga a usar un logger en lugar deconsole.logen producción.
Actívalas todas en modo "error", no "warn". Una advertencia se ignora. Un error se corrige.
Lo que aprendí de esta semana de refactorización
Esta semana fue la mejor del proyecto. No la más emocionante, ninguna característica visible para el usuario. Pero la más impactante para el futuro. Cada característica que construí después —el sistema de gamificación, los grupos jerárquicos, la agenda colaborativa— se benefició de esta arquitectura limpia.
Si eres un desarrollador en solitario y pospones una refactorización porque "no entrega nada visible", detente. Es la inversión más rentable que puedes hacer. No es glamuroso, no es emocionante, pero es fundamentalmente necesario.
La mejor semana del proyecto. Y lo repito sin dudarlo.
Preguntas Frecuentes
¿Cuánto tiempo lleva refactorizar 16 pantallas?
Para mí, aproximadamente dos semanas a tiempo completo. Cada pantalla toma entre 2 horas y un día según su complejidad. La pantalla más simple (un formulario básico): 2 horas. La más compleja (el Feed con gamificación): un día completo.
¿La refactorización introduce nuevos errores?
Ese es el riesgo principal. Para minimizarlo, refactoricé una pantalla a la vez y probé manualmente cada flujo antes de pasar al siguiente. No apareció ninguna regresión importante durante las dos semanas de refactorización.
¿Hay que escribir pruebas antes de refactorizar?
Idealmente, sí. En realidad, en un proyecto en solitario con 16 pantallas para refactorizar, escribir pruebas exhaustivas antes de la refactorización duplicaría el tiempo. Opté por pruebas manuales rigurosas y pruebas automatizadas después de la refactorización, sobre la arquitectura limpia.
¿El patrón hook + subcomponentes funciona para todas las pantallas?
Sí, con variaciones. Algunas pantallas simples no necesitan subcomponentes, el hook solo es suficiente. Otras pantallas complejas tienen varios niveles de subcomponentes. El principio sigue siendo el mismo: separar lógica y renderizado.
¿ESLint ralentiza el desarrollo diario?
Las primeras horas, sí, el tiempo para corregir los errores existentes. Luego, es lo contrario: ESLint acelera el desarrollo al detectar errores incluso antes de iniciar la aplicación. Es como un copiloto que corrige tu trayectoria en tiempo real.