Anexo H · Guion de Defensa Oral

Aprende → Publica → Defiende

El método más efectivo para un curso intensivo, explicado y ensayado unidad por unidad.

Esta guía no repite el temario: te dice exactamente qué vas a decir y en qué orden cuando llegue el momento de defender tu proyecto frente al docente. Cada Unidad trae un ejemplo real, tomado de tu propio proyecto integrador, con un guion palabra por palabra que puedes practicar en voz alta hasta que te salga natural.

1 · Aprende

Entiendes el concepto de la semana con un ejemplo mínimo, no memorizas código.

2 · Publica

Subes ese avance a producción (Render + MySQL). Si no está publicado, no cuenta.

3 · Defiende

Explicas en voz alta, con tus palabras, qué hiciste y por qué. Aquí se nota quién entendió.

El método

¿Por qué este método es el más efectivo en 8 semanas?

En un curso intensivo no alcanza el tiempo para "ver todo y luego practicar". Por eso el ciclo se repite completo cada 2 semanas, en dosis pequeñas: aprendes lo mínimo necesario para avanzar, publicas de inmediato para que el avance sea real y verificable, y defiendes en voz alta para que el conocimiento se quede contigo y no solo en el código. Repetir este ciclo 4 veces (una por Unidad) es lo que te prepara, sin darte cuenta, para la defensa final de la Unidad 4.

Aprender sin publicar

Se te olvida en una semana porque nunca lo defendiste ni lo viste "vivo" en internet.

Publicar sin defender

Puedes tener código que ni tú mismo entiendes del todo — la IA lo generó, tú lo copiaste.

Aprender + Publicar + Defender

Si lo puedes explicar en voz alta y modificarlo en vivo, es tuyo. Eso es lo único que la IA no puede hacer por ti.

La estructura fija de toda defensa (para las 4 Unidades)

No importa la Unidad: el orden en que hablas siempre es el mismo. Memoriza este orden, no el contenido — el contenido cambia, la estructura no.

1

Apertura / Presentación · 10-15 seg

Di quién eres, qué construiste y en qué URL vive. Una sola frase, sin rodeos.

2

Recorrido del entregable en vivo · 30-45 seg

Muestras la URL real funcionando y señalas las partes clave mientras hablas.

3

Justificación técnica · 30-45 seg

Explicas por qué tomaste una decisión técnica, no solo qué hiciste. Aquí se distingue a quien entendió de quien copió.

4

Reto de Live Coding · 1-2 min · vale 40% de la nota

El docente pide un cambio real y lo haces frente a él, narrando cada paso en voz alta.

5

Preguntas conceptuales rápidas · 30-60 seg · vale 25% de la nota

Preguntas de "por qué funciona así", no de sintaxis. Se responden con lógica, no con memoria.

6

Cierre · 10 seg

Agradeces y quedas abierto a más preguntas. No te quedes callado esperando: tú cierras.

Cómo usar esta guía: para cada Unidad, primero lee "Aprende" y "Publica" para ubicar el ejemplo concreto que se está defendiendo. Después practica en voz alta la sección "Defiende" — al principio léela casi literal, y en cada repaso cámbiala más a tus propias palabras, sin perder el orden de los pasos.

Unidad 1 · Front-End Esencial

Ejemplo: agregar una tarjeta de proyecto nueva al portafolio

1 · Aprende

Entiendes que HTML5 semántico (header, main, section, article, footer) organiza el contenido por significado, no por apariencia, y que Tailwind te permite maquetar mobile-first con clases como grid md:grid-cols-3.

2 · Publica

Guardas el cambio, corres git add . && git commit -m "..." && git push, y Render redespliega solo por el webhook de GitHub. La URL pública queda actualizada en menos de un minuto.

3 · Defiende — guion palabra por palabra

1

Apertura · 0:00-0:15

"Buenas [tardes/días], profesor. Mi proyecto es un portafolio personal construido con HTML5 semántico y Tailwind CSS, publicado en Render en esta dirección: https://[usuario]-portafolio.onrender.com."
2

Recorrido en vivo · 0:15-0:45

"Como pueden ver, la página tiene cuatro bloques semánticos: el <header> con mi nombre y navegación, un <main> que agrupa las secciones 'Sobre mí', 'Proyectos' y 'Contacto', y cierra con un <footer>. Cada proyecto dentro de 'Proyectos' es un <article> independiente."
3

Justificación técnica · 0:45-1:15

"Usé etiquetas semánticas en vez de puros <div> porque mejoran la accesibilidad — un lector de pantalla puede saltar directo a <nav> o a <main> — y el SEO, porque el buscador entiende de qué trata cada bloque. Para el diseño elegí Tailwind porque trabajo mobile-first: escribo el estilo pensando primero en celular y solo agrego md: cuando necesito cambiar algo en pantallas grandes."
4

Reto de Live Coding · 1:15-3:00 · "Agrega una tarjeta de proyecto nueva y publícala"

Narra cada acción mientras la haces — no la hagas en silencio:

  1. 1. "Abro index.html en VS Code y ubico la sección de Proyectos."
  2. 2. "Copio el último <article> completo, porque cada tarjeta comparte la misma estructura."
  3. 3. "Pego el bloque dentro del mismo contenedor grid y cambio el título y la descripción por el nuevo proyecto."
  4. 4. "Guardo con Ctrl+S y reviso en el navegador que la tarjeta ya aparece localmente."
  5. 5. "Abro la terminal y corro git add . para preparar el cambio."
  6. 6. "Corro git commit -m "feat: agregar tarjeta de proyecto Landing Restaurante" — un mensaje descriptivo, no 'update'."
  7. 7. "Corro git push. Esto dispara el redeploy automático en Render porque el repo está conectado por webhook."
  8. 8. "Mientras Render redespliega, unos 30 a 60 segundos, recargo la URL pública y muestro la tarjeta nueva ya visible en producción."
5

Preguntas conceptuales · 3:00-3:45

¿Por qué mobile-first y no diseñar primero para escritorio?

"Porque la mayoría de usuarios reales entra desde el celular primero. Con Tailwind escribo el estilo base para pantallas chicas y solo sobrescribo con md: o lg: cuando hace falta, así evito estilos innecesarios."

¿Qué pasaría si no hubieras usado Git?

"No tendría historial de cambios fechado, no podría revertir un error, y Render no tendría de dónde jalar el código para desplegarlo automáticamente."
6

Cierre · 3:45-4:00

"Eso es todo lo que quería mostrar de la Unidad 1. Quedo atento a cualquier otra pregunta."
Unidad 2 · Django + MySQL en la nube

Ejemplo: agregar un campo al modelo y migrar en vivo

1 · Aprende

Entiendes la arquitectura MTV: el Modelo (models.py) define la tabla, la Vista (views.py) consulta datos con el ORM, y la planTilla los muestra en HTML. Y que makemigrations + migrate son los dos pasos para que un cambio en Python se refleje en MySQL.

2 · Publica

Migras primero en local contra MySQL (Aiven), haces git push, Render redespliega el código y su Build Command corre migrate solo (el plan Free no tiene Shell); en el log de Render confirmas que la base de producción está al día.

3 · Defiende — guion palabra por palabra

1

Apertura · 0:00-0:15

"Mi proyecto es una vitrina de servicios hecha con Django, conectada a una base de datos MySQL en la nube con Aiven, publicada en Render en esta URL: https://[proyecto].onrender.com."
2

Recorrido en vivo · 0:15-1:00

"Aquí en /admin se ven los registros de Servicio que existen en MySQL, y en la vista pública esos mismos datos se listan usando el ORM de Django, no datos escritos a mano en el HTML. El modelo Servicio vive en models.py, la vista que los consulta en views.py, y la plantilla que los pinta en templates/."
3

Justificación técnica · 1:00-1:40

"Usé MySQL en la nube en vez de SQLite local porque el sistema de archivos de Render es efímero: si usara SQLite, los datos se borrarían cada vez que el servicio se reinicia. Con MySQL en Aiven, los datos persisten siempre, sin importar cuántas veces se redespliegue la app."
4

Reto de Live Coding · 1:40-3:20 · "Agrega un campo al modelo y migra en vivo"

  1. 1. "Abro models.py y ubico la clase Servicio."
  2. 2. "Agrego la línea imagen_url = models.URLField(blank=True, null=True). Uso blank=True, null=True para que el campo sea opcional y no rompa los registros que ya existen."
  3. 3. "Guardo el archivo y en la terminal corro python manage.py makemigrations. Django detecta el cambio y genera un archivo nuevo dentro de migrations/, como un plan de lo que va a cambiar."
  4. 4. "Corro python manage.py migrate. Este comando sí ejecuta ese plan contra MySQL: agrega la columna imagen_url a la tabla real."
  5. 5. "Muestro en el panel de Aiven (o recargando /admin) que la columna nueva ya existe en la tabla."
  6. 6. "Corro git add ., git commit -m "feat: agregar campo imagen_url al modelo Servicio", git push."
  7. 7. "Espero el redeploy en Render y abro el log: como migrate está en el Build Command, Render lo corre solo. Dice 'No migrations to apply' porque ya migré en local contra la misma base de Aiven."
5

Preguntas conceptuales · 3:20-4:00

¿Qué diferencia hay entre makemigrations y migrate?

"makemigrations lee mis modelos y genera el archivo con el plan de cambios, pero todavía no toca la base de datos. migrate es el que ejecuta ese plan de verdad contra MySQL."

¿Por qué separar Modelo, Vista y Plantilla en vez de mezclar todo en un archivo?

"Porque cada parte cambia por razones distintas: si cambio el diseño solo toco la plantilla, si cambio una regla de negocio solo toco la vista, y si cambio la estructura de datos solo toco el modelo. Así un cambio no rompe las otras dos capas."
6

Cierre · 4:00-4:10

"Con esto cierro la Unidad 2. Quedo abierto a más preguntas."
Unidad 3 · CRUD Dinámico y Sesiones

Ejemplo: crear un usuario nuevo y demostrar el aislamiento de datos

1 · Aprende

Entiendes que @login_required protege una vista, que {% csrf_token %} protege un formulario, y que un ForeignKey a User permite filtrar Servicio.objects.filter(propietario=request.user) para que cada quien vea solo lo suyo.

2 · Publica

Despliegas el sistema de registro/login/logout en producción y documentas en el README cómo comprobaste, con dos cuentas reales, que el aislamiento de datos funciona.

3 · Defiende — guion palabra por palabra

1

Apertura · 0:00-0:15

"Mi proyecto ahora tiene un CRUD completo protegido con login: cada usuario solo puede ver y editar sus propios servicios."
2

Recorrido en vivo · 0:15-1:00

"Si intento entrar a /panel sin sesión iniciada, Django me redirige automáticamente al login. Inicio sesión con mi cuenta y ahora sí veo mi panel privado con mis servicios: puedo crear uno nuevo, editarlo y borrarlo desde aquí, sin pasar por /admin."
3

Justificación técnica · 1:00-1:40

"Cada Servicio tiene un ForeignKey al modelo User de Django. En cada vista del panel filtro con Servicio.objects.filter(propietario=request.user), así la base de datos nunca me regresa registros de otro usuario, y @login_required bloquea el acceso a quien no inició sesión."
4

Reto de Live Coding · 1:40-3:20 · "Crea un usuario nuevo y demuestra el aislamiento"

  1. 1. "Cierro sesión de mi cuenta actual."
  2. 2. "Voy a /registro y creo una cuenta de prueba nueva."
  3. 3. "Inicio sesión con esa cuenta y entro al panel privado. Como ven, la lista de servicios está vacía: el filtro propietario=request.user no encuentra ningún registro de este usuario nuevo."
  4. 4. "Creo un servicio de prueba con esta cuenta."
  5. 5. "Cierro sesión, vuelvo a entrar con mi cuenta original y muestro que NO aparece el servicio que acabo de crear con la cuenta de prueba."
  6. 6. "Esto demuestra que el aislamiento ocurre a nivel de consulta a la base de datos, no solo visualmente en la plantilla."
5

Preguntas conceptuales · 3:20-4:00

¿Qué hace exactamente @login_required?

"Es un decorador que Django ejecuta antes de entrar a la vista; si no hay sesión activa, redirige al login en vez de mostrar el contenido protegido."

¿Para qué sirve {% csrf_token %} en el formulario?

"Genera un token único por sesión que Django valida al recibir el formulario, para confirmar que la petición viene realmente de mi sitio y no de un ataque CSRF externo."
6

Cierre · 4:00-4:10

"Así queda demostrado el aislamiento por usuario. Quedo atento a dudas."
Unidad 4 · Proyecto Integrador y Defensa Final

La defensa completa: todo lo anterior, en una sola sustentación de 3-5 min

Aquí no hay un solo reto: el docente puede pedir cualquier reto de live coding de las Unidades 1, 2 o 3, al azar, además de preguntas conceptuales de todo el curso. Por eso conviene repasar los guiones anteriores antes de este día. La estructura es la misma (seguir en orden los pasos del guion de cada Unidad), pero ahora cada paso pesa según la Matriz de Evaluación Anti-IA.

1 · Aprende

En la Semana 7 repasas tu propia bitácora de commits, pules UX (mensajes vacíos, paginación, estados sin datos) y haces un simulacro completo de defensa con un reto al azar.

2 · Publica

En la Semana 8 congelas la versión final: último migrate en producción, tag/release en GitHub, y verificas que la URL responde en el momento de la revisión.

3 · Defiende — guion completo y peso de cada paso

1

Apertura · 0:00-0:15

"Buenas [tardes/días], profesor. Voy a defender mi proyecto integrador, [nombre del proyecto], una vitrina de servicios construida con Django y MySQL en la nube, publicada en Render en esta URL: https://[proyecto].onrender.com."
2

Recorrido completo · 0:15-1:00

"Recorro las cuatro capacidades construidas a lo largo del curso: la vitrina pública responsiva de la Unidad 1, el catálogo dinámico leído desde MySQL de la Unidad 2, el panel privado con CRUD y login de la Unidad 3, y aquí en la Unidad 4 la versión pulida y final, sin errores visibles, con datos reales."
3

Justificación técnica global · 1:00-1:45

"Elegí Django porque su arquitectura MTV separa datos, lógica y presentación; MySQL en la nube porque el hosting de Render es efímero y necesito persistencia real; y protegí el CRUD con @login_required y filtrado por request.user porque cada vitrina le pertenece a un dueño distinto."
4

Live Coding sorpresa · 1:45-3:15 · vale 40% de la nota

El docente elige uno de estos tres retos al azar (o uno nuevo del mismo nivel). Repásalos todos, no adivines cuál te tocará:

  • Unidad 1 — Agregar una tarjeta/sección nueva y publicarla.
  • Unidad 2 — Agregar un campo al modelo y migrar en vivo.
  • Unidad 3 — Crear un usuario nuevo y demostrar el aislamiento de datos.
"Voy a narrar cada paso mientras lo hago: primero identifico en qué archivo va el cambio, explico por qué ahí y no en otro lado, hago el cambio, lo pruebo en local, y lo publico con git add, commit, push hasta verlo reflejado en la URL en vivo."
5

Examen conceptual rápido · 3:15-4:00 · vale 25% de la nota

Explica el flujo completo de una petición HTTP en tu app.

"El navegador manda una petición a una URL; urls.py la conecta con una vista en views.py; la vista consulta el modelo con el ORM, arma el contexto y se lo pasa a una plantilla; Django renderiza el HTML final y lo regresa como respuesta al navegador."

¿Qué ventaja tiene el ORM sobre escribir SQL puro?

"Escribo Python en vez de SQL, Django arma las consultas de forma segura evitando inyección SQL, y si cambio de motor de base de datos no tengo que reescribir las consultas."
6

Cierre y evidencia · 4:00-4:10 · commits 20% + entregable publicado 15%

"Con esto cierro la defensa. Mi historial de commits en GitHub muestra el avance semana por semana, y el release final marca la versión que estoy sustentando hoy. Quedo atento a cualquier pregunta adicional."

Antes de defender

Checklist de 60 segundos

Revisa esto justo antes de entrar a defender, sin importar la Unidad:

Señales que bajan la nota (evítalas)

  • Quedarte en blanco al pedirte modificar tu propio código sin ayuda.
  • No reconocer el nombre de tus propias variables, modelos o vistas.
  • Explicar el código pero no poder describir el flujo general del framework.
  • Un solo commit gigante la noche anterior con mensaje genérico.
  • El entregable funciona en local pero la URL pública no responde.