La cola del lagarto

En biología, la autotomía es cuando un animal se desprende de una parte del cuerpo que ya no le sirve. Un lagarto suelta su cola para escapar de un depredador. La cola fue útil una vez, pero sobrevivir exige dejarla ir. Luego vuelve a crecer una nueva.

Así deberías pensar sobre la refactorización de una app React Native hecha con vibe coding.

En los primeros MVPs codificados con IA, el primer flujo de auth suele salir mucho más rápido de lo que cualquiera espera. El problema empieza unas semanas después, cuando el producto cambia y el equipo intenta refactorizar con cuidado un código que en realidad nunca diseñó. Ahí es cuando se rompe el login, el estado del usuario se desajusta y el número de bugs sube. Están intentando preservar código que debería haberse reemplazado.

Refactorizar código generado por IA es caro porque exige entender una intención que nunca fue tuya. Claude Code creó abstracciones que tú no diseñaste. Tomó decisiones de acoplamiento que tú no aprobaste. Refactorizar ese código significa hacer ingeniería inversa de decisiones arquitectónicas tomadas de forma probabilística, no intencional.

Reemplaza, no refactorices

La alternativa: si un módulo satisface la misma interfaz y pasa las mismas pruebas, puedes intercambiarlo sin entender la implementación antigua. El módulo viejo se borra. El nuevo ocupa su lugar. La composition root es el único archivo que lo sabe.

// Module A (Auth v1) -> Interface Contract -> Module A' (Auth v2)

// The old auth module. You don't need to understand it.
// Claude Code generated it. It worked. Now it's done.
class SupabaseAuthService implements AuthService {
  // ... implementation you inherited ...
}

// The new auth module. You designed it. Claude Code helps write it.
class CustomAuthService implements AuthService {
  // ... your clean implementation ...
}

// The composition root is the ONLY place that changes:
const auth: AuthService = useSupabase
  ? new SupabaseAuthService()
  : new CustomAuthService()

La pantalla de login no cambia. Los route guards no cambian. Los hooks no cambian. Solo la composition root sabe que ocurrió un cambio. Ese es el poder de una arquitectura guiada por interfaces cuando trabajas con código generado por IA. Las interfaces son tu póliza de seguro contra la deuda técnica.

Cuatro requisitos previos para borrar con seguridad

Esto solo funciona si tienes cuatro cosas en su sitio. Sin ellas, solo estás borrando código y esperando tener suerte. Con ellas, estás haciendo cirugía:

  • Interfaces definidas: cada módulo expone un contrato. Tipos de TypeScript, esquemas de API, boundaries claros. Cursor genera contra ellos. Claude Code los lee. Tú los posees.
  • Enforcement de boundaries: los módulos no pueden meterse en los internos de otros. dependency-cruiser, ESLint o la convención lo impiden.
  • Contract tests: los tests verifican la interfaz, no la implementación. Si el módulo nuevo pasa las mismas pruebas, es conductualmente equivalente.
  • Grafos de dependencias limpios: sin dependencias circulares. Sin acoplamiento implícito a través de globales. El grafo de imports es un DAG, no una telaraña.

Cambiar analytics sin tocar una pantalla

Empezaste con Segment porque Claude Code te lo sugirió. Ahora necesitas PostHog. El módulo viejo se borra. El nuevo implementa la misma interfaz. Cada call site permanece idéntico:

// Before
const analytics = new SegmentAnalytics(writeKey)

// After — same interface, different implementation
const analytics = new PostHogAnalytics(apiKey)

// Every call site stays the same.
// Cursor-generated screens don't change.
analytics.track('purchase_completed', { productId: '123' })
analytics.identify(userId, { plan: 'premium' })

El instinto de preservar es fuerte. Queremos llevar nuestro código hacia delante con cuidado, conservando cada comportamiento. Pero cuando trabajas con código generado por IA, el camino más seguro a menudo es soltarlo. Escribe buenas interfaces. Haz cumplir los boundaries. Luego ten la disposición de borrar.

El Autotomy Expo Starter Pack está construido alrededor de esta filosofía: cada módulo está diseñado para el reemplazo, no para la preservación. Cuando tu app hecha con vibe coding choca contra el muro de la escala, no desenredas las decisiones arquitectónicas de Claude Code. Las reemplazas.