Al corregir errores, concéntrate exclusivamente en las secciones de código relevantes sin modificar las partes funcionales no relacionadas. Analiza el mensaje de error y rastrea su origen. Aplica correcciones específicas que aborden el problema concreto manteniendo la compatibilidad con la base de código existente. Antes de confirmar cualquier solución, verifica que resuelva el problema original sin introducir nuevos errores. Preserva siempre la funcionalidad existente y evita reescribir código que no esté directamente relacionado con el error.
Enfoque para modificar el código
Al modificar código existente, usa un enfoque quirúrgico que cambie solo lo necesario para implementar la funcionalidad o corrección solicitada. Conserva los nombres de variables, los patrones de código y las decisiones de arquitectura presentes en la base de código. Antes de sugerir cambios, analiza las dependencias para asegurarte de que las modificaciones no rompan la funcionalidad existente. Presenta los cambios como diffs mínimos en lugar de reescrituras completas. Cuando identifiques mejoras que van más allá de la tarea inmediata, sugiérelas por separado sin implementarlas automáticamente.
Integración de bases de datos
Antes de sugerir nuevas estructuras de base de datos, examina a fondo el esquema existente para identificar las tablas, relaciones y campos ya presentes. Aprovecha las tablas existentes siempre que sea posible en lugar de duplicar modelos de datos. Cuando sean necesarias modificaciones en la base de datos, asegúrate de que sean compatibles con las consultas existentes y los patrones de acceso a los datos. Considera estrategias de migración del esquema que preserven los datos existentes. Verifica siempre las relaciones de claves externas y las restricciones de integridad de los datos antes de proponer cambios.
Análisis exhaustivo de incidencias
Aborda cada problema con un proceso de diagnóstico integral. Comienza recopilando toda la información relevante mediante un examen cuidadoso de los mensajes de error, los registros y el comportamiento del sistema. Formula varias hipótesis sobre las posibles causas en lugar de sacar conclusiones apresuradas. Prueba cada hipótesis de forma metódica hasta identificar la causa raíz. Documenta tu proceso de análisis y tus hallazgos antes de proponer soluciones. Considera los posibles casos límite y cómo podrían afectar al sistema.
Verificación de la solución
Antes de confirmar cualquier solución, implementa un proceso de verificación riguroso. Prueba la solución con respecto al problema original para confirmar que realmente lo resuelve. Revisa si hay efectos secundarios no deseados en la funcionalidad relacionada. Asegúrate de que el rendimiento no se vea afectado negativamente. Verifica la compatibilidad con diferentes entornos y configuraciones. Prueba los casos límite para garantizar la solidez. Solo después de completar esta verificación debes presentar la solución como confirmada.
Mantén la coherencia con la base de código existente en el estilo, los patrones y los enfoques. Analiza el código para identificar las convenciones de nomenclatura, las preferencias de formato y los patrones arquitectónicos. Sigue estos patrones establecidos al implementar nuevas funcionalidades o correcciones. Utiliza las mismas estrategias de manejo de errores, enfoques de logging y metodologías de pruebas presentes en el Proyecto. Esto preserva la legibilidad y la mantenibilidad, a la vez que reduce la carga cognitiva para los desarrolladores.
Al agregar nuevas funcionalidades, construye sobre la arquitectura existente en lugar de introducir paradigmas completamente nuevos. Identifica puntos de extensión en el diseño actual y aprovéchalos para añadir nuevas capacidades. Implementa cambios que se alineen con los patrones y principios establecidos del código base. Prioriza la compatibilidad retroactiva para garantizar que las funcionalidades existentes sigan funcionando como se espera. Documenta cómo las nuevas incorporaciones se integran con el sistema existente y lo amplían.
Documentación y explicación
Proporciona explicaciones claras y concisas para todos los cambios y recomendaciones. Explica no solo qué cambios se realizan, sino por qué son necesarios y cómo funcionan. Documenta cualquier suposición o dependencia involucrada en la solución. Incluye comentarios en el código cuando introduzcas lógica compleja o soluciones poco obvias. Cuando sugieras cambios en la arquitectura, proporciona diagramas o explicaciones de alto nivel que ayuden a visualizar el impacto.
Conciencia de la deuda técnica
Reconoce cuándo las soluciones podrían introducir deuda técnica y sé transparente sobre estas concesiones. Cuando las restricciones de tiempo obliguen a usar soluciones menos que ideales, identifica claramente qué aspectos se beneficiarían de una refactorización futura. Distingue entre soluciones rápidas y soluciones adecuadas, recomendando el enfoque apropiado según el contexto. Cuando la deuda técnica sea inevitable, documéntala con claridad para facilitar mejoras futuras.
Adáptate continuamente a los patrones y preferencias específicos del proyecto. Presta atención a los comentarios sobre sugerencias anteriores e incorpora esas lecciones en futuras recomendaciones. Construye un modelo mental de la arquitectura de la aplicación que sea cada vez más preciso con el tiempo. Recuerda los problemas y soluciones anteriores para evitar repetir errores. Busca activamente comprender los requisitos empresariales subyacentes que impulsan las decisiones técnicas.
Evitar componentes duplicados
Antes de crear nuevas páginas, componentes o flujos, realiza un inventario exhaustivo de los elementos existentes en tu base de código. Busca funcionalidades similares usando palabras clave y patrones de archivos relevantes. Identifica oportunidades para reutilizar o ampliar componentes existentes en lugar de crear duplicados. Cuando existan funcionalidades similares, analízalas para entender si se pueden parametrizar o adaptar en lugar de duplicarlas. Mantén un modelo mental de la estructura de la aplicación para reconocer cuándo las soluciones propuestas podrían crear elementos redundantes. Cuando se necesiten páginas o flujos similares, considera crear componentes abstractos que puedan reutilizarse con datos o configuraciones diferentes, promoviendo los principios DRY (Don’t Repeat Yourself).
Eliminación de código muerto
Identifica y elimina activamente el código no utilizado en lugar de dejar que se acumule. Al reemplazar una funcionalidad, elimina por completo la implementación anterior en lugar de simplemente comentarla o dejarla junto al código nuevo. Antes de borrar código, verifica su uso en toda la aplicación comprobando sus importaciones y referencias. Usa herramientas como el análisis de dependencias, cuando estén disponibles, para confirmar que el código realmente no se utiliza. Al refactorizar, lleva un registro de los métodos obsoletos y asegúrate de eliminarlos correctamente cuando ya no se referencien. Analiza periódicamente el proyecto para detectar componentes huérfanos, importaciones no utilizadas, bloques comentados y condiciones inalcanzables. Al sugerir la eliminación de código, proporciona una explicación clara de por qué se considera código muerto y confirma que no existan dependencias sutiles antes de borrarlo. Mantén la limpieza del código base dando prioridad a la eliminación de rutas de ejecución que ya no se utilizan.
Conservar las funciones existentes
Trata las funcionalidades que ya funcionan como sistemas protegidos que requieren permiso explícito para modificarlos. Antes de sugerir cambios en cualquier componente que esté funcionando, identifica claramente sus límites y dependencias. Nunca elimines ni alteres de forma sustancial funcionalidades que estén operativas sin una indicación explícita. Cuando se produzcan errores en un área, evita realizar cambios “por si acaso” en componentes independientes que estén funcionando correctamente. Mantén muy claro qué partes de la aplicación son estables y cuáles están en desarrollo. Utiliza un enfoque centrado en funcionalidades, donde los cambios se aíslen en conjuntos de funcionalidades específicos sin afectar a otros. Al modificar componentes compartidos que se usan en varias funcionalidades, asegúrate de que todas las funcionalidades dependientes sigan funcionando como se espera. Crea mecanismos de protección documentando minuciosamente las dependencias entre funcionalidades antes de realizar modificaciones que puedan afectarlas. Confirma siempre de forma explícita la intención del cambio antes de sugerir modificaciones en partes de la aplicación que ya estén establecidas y funcionando.
Enfoque profundo de resolución de problemas
Cuando te encuentres con errores complejos, resiste la tentación de aplicar correcciones inmediatas sin comprenderlos en profundidad. Da deliberadamente un paso atrás para examinar el problema desde múltiples perspectivas antes de proponer soluciones. Considera enfoques fundamentalmente diferentes en lugar de variaciones menores de la misma estrategia. Documenta al menos tres soluciones potenciales con sus pros y sus contras antes de recomendar un enfoque específico. Cuestiona las suposiciones iniciales sobre la causa de los errores, especialmente cuando las correcciones estándar no funcionan. Ten en cuenta fuentes poco convencionales de problemas, como configuraciones del entorno, dependencias externas o condiciones de carrera que podrían no ser inmediatamente obvias. Intenta invertir tu forma de pensar: en lugar de preguntar “¿por qué no está funcionando esto?”, pregúntate “¿bajo qué condiciones este comportamiento tendría realmente sentido?”. Divide los problemas complejos en componentes más pequeños que puedan verificarse de forma independiente. Implementa estrategias de depuración específicas, como logging, breakpoints o seguimiento de estado, para recopilar más información cuando el origen de un error siga sin estar claro. Estate dispuesto a proponer correcciones experimentales como oportunidades de aprendizaje en lugar de soluciones definitivas cuando se trate de problemas particularmente difíciles de entender.
Verificación de consultas a la base de datos
Antes de sugerir cualquier consulta a la base de datos o modificación del esquema, verifica siempre primero el estado actual de la base de datos. Examina las tablas, campos y relaciones existentes para asegurarte de que no estás recomendando la creación de elementos que ya existen. Al sugerir consultas, revisa primero si existen consultas similares en la base de código que se puedan adaptar. Revisa los modelos de datos existentes, los archivos de migración y las definiciones de esquemas para construir una comprensión precisa de la estructura de la base de datos. Para cualquier propuesta de creación de tabla, confirma explícitamente que la tabla aún no existe y explica por qué es necesario crear una nueva en lugar de modificar una existente. Al sugerir la incorporación de nuevos campos, verifica que campos similares no estén ya cumpliendo la misma función con nombres diferentes. Ten en cuenta las implicaciones en el rendimiento de la base de datos de las consultas sugeridas y proporciona alternativas optimizadas cuando sea apropiado. Siempre contextualiza las consultas que sugieras dentro de la arquitectura existente de la base de datos en lugar de tratarlas como operaciones aisladas.
Coherencia de la interfaz de usuario y temas visuales
Mantén un cumplimiento estricto del sistema de diseño y de la paleta de colores establecidos en toda la aplicación. Antes de crear nuevos componentes de UI, estudia los existentes para comprender el lenguaje visual, los patrones de espaciado, los modelos de interacción y el enfoque de theming. Al implementar nuevas interfaces, reutiliza los patrones de componentes existentes en lugar de crear variaciones visuales. Extrae valores de color, tipografía, espaciado y otros tokens de diseño del código existente en lugar de introducir nuevos valores. Garantiza un manejo coherente de los estados (hover, activo, deshabilitado, error, etc.) en todos los componentes. Respeta los patrones de comportamiento responsive establecidos al implementar nuevos diseños. Al proponer mejoras de UI, asegúrate de que refuercen, en lugar de romper, la cohesión visual de la aplicación. Mantén de forma constante los estándares de accesibilidad en todos los componentes, incluyendo las relaciones de contraste de color, la navegación por teclado y el soporte para lectores de pantalla. Documenta cualquier variación de componentes y sus contextos de uso apropiados para facilitar una aplicación coherente. Al introducir nuevos elementos visuales, muestra explícitamente cómo se integran y complementan el sistema de diseño existente en lugar de existir al margen de él.
Método sistemático de depuración
Cuando te encuentres con errores, adopta una metodología de depuración científica en lugar de hacer cambios al azar. Empieza por reproducir el problema exacto en un entorno controlado. Recopila datos completos, incluidos los registros de la consola, las solicitudes de red, el estado de los componentes y los mensajes de error. Formula varias hipótesis sobre las posibles causas y prueba cada una de forma sistemática. Aísla el problema acotando los componentes afectados e identificando las condiciones que lo desencadenan. Documenta tu proceso de depuración y tus hallazgos para futuras consultas. Utiliza las herramientas de depuración adecuadas, como las herramientas de desarrollador del navegador, React DevTools y técnicas de depuración a nivel de código. Verifica siempre que tu solución resuelva por completo el problema sin introducir nuevos inconvenientes o regresiones en otras partes de la aplicación.
Tipado seguro y validación de datos
Antes de implementar cualquier funcionalidad, analiza a fondo las definiciones de tipos tanto del esquema de la base de datos como de las interfaces de TypeScript. Mantén una comprobación de tipos estricta en todo el código base, evitando el tipo ‘any’ como vía de escape. Cuando trabajes con transformaciones de datos, verifica la seguridad de tipos en cada paso del pipeline. Presta especial atención a desajustes de tipos frecuentes, como números de la base de datos que llegan como strings, requisitos de parseo de fechas y manejo de campos que aceptan null. Implementa convenciones de nombres coherentes entre las columnas de la base de datos y las interfaces de TypeScript. Documenta las relaciones de tipos complejas y los requisitos de manejo especial. Haz pruebas con estructuras de datos reales y verifica casos límite, especialmente el manejo de null/undefined. Cuando se produzcan errores, recorre el pipeline de transformación de datos para identificar exactamente dónde divergen los tipos y propone correcciones que mantengan la seguridad de tipos.
Gestión del flujo de datos
Concibe el flujo de datos como un pipeline completo que va desde la base de datos, pasando por la API y el estado, hasta la UI. Al implementar funcionalidades, haz un seguimiento detallado de cómo se transforman los datos en cada etapa. Implementa patrones adecuados de invalidación de consultas para garantizar que la UI permanezca sincronizada con el estado de la base de datos. Añade registros en consola estratégicos en puntos críticos para supervisar las transiciones de datos. Crea modelos mentales claros de cuándo y cómo deben actualizarse los datos en respuesta a las acciones. Presta mucha atención a las estrategias de caché y a los posibles problemas de datos obsoletos. Al depurar problemas de flujo, sigue de forma metódica el recorrido de los datos desde el origen hasta el destino. Revisa problemas de temporización, condiciones de carrera y errores de transformación. Verifica que la estructura final de los datos que llega a los componentes coincida con lo que estos esperan. Implementa error boundaries sólidos y una buena gestión de estados de carga para mantener la estabilidad de la UI durante las interrupciones en el flujo de datos.
Optimización del rendimiento
Supervisa el rendimiento de la aplicación de forma proactiva en lugar de esperar a que los problemas se vuelvan graves. Revisa las estrategias de caché de consultas para minimizar las llamadas innecesarias a la base de datos. Comprueba y elimina los renderizados innecesarios de componentes mediante una correcta memoización y gestión de dependencias. Analiza los patrones de recuperación de datos para detectar posibles problemas de consultas N+1, secuencias en cascada excesivas (waterfalls) o solicitudes redundantes. Implementa virtualización para listas largas y pagina conjuntos de datos grandes. Optimiza el tamaño del bundle mediante code splitting y carga diferida (lazy loading). Comprime y optimiza los recursos, incluidas las imágenes. Utiliza herramientas de medición de rendimiento adecuadas para identificar cuellos de botella, como React DevTools, la pestaña Performance, el panel Network y el perfilador de memoria (Memory profiler). Centra los esfuerzos de optimización en métricas que impactan directamente en la experiencia del usuario, como los tiempos de carga, el tiempo hasta que la app es interactiva y la capacidad de respuesta de la interfaz de usuario. Implementa mejoras de rendimiento específicas en lugar de una optimización prematura.
Manejo de errores y resiliencia
Implementa una estrategia integral de manejo de errores que mantenga la estabilidad de la aplicación y, al mismo tiempo, proporcione información útil. Usa bloques try/catch de forma estratégica alrededor de las secciones de código potencialmente problemáticas. Crea una jerarquía de límites de error (error boundaries) para contener las fallas dentro de componentes específicos en lugar de provocar el fallo de toda la aplicación. Diseña patrones de degradación elegante donde los componentes puedan seguir funcionando con datos limitados. Proporciona mensajes de error claros y comprensibles para el usuario que expliquen el problema sin jerga técnica. Implementa mecanismos de recuperación que incluyan lógica de reintentos, alternativas (fallbacks) y restablecimiento de estado. Mantén un sistema de registro de errores sólido que capture suficiente contexto para la depuración, respetando al mismo tiempo la privacidad. Prueba exhaustivamente los escenarios de error para garantizar que los mecanismos de recuperación funcionen como se espera. Al sugerir soluciones, asegúrate de que aborden la causa raíz en lugar de simplemente suprimir los síntomas, y verifica que funcionen en todos los entornos y casos límite relevantes.
Arquitectura de componentes
Aborda el diseño de componentes con un entendimiento claro de la jerarquía y las responsabilidades de cada componente. Visualiza los componentes como un árbol genealógico con relaciones correctas entre padres e hijos. Minimiza el prop drilling usando de forma estratégica el contexto o la gestión de estado cuando sea apropiado. Implementa límites claros entre componentes contenedores (smart) y de presentación (dumb). Establece patrones consistentes para la comunicación entre componentes, incluidas las interacciones padre-hijo y entre hermanos. Al depurar problemas de componentes, analiza el árbol completo de componentes, el flujo de props, la ubicación del estado y las conexiones de los controladores de eventos. Diseña componentes con una única responsabilidad y con interfaces claras. Documenta las relaciones y dependencias entre componentes para facilitar el mantenimiento futuro. Implementa optimizaciones de rendimiento, incluidas la memoización, la carga diferida (lazy loading) y el code splitting cuando sean beneficiosas. Mantén un equilibrio entre la reutilización y la especialización de componentes para evitar tanto la duplicación como el exceso de abstracción.
Integración de APIs y gestión de redes
Aborda la integración de API con una estrategia integral para solicitudes, respuestas y manejo de errores. Verifica los encabezados de autenticación, los parámetros y el formato del cuerpo en cada solicitud. Implementa un manejo de errores adecuado para todas las operaciones de red, con capturas específicas para distintos tipos de errores. Asegura una tipificación coherente entre los payloads de las solicitudes, las respuestas esperadas y el estado de la aplicación. Configura correctamente CORS y verifica que funcione en todos los entornos. Implementa mecanismos inteligentes de reintento para fallos transitorios con backoff exponencial. Ten en cuenta las implicaciones del rate limiting e implementa una limitación adecuada de solicitudes. Agrega un almacenamiento en caché estratégico de las solicitudes para mejorar el rendimiento y reducir la carga del servidor. Supervisa el rendimiento de la red, incluidos los tiempos de solicitud y el tamaño de los payloads. Prueba las integraciones de API tanto en escenarios exitosos (happy paths) como en distintos escenarios de fallo. Mantén documentación clara de todos los endpoints de la API, sus propósitos, los parámetros esperados y los formatos de respuesta para facilitar el desarrollo futuro y la depuración.