Registro de progreso del estudiante#
Este documento es una bitácora empírica de auditoría personal, no una lista cosmética de tareas pendientes. Su propósito es certificar la adquisición de competencias técnicas mediante evidencia observable y verificable.
Márcala únicamente cuando hayas producido tus propios resultados en la terminal, puedas explicar los mecanismos causales subyacentes y hayas superado la prueba de falsación mínima de cada tema. Leer pasivamente una lección o ver compilar un ejemplo sin entenderlo no cumple el criterio de salida.
Para preparar tu entorno de trabajo local aislado en Windows, consulta la guía de laboratorios en Windows. Para definiciones rigurosas de términos técnicos, apóyate en el glosario y diccionario técnico.
Mini-glosario de verificación y evidencia#
Antes de registrar cualquier avance en esta bitácora, debes dominar y aplicar estos cuatro conceptos metodológicos esenciales:
1. Evidencia observable#
- Intuición cotidiana: Una fotografía nítida de un velocímetro marcando 120 km/h en un tramo específico de autopista, en lugar de un conductor diciendo "me parece que iba rápido".
- Definición técnica precisa: Datos empíricos, medibles y reproducibles generados directamente por una herramienta de desarrollo o por el sistema operativo. Incluye mensajes de diagnóstico del compilador con códigos de error y números de línea exactos, resultados de suites de prueba con aserciones aprobadas o fallidas, códigos de retorno de procesos (
$LASTEXITCODE), volcados de tráfico de red (HTTP status, headers y body) o registros estructurados con marcas temporales. - Ejemplo en el sistema:
# Observable evidence: The compiler halts with error E0382 due to a move violation.
rustc --test .\borrow_check.rs
# Output: error[E0382]: borrow of moved value: `entry_title`
- Lo que NO es: No es la sensación subjetiva de "haber entendido el concepto", ni el recuerdo vago de haber leído el capítulo, ni la afirmación "el código corrió sin problemas" sin adjuntar la salida del comando.
2. Prueba de falsación mínima#
- Intuición cotidiana: Probar la resistencia de un candado no jalándolo suavemente hacia donde sabemos que traba, sino aplicando una palanca en el punto más vulnerable para ver si realmente resiste la intrusión.
- Definición técnica precisa: El experimento reproducible más pequeño posible diseñado específicamente para refutar una hipótesis sobre el comportamiento del sistema. Consiste en alterar deliberadamente un supuesto, un dato de entrada o un invariante para verificar si el compilador, el arnés de pruebas o el mecanismo de validación detecta y rechaza con exactitud la transgresión prevista.
- Ejemplo en código:
// Hypothesis: NonEmptyTitle rejects blank strings.
// Falsification test: Pass whitespace-only input and assert it returns Err.
#[test]
fn rejects_whitespace_only_title() {
let result = NonEmptyTitle::parse(" ".to_string());
assert!(result.is_err(), "Expected whitespace-only title to be rejected");
}
- Lo que NO es: No es una prueba tautológica que simplemente reproduce el camino feliz (happy path) que ya sabemos que funciona. Si la prueba no tiene la capacidad de fallar cuando la regla se rompe, carece de valor científico.
3. Fallo de concurrencia: Data Race frente a Condición de Carrera Lógica (Race Condition)#
- Intuición cotidiana:
- Data race: Dos personas intentando escribir simultáneamente con bolígrafos diferentes en el mismo milímetro cuadrado de una hoja de papel, emborronando la tinta y rompiendo el papel.
- Condición de carrera lógica: Dos personas que retiran legalmente dinero del mismo cajero con tarjetas asociadas a la misma cuenta en el mismo segundo; ninguna máquina se rompe, pero el saldo final queda en números rojos porque la cuenta no se bloqueó durante la consulta y el retiro.
- Definición técnica precisa:
- Data race (Carrera de datos a nivel de memoria): Ocurre cuando dos o más punteros en hilos distintos acceden simultáneamente a la misma posición física de memoria, al menos uno de ellos es una escritura, y no existe sincronización atómica o de exclusión mutua. En Rust seguro (safe Rust), el sistema de tipos y préstamos (
SendySync) previene matemáticamente las data races en tiempo de compilación. - Race condition (Condición de carrera lógica): Ocurre cuando la corrección de una secuencia de operaciones de alto nivel depende del orden temporal relativo o del entrelazado de eventos concurrentes, incluso si la memoria no se corrompe.
- Ejemplo en el sistema:
- En Rust no seguro o C++, un data race causa corrupción de punteros y comportamiento indefinido (Undefined Behavior).
- En un servicio web con base de datos, un check-then-act sin transacciones serializables permite que dos solicitudes
POST /reserveconcurrentes lean que hay 1 asiento disponible y ambas confirmen la reserva, sobrevenciendo la capacidad del evento (condición de carrera lógica). - Lo que NO es: No son sinónimos. Un sistema escrito en Rust seguro está 100% libre de data races en memoria, pero sigue siendo totalmente susceptible a condiciones de carrera lógicas en su base de datos o en su lógica de negocio si no utiliza bloqueos o transacciones adecuadas.
4. Refactorización que preserva el comportamiento#
- Intuición cotidiana: Sustituir el motor de combustión de un barco por un motor híbrido con el barco atracado en el muelle, garantizando que el timón, la velocidad de crucero, los mandos del capitán y la capacidad de carga se mantengan idénticos a los del diseño original.
- Definición técnica precisa: Transformación controlada de la estructura interna del código (extracción de funciones, desacoplamiento de módulos, renombramiento semántico, optimización de algoritmos locales) que no altera en lo absoluto el comportamiento observable externo del componente. Esta preservación se demuestra empíricamente ejecutando la misma suite exhaustiva de pruebas antes y después de la modificación, manteniéndose todas en verde.
- Ejemplo en el sistema: Cambiar un bucle manual con índices por un iterador funcional en Rust (
collection.into_iter().filter(...).collect()), verificando que los mismos casos de prueba unitaria compilan y producen resultados idénticos byte a byte. - Lo que NO es: No es agregar nuevas validaciones no solicitadas, ni modificar los códigos de error HTTP de una API existente, ni "aprovechar para arreglar otro problema". Si el comportamiento externo cambia en un solo detalle, no fue una refactorización: fue un cambio funcional o la introducción de una incompatibilidad regresiva.
Lista de verificación de criterios de salida por lección#
Marca cada casilla únicamente cuando hayas ejecutado la práctica correspondiente en tu laboratorio privado, verificado el resultado esperado y formulado una explicación causal en tus propias palabras.
Módulo 00 · Inicio y método#
- 00 Método y laboratorio: Verifiqué la disponibilidad de mis herramientas locales (
rustc,node), comprendí que el curso no instala software comercial ni aplicaciones SaaS, y ejecuté con éxito la prueba mínima conrustc --test.
Módulo 01 · Fundamentos de Rust#
- 01 Tipos y flujo: Distingo tipos primitivos escalares y compuestos, explico cómo se representan en la pila (stack), y predigo el flujo de control sin depender del compilador.
- 02 Ownership y préstamos: Explico las reglas de propiedad única, la diferencia entre movimiento (move) y copia (copy), y demuestro por qué el compilador prohíbe tener múltiples referencias mutables o mezclar referencias inmutables con mutables.
- 03 Modelado de errores y pruebas: Utilizo
ResultyOptionpara modelar fallos sin invocarunwrap(), entiendo el papel de la macropanic!, y diseño pruebas unitarias que falsan el comportamiento en rojo antes de escribir el código verde. - 04 Colecciones e iteración: Diferencio la semántica de memoria entre un array de tamaño fijo en la pila y un
Vec<T>en el heap, y utilizo iteradores consumiendo referencias o valores sin duplicaciones accidentales de memoria.
Módulo 02 · Backend y contratos#
- 05 Contratos HTTP: Diseño endpoints REST con métodos, cabeceras y códigos de estado semánticos exactos, y defino esquemas JSON que validan entradas en el límite de la red.
- 06 Límites con Actix: Construyo un servicio web básico con Actix Web, separando el handler de transporte de la lógica de dominio interna mediante tipos fuertemente tipados.
- 07 Invariantes PostgreSQL: Modela tablas relacionales con restricciones
CHECK, claves foráneas y tipos precisos, explicando cómo una transacción ACID garantiza consistencia ante fallos del proceso. - 08 Async y concurrencia: Explico cómo opera un ejecutor de tareas asíncronas (
tokio), qué significa que unFuturesea evaluado mediante sondeo perezoso (polling), y distingo un bloqueo de CPU no cooperativo de una espera asíncrona de I/O.
Módulo 03 · Navegador y frontend#
- 09 HTML, CSS y accesibilidad: Construyo interfaces con marcado semántico nativo, atributos ARIA adecuados y navegación funcional por teclado sin depender de JavaScript para lo estructural.
- 10 TypeScript y DOM: Configuro el compilador de TypeScript con banderas estrictas, realizo narrowing de tipos con
instanceofpara manipular nodos del DOM y controlo eventos sin fugas de memoria. - 11 Estado en React: Modelo el estado local y componentes puros respetando la inmutabilidad, explico el ciclo de reconciliación y evito efectos secundarios descontrolados en hooks.
- 12 Integración full stack: Conecto cliente web y servidor backend mediante solicitudes HTTP tipadas, manejando estados de carga, desconexión y errores de red en la interfaz.
Módulo 04 · Diseño y arquitectura#
- 13 Code smells y refactorización: Identifico síntomas de acoplamiento, duplicación o complejidad ciclomática excesiva, y aplico refactorizaciones controladas que preservan el comportamiento.
- 14 Límites y dependencias: Aplico el principio de inversión de dependencias desacoplando la lógica central del dominio de los adaptadores de base de datos y de red.
- 15 Pruebas y depuración: Implemento la pirámide de pruebas (unitarias, de integración y de contrato), depuro fallos con trazas reproducibles y aíslo causas raíz sin ensayo y error.
Módulo 05 · Operación y diagnóstico#
- 16 Autenticación y autorización: Implemento autenticación mediante tokens criptográficos o sesiones seguras, establezco control de acceso basado en roles y protejo contraseñas con funciones de derivación de claves (hashing robusto con sal).
- 17 Entrega y observabilidad: Empaqueto el binario de forma determinista, configuro instrumentación estructurada con identificadores de traza (trace IDs) y defino métricas clave de salud del sistema.
- 18 Diagnóstico full stack: Resuelvo un incidente simulado de extremo a extremo, siguiendo el rastro del fallo desde una anomalía en la interfaz web hasta un cuello de botella o error en la persistencia.
Evidencia empírica por lección (Bitácora de experimentos)#
Completa las filas de esta tabla a medida que ejecutes cada lección en tu laboratorio personal:
| Lección | Predicción antes de ejecutar | Evidencia observable (compilador, test, log, inspección) | Conceptos del glosario explicados con mis propias palabras | Duda conceptual abierta / Siguiente experimento de falsación |
|---|---|---|---|---|
| 00 Inicio | Ej: rustc --test .\sample.rs compilará sin red y emitirá 1 test aprobado. | Ej: test adds_two_numbers ... ok. test result: ok. 1 passed; 0 failed. | Arnés de prueba, compilación local, estándar. | ¿Qué pasa si elimino la directiva #[test] del archivo? |
| 01 Tipos y flujo | ||||
| 02 Ownership | ||||
| 03 Errores y pruebas | ||||
| 04 Colecciones | ||||
| 05 Contratos HTTP | ||||
| 06 Límites Actix | ||||
| 07 Invariantes Postgres | ||||
| 08 Async y concurrencia | ||||
| 09 HTML/CSS/A11y | ||||
| 10 TypeScript y DOM | ||||
| 11 Estado React | ||||
| 12 Integración E2E | ||||
| 13 Refactorización | ||||
| 14 Límites y dependencias | ||||
| 15 Testing y depuración | ||||
| 16 Autenticación/Permisos | ||||
| 17 Observabilidad | ||||
| 18 Diagnóstico integral |
Protocolo de verificación: ¿Cómo saber si realmente entendiste un mecanismo?#
Es muy fácil caer en la trampa del sesgo de reconocimiento: leer un código bien documentado, asentir con la cabeza porque "tiene sentido" y creer falsamente que uno domina el concepto. Para auditar tu verdadero nivel de comprensión y no engañarte a ti mismo, aplica estos cuatro criterios de verificación antes de marcar cualquier lección como completada:
Criterio 1: El experimento de mutación destructiva deliberada#
- En qué consiste: Toma el código que acabas de hacer funcionar y rompe deliberadamente una de sus premisas fundamentales (por ejemplo, cambia un préstamo inmutable por un movimiento de variable, elimina una transacción SQL antes de un fallo simulado o remueve un tipo guard en TypeScript).
- Prueba de fuego: Antes de pulsar Enter en tu terminal, escribe en una hoja o di en voz alta el error exacto que producirá la herramienta (código de error, línea implicada y explicación técnica).
- Diagnóstico: Si el error producido coincide exactamente con tu predicción, tu modelo mental está alineado con la realidad del compilador o runtime. Si el error te toma por sorpresa o el programa sigue pasando en silencio, tu comprensión contiene lagunas críticas.
Criterio 2: Explicación causal a nivel de hardware y memoria (sin jerga vacía)#
- En qué consiste: Explica qué hace el programa sin usar palabras cliché como "magia de Rust", "se gestiona solo" o "lo hace por debajo".
- Prueba de fuego: Describe exactamente qué sucede en términos físicos:
- ¿Dónde residen los bytes de este dato: en la trama de la pila (stack frame), en la memoria dinámica (heap) o en la sección de datos estáticos del binario?
- ¿Cuántos bytes ocupa esta variable en la pila (puntero + longitud + capacidad = 24 bytes en sistemas de 64 bits)?
- ¿En qué instrucción exacta del ensamblador o en qué llave de cierre (
}) se invoca el desasignador de memoria (drop)? - Diagnóstico: Si solo puedes repetir términos prestados de la documentación oficial pero no puedes dibujar las cajitas de memoria y las flechas de los punteros en una hoja de papel, has memorizado vocabulario, no el mecanismo.
Criterio 3: Reconstrucción desde una hoja en blanco#
- En qué consiste: Cierra todos los archivos del curso, apaga el autocompletado inteligente de tu editor, bloquea el acceso al chat de IA y abre un archivo completamente vacío en un directorio temporal.
- Prueba de fuego: Implementa desde cero la estructura de datos o el contrato de la lección (por ejemplo, un enum con variantes de error, una función de parsing de invariantes y una prueba unitaria).
- Diagnóstico: Si no puedes empezar sin copiar el armazón de otro archivo, dependes de muletas externas. La capacidad de escribir el esqueleto mínimo y compilarlo a la primera demuestra que las reglas de diseño se han incorporado a tu memoria de trabajo a largo plazo.
Criterio 4: Diseño de pruebas adversas en las fronteras#
- En qué consiste: Someter el componente a entradas no cooperativas y casos borde que no aparecían en el enunciado original.
- Prueba de fuego: Diseña pruebas unitarias que suministren:
- Cadenas vacías, cadenas con espacios en blanco invisibles o secuencias de escape no imprimibles.
- Cargas numéricas desbordadas (números negativos donde se esperan enteros sin signo, o valores mayores a 2³²-1).
- Cortes de conexión en medio de una transmisión de red o errores de I/O en la persistencia.
- Diagnóstico: Si tu diseño solo contempla el "camino feliz" y entra en pánico (panic!) o produce inconsistencias al recibir entradas adversas, el sistema no está protegido por contratos firmes ni invariantes bien concebidos.