Del caso límite en C++ a una consulta SQL
Por JR, creador de Telemetry.
Un programa puede dar una cifra razonable y seguir tomando decisiones equivocadas. En este ejercicio vamos a provocar un fallo pequeño en C++, conservar las entradas y salidas de cada decisión y localizarlo con SQL. Todos los datos son ficticios. El ejemplo se ejecuta localmente, sin cuentas ni servicios externos.
La regla antes que el código
Imaginemos que asignamos un grupo a un aula. La regla es sencilla: aceptamos el grupo cuando el número de alumnos es menor o igual que las plazas libres. Para mantener el ejercicio acotado, suponemos números enteros positivos y una sola decisión cada vez; no hay reservas simultáneas.
Vamos a comprobar cuatro casos. Antes de ejecutar el programa, intenta decidir cuáles deberían aceptarse:
| Caso | Plazas libres | Alumnos | Decisión esperada |
|---|---|---|---|
| a | 4 | 3 | Aceptar |
| b | 4 | 4 | Aceptar |
| c | 4 | 5 | Rechazar |
| d | 1 | 1 | Aceptar |
Los casos b y d están justo en el límite. Si solo probásemos grupos más pequeños o más grandes que el aula, no distinguiríamos entre estas dos expresiones:
plazas > grupo // Falla cuando ambos valores son iguales. plazas >= grupo // Coincide con la regla de este ejercicio.
Registrar una decisión, no solo un total
El archivo `ejemplo.cpp` ejecuta los mismos cuatro casos con ambas expresiones. La versión v1 contiene el fallo y v2 lo corrige. Emite ocho objetos JSON, uno por decisión, con estos campos:
- `event_id`: identificador único dentro del ejemplo, como `v1-b`.
- `version` y `caso`: permiten comparar exactamente las mismas entradas.
- `plazas_libres` y `alumnos`: las entradas utilizadas para decidir.
- `aceptado`: resultado observado, 1 para aceptar y 0 para rechazar.
La función que queremos comprobar es:
bool admite(int plazas, int grupo, bool corregido) {
return corregido ? plazas >= grupo : plazas > grupo;
}
La condición `corregido` sirve para reunir las dos versiones en un único programa didáctico. No sería una buena forma de mantener un fallo conocido en una aplicación real.
Compila y ejecuta el archivo con un compilador compatible con C++17:
c++ -std=c++17 -Wall -Wextra -pedantic ejemplo.cpp -o ejemplo ./ejemplo > eventos.json
Estos comandos utilizan una terminal de macOS o Linux; en otros entornos puede cambiar la forma de ejecutar el binario. El archivo JSON es la salida del programa, no una lista de resultados escrita a mano.
En v1 se acepta uno de los cuatro grupos; en v2, tres. Ese resumen revela una diferencia, pero no explica qué ocurrió. Conservar las entradas junto a la decisión permite descubrir que ambos rechazos incorrectos corresponden a grupos que caben exactamente.
Consultar los eventos con SQLite
El archivo `comprobar.py` usa únicamente la biblioteca estándar de Python 3. Lee `eventos.json`, crea una base SQLite en memoria e inserta los ocho eventos mediante parámetros. No construye instrucciones SQL concatenando los valores del JSON. La clave primaria impide cargar dos veces el mismo identificador en esta tabla.
Guarda `comprobar.py` y `consulta.sql` junto a `eventos.json` y ejecuta:
python3 comprobar.py
La consulta busca decisiones que no coinciden con la regla:
SELECT version, caso, plazas_libres, alumnos, aceptado FROM depuracion_aula WHERE aceptado <> CASE WHEN plazas_libres >= alumnos THEN 1 ELSE 0 END ORDER BY version, caso;
`CASE` calcula la decisión esperada a partir de las entradas; `<>` selecciona las filas donde el resultado observado es distinto. No preguntamos simplemente qué grupos fueron rechazados: el caso c debe rechazarse y, por tanto, no debe aparecer como error.
El resultado esperado es:
version caso plazas_libres alumnos aceptado v1 b 4 4 0 v1 d 1 1 0
La comprobación también exige ocho eventos. Si el programa deja de emitir un caso, no basta con que la consulta devuelva cero discrepancias: quizá falten observaciones. Con este conjunto conocido verificamos tanto el número de decisiones como los errores concretos.
Qué hemos demostrado y qué queda fuera
Para estas cuatro entradas, v2 coincide con la regla y v1 falla en dos casos de igualdad. Esto no demuestra la corrección de un sistema de reservas completo. No hemos comprobado entradas negativas, límites del tipo entero ni dos solicitudes que intentan ocupar las mismas plazas al mismo tiempo.
Tampoco hemos medido una mejora de rendimiento, una tasa de éxito real ni resultados de aprendizaje en un aula. Los datos fueron elegidos para hacer visible un error lógico. Antes de generalizar, hay que ampliar el contrato y las pruebas.
Como continuación, prueba estas preguntas:
- ¿Qué debería ocurrir si el grupo tiene cero alumnos? Define la regla antes de añadir el caso.
- Si eliminas uno de los eventos, ¿por qué una consulta sin discrepancias no garantiza que todo esté bien?
- ¿Qué dato faltaría para estudiar reservas simultáneas? ¿Puede resolverlo por sí sola una consulta realizada después de los hechos?
De la prueba local a una aplicación
La idea reutilizable es conservar suficiente contexto para contrastar una decisión con su regla: qué entró, qué salió y qué versión del código actuó. SQL ayuda a comparar muchas decisiones, pero no sustituye las pruebas ni recupera eventos que nunca se registraron.
Soy el creador de Telemetry, un servicio para enviar eventos de aplicaciones y consultarlos con SQL. Este ejercicio muestra el razonamiento de forma independiente con SQLite; no requiere utilizar Telemetry y no incluye una integración alojada. En una aplicación instrumentada, el siguiente paso sería definir qué eventos se necesitan y comprobar su envío antes de analizar resultados entre versiones.
Materiales del artículo: `ejemplo.cpp`, `consulta.sql` y `comprobar.py`. El JSON se genera al ejecutar el programa C++. El código y el texto son originales de esta contribución.
| Nombre | Fichero | Fecha | Tamaño | Contador | Descarga |
|---|---|---|---|---|---|
| Materiales | limite.zip | 2026-09-21 | 1819 bytes | 19 |