Buscar/Cambiar el código de una base de datos de alto rendimiento sin perder velocidad ni compatibilidad

Cambiar el código de una base de datos de alto rendimiento sin perder velocidad ni compatibilidad

Úsala cuando una IA modifique una base de datos centrada en la velocidad que abarca Java, SQL, Rust, código nativo y CI. Da reglas de estilo, NULL, limpieza de memoria, pruebas de queries, fallos, pull requests y build, y cierra con una revisión antes de dar el trabajo por terminado.

Para usar estas reglas de IA
## Mantener separados los módulos de la base de datos y proteger las rutas de datos sin asignaciones - Conserva límites explícitos entre los módulos del motor de almacenamiento, motor SQL, protocolos de red, utilidades, colas de workers, logging, tareas en segundo plano, benchmarks, pruebas de compatibilidad y ejemplos. - Mantén el código de producción separado de benchmarks, utilidades de build, ejemplos y wrappers de plataforma. - Trata un repositorio de cliente anidado o submódulo como repositorio independiente, con sus propios commits y objetivo de compatibilidad. - Identifica el punto de entrada correcto antes de cambiar el comportamiento: arranque del servidor, motor de almacenamiento, compilador SQL, lector de tablas o escritor de tablas. - Protege las rutas de datos sin asignaciones durante la ejecución de queries y la ingesta. - Prefiere pools de objetos, buffers reutilizables, almacenamiento por columnas, ejecución vectorizada y aceleración nativa cuando la arquitectura lo exija. - No introduzcas dependencias de ejecución de terceros cuando el proyecto implemente internamente algoritmos críticos para el rendimiento. - Limita el código nativo a operaciones que justifiquen sus riesgos de memoria, plataforma y fallos. ## Ordenar los miembros de las clases Java y mantener la compatibilidad con clientes Java antiguos - Agrupa los miembros de clase por tipo static o instance y visibilidad, y ordénalos alfabéticamente dentro de cada grupo. - Inserta los campos y métodos nuevos en su posición ordenada correcta en vez de crear grupos decorativos por secciones. - Nunca añadas comentarios banner como encabezados artificiales de sección en Java. - Usa las funciones modernas del lenguaje compatibles con el módulo principal, como switches mejorados, strings multilínea y variables de patrón. - Respeta objetivos de lenguaje anteriores en módulos de compatibilidad; no dejes que la sintaxis del módulo principal se filtre a un cliente orientado a una versión anterior de Java. - Antepon `is` o `has`, según corresponda, a variables, campos y métodos booleanos. - Mantén los mensajes de log estrictamente en ASCII cuando el pipeline de logging no pueda representar de forma fiable puntuación o símbolos Unicode. - Usa los tipos de colección del proyecto conscientes de los recursos en lugar de arrays de objetos genéricos cuando se integren con las utilidades de limpieza establecidas. - Sigue los patrones existentes de nombres, propiedad y asignación antes de introducir una abstracción nueva. ## Decidir el manejo de NULL y liberar la memoria en cada ruta de error - Decide explícitamente el comportamiento de NULL para datos de columnas, resultados de expresiones, sentencias SQL y estados intermedios. - Distingue un sentinel NULL que signifique «todavía no inicializado» de un NULL real de datos. - Sigue cada asignación y recurso cerrable por las rutas de éxito, error, cancelación y retorno temprano. - Usa sistemáticamente los helpers de limpieza del repositorio para listas y elementos cerrables. - Trata la prevención de fugas como requisito de diseño, no como una preocupación exclusiva de las pruebas. - Añade aserciones de fugas de memoria a las pruebas que asignen memoria nativa. - Las pruebas unitarias estrechas que demuestren no asignar memoria nativa pueden omitir el harness de fugas. - Verifica la limpieza en todas las rutas de error pertinentes, no solo en la ruta de éxito. - Nunca ocultes una ambigüedad de propiedad detrás de un container o helper cómodo. ## Probar las queries con aserciones estrictas que releen los resultados - Prefiere el framework fluido canónico de aserciones de queries frente a helpers antiguos de impresión y comparación en una sola pasada. - Para queries deterministas, exige una segunda pasada del cursor, comprobaciones cruzadas de tamaño, comprobaciones de columnas variables y las aserciones pertinentes de propiedades de factory. - Usa una aserción de una sola pasada únicamente cuando la projection sea realmente inestable entre relecturas, e indica el motivo. - Entre los casos de inestabilidad válidos están las funciones aleatorias sin seed y las funciones que varían con el tiempo. - Ejecuta DDL y otras sentencias que no sean queries mediante la ruta de ejecución para no-queries. - Comprueba los planes de ejecución con los helpers de plan del framework cuando el comportamiento del optimizador forme parte del contrato. - Usa una sola sentencia INSERT para varias filas de prueba cuando el dialecto lo admita. - Usa strings multilínea para SQL largo y resultados esperados de varias líneas. - Escribe las palabras clave SQL de forma coherente, preferiblemente en uppercase. - Separa los millares con underscores en literales de 5 o más dígitos cuando la sintaxis lo admita. ## Seguir el dialecto SQL y señalar el carácter exacto del error - Trata los tipos de arrays multidimensionales como tipos distintos cuando la dimensionalidad esté codificada en el tipo de columna. - Usa sistemáticamente la sintaxis de cast preferida por el dialecto en vez de mezclar formas equivalentes. - Mantén sincronizada la compatibilidad con separadores numéricos entre el parser, el código de implementación y las pruebas. - No des por hecho que existen funciones estándar de SQL; documenta y prueba las operaciones no compatibles. - Cuando no se admita la eliminación de filas, modela explícitamente la eliminación lógica en la lógica de aplicación. - Mantén las operaciones de drop a nivel de partición separadas de la eliminación a nivel de fila porque difieren en alcance y seguridad. - Sitúa la posición de un error SQL en el carácter exacto que lo causa, no solo al inicio de la expresión. - Prueba los errores del parser tanto por el mensaje como por la posición exacta. - Conserva la diferencia entre errores de sintaxis, semántica, tipo y ejecución. ## Tratar cada prueba fallida como un defecto real hasta que las evidencias digan lo contrario - Trata cada prueba roja, trabajo de CI fallido y entrada de log inesperada como defecto activo hasta que la evidencia demuestre lo contrario. - «Preexistente», «flaky», «no relacionado» y «problema conocido» son hipótesis, no conclusiones. - Reproduce en la baseline pertinente, inspecciona el historial de versiones, mide las restricciones temporales y revisa informes upstream autoritativos. - Aparta un fallo únicamente después de que la evidencia obligue a esa conclusión. - Informa de la evidencia que justificó la clasificación para que otro reviewer pueda verificarla. - No uses una repetición en verde como única prueba de que un fallo era inocuo. - Investiga fallos de interacción cuando varias modificaciones compartan el mismo linaje de CI. - Conserva los logs, inputs fallidos y la menor reproducción fiable necesarios para el diagnóstico. - Limita la corrección a la causa demostrada y añade una prueba de regresión que falle sin ella. ## Adaptar branches y pull requests al tipo de merge y al coste de CI - Ajusta la estrategia de branch y pull request al modelo de merge y al coste de CI del repositorio. - En un flujo squash-merge, no dediques esfuerzo a pulir el historial desechable de una branch. - Añade un commit de corrección claro en lugar de reescribir commits anteriores o hacer force-push solo por estética del historial. - Agrupa las correcciones relacionadas cuando dividirlas multiplicaría las ejecuciones largas de CI, la exposición a flakes y la coordinación del merge. - Divide los cambios solo cuando el usuario lo solicite o cuando deban poder hacerse merge o revert de forma independiente. - Al actualizar un pull request existente, sincroniza con su head remoto, añade los cambios a esa branch y actualiza sus metadatos. - No abras un segundo pull request únicamente para volver a ejecutar la validación del mismo linaje de cambios. - No crees worktrees ni branches de checkout para revisar cuando la política del repositorio defina otra branch como estado canónico de revisión. - Obtén el diff de un pull request sin cambiar de branch cuando solo necesites el diff. - Haz commit primero dentro del repositorio anidado antes de registrar el pointer del submódulo en el parent. ## Escribir pull requests y commits que cuenten por igual las ventajas y los inconvenientes - Usa la convención exigida para títulos de pull requests y haz que la descripción resulte significativa para usuarios finales. - Describe con la misma prominencia efectos positivos, efectos negativos, regresiones y tradeoffs. - Evita lenguaje comercial, superlativos, métricas selectivas y énfasis decorativo. - Referencia un issue corregido con la forma de cierre requerida al principio del cuerpo del pull request. - Mantén los títulos de commit breves, descriptivos y con el estilo exigido por el repositorio. - Incluye un cuerpo de commit sustancial que explique el cambio, en lugar de repetir el título. - Usa bullets sencillos en los planes de prueba cuando se prohíban checkboxes o marcas de verificación. - Aplica labels que correspondan al dominio y al título del cambio. - Usa voz activa en commits, pull requests y comentarios de código. - Nombra la clase, método, caller o componente que actúa en vez de ocultarlo en construcciones pasivas. ## Comprobar el entorno y luego hacer build y pruebas desde el alcance más pequeño - Verifica el runtime del lenguaje, la herramienta de build, la arquitectura y las variables de entorno requeridas antes de compilar. - Elige el perfil de build más pequeño que demuestre el cambio actual y usa perfiles más completos cuando se vean afectados artefactos web o nativos. - Vuelve a compilar módulos dependientes cuando un cache local de artefactos pueda contener un cliente o biblioteca desactualizados. - Ejecuta secuencialmente las invocaciones de pruebas costosas cuando los builds paralelos interfieran entre sí. - Empieza por la clase o método de prueba pertinente más estrecho y amplía según el riesgo y la política del repositorio. - No trates la compilación por sí sola como prueba del comportamiento de ejecución. - Valida el servidor mediante la ruta de arranque compatible e inspecciona el endpoint o la interfaz directamente afectados. - Mantén los artefactos de build en las ubicaciones designadas y propiedad de cada módulo. - Registra el comando exacto que falló y el primer error accionable cuando se detenga un build. ## Eliminar las advertencias de Rust y evitar que un panic tumbe la JVM a través de JNI - Antes de completar trabajo en Rust, ejecuta formateo, compilación de todos los targets, lint y pruebas de biblioteca desde la raíz del crate. - Exige cero errores y cero warnings en todas las comprobaciones obligatorias. - Mide la cobertura después de añadir o modificar pruebas. - Para cada línea sin cobertura, añade una prueba o demuestra que es inalcanzable y marca explícitamente esa invariante. - Nunca llames a `unwrap()` ni `expect()` con datos derivados de archivos o inputs externos. - Propaga los fallos recuperables mediante `Result`, `Option` y la propagación de errores estándar del lenguaje. - Recuerda que un panic de Rust que cruce JNI puede abortar toda la JVM sin recuperación. - Compila las bibliotecas nativas C y C++ con la configuración de release del repositorio y verifica los artefactos esperados. - Trata la propiedad, vida útil, alineación y conversión de errores de FFI como contratos explícitos. - Prueba los fallos de límites en cada plataforma compatible afectada por el cambio. ## Evitar asignaciones en el heap y medir la mejora de velocidad con benchmarks - Evita asignaciones en el heap en rutas de datos donde el comportamiento zero-GC sea un requisito arquitectónico. - Reutiliza buffers y objetos en pools, y explicita la transferencia de propiedad. - Almacena los datos analíticos por columnas cuando la compresión y las operaciones vectorizadas dependan de esa disposición. - Mantén SIMD, la gestión de memoria y las optimizaciones específicas de plataforma detrás de límites nativos estrechos. - Separa almacenamiento, parsing, planificación, generación de código, ejecución, gestión de protocolos y trabajo en segundo plano. - Usa colecciones personalizadas solo cuando su comportamiento de asignación y limpieza se comprenda y esté probado. - Mide los cambios de rendimiento con benchmarks representativos, no por intuición. - Acompaña una optimización con pruebas de corrección, comprobaciones de recursos y un tradeoff documentado. - No debilites la compatibilidad ni la precisión de errores para obtener una mejora de velocidad no medida. ## Revisar el diff final e informar de los resultados antes de dar el trabajo por terminado - Revisa el diff final para comprobar el orden de miembros, los límites de compatibilidad, el comportamiento de NULL, la propiedad de recursos y Unicode accidental en los logs. - Ejecuta las comprobaciones de Java, SQL, Rust, código nativo e integración afectadas por el cambio. - Confirma que las queries deterministas usen la ruta fuerte de aserción con relectura. - Confirma que inputs externos no puedan provocar un panic nativo irrecuperable. - Verifica que cada fallo investigado tenga una clasificación respaldada por evidencia y una reproducción informada. - Asegúrate de que los metadatos del pull request, labels, plan de pruebas, texto de commits y referencias a issues cumplan la política del repositorio. - Verifica que los repositorios anidados y los pointers del parent se hayan registrado en el orden correcto. - No declares la finalización mientras las comprobaciones obligatorias tengan errores o warnings. - Informa de los comandos ejecutados, resultados observados, riesgos restantes y alcance no probado intencionadamente.