← JavaScript: el lenguaje

Sesión 6

Integración y entrega

Tres horas. Media hora para aprender a leer y mejorar código ajeno sin cambiar lo que hace, y dos horas y media modelando un dominio que no has visto, refactorizando un fichero heredado y cerrando la entrega.

Hoy · Hoja de ruta

  1. 1. Aprende: Nada nuevo del lenguaje. Qué señales indican que un código se puede mejorar sin cambiar su comportamiento, y qué se revisa antes de dar un módulo por terminado.
  2. 2. Haz: Modela y consulta un dominio desconocido, refactoriza un fichero que funciona pero está mal escrito, y audita tu proyecto y el de un compañero.
  3. 3. Entrega: Los cuatro módulos, la lista de auditoría, la revisión del compañero y tus tres decisiones.

Antes de empezar · 5 minutos, sin apuntes

  1. Ante datos nuevos, ¿qué decides primero: la estructura o las funciones?
  2. ¿Qué es lo primero que miras al abrir código de otra persona?
  3. ¿Cómo sabes que una mejora no ha roto nada?

Se explica

25 minutos · conceptos y demostración

Hoy no entra nada nuevo del lenguaje. Entra lo que se hace con el lenguaje cuando el código ya existe: leerlo, mejorarlo sin romperlo y decidir si está terminado.

El camino, que ya es el mismo de siempre

Cómo se ataca un dominio nuevo
  1. Identificar las entidades y sus propiedades
  2. Modelarlas como array de objetos
  3. Escribir una función por pregunta
  4. Validar la entrada en el borde
  5. Comprobar con casos normales, límite y vacíos

Sin copiar y pegar de tu proyecto

Puedes consultar tus apuntes y la documentación. Lo que no vale es duplicar tu catalogo.js y renombrar variables: la sesión sirve justamente para comprobar si sabrías escribirlo otra vez.

Las señales de un código que pide una revisión

Señal Qué suele significar Qué se hace
Una función de 60 líneas Hace varias cosas Extraer funciones
Nombres de una letra Nadie sabe qué contienen Renombrar
El mismo bloque tres veces Falta una función Extraer y parametrizar
Números sueltos (* 1.21) Falta una constante Nombrarlo
Anidamiento de cuatro niveles Faltan salidas tempranas Invertir condiciones
Comentarios que explican qué hace El código no se explica solo Reescribir el código

Refactorizar

Cambiar cómo está escrito un programa sin cambiar lo que hace. Si el comportamiento cambia, la operación deja de ser una refactorización y pasa a ser una modificación, que debe probarse como tal.

Salidas tempranas

// Antes: cuatro niveles de anidamiento
function precioFinal(producto) {
  if (producto) {
    if (producto.precio > 0) {
      if (producto.descuento) {
        return producto.precio * (1 - producto.descuento);
      } else {
        return producto.precio;
      }
    }
  }
}

// Después: los casos raros se despachan al principio
function precioFinal(producto) {
  if (!producto) return 0;
  if (producto.precio <= 0) return 0;
  if (!producto.descuento) return producto.precio;
  return producto.precio * (1 - producto.descuento);
}

La segunda versión se lee de arriba abajo, y cada línea responde a un caso.

Comprobar que no has roto nada

Antes de tocar, escribe en un fichero las respuestas actuales del programa para media docena de entradas. Refactoriza. Vuelve a ejecutar. Si algo cambió, la refactorización introdujo un error.

Eso es, en versión manual, lo que en el módulo de servidor harán los tests automáticos.

Leer el código de otra persona

La revisión de hoy no es de estilo. Se hace en cuatro pasos, y el primero no incluye preguntarle nada a su autor:

  1. Ejecutar el programa y describir qué hace.
  2. Elegir dos funciones y explicarlas en voz alta.
  3. Buscarle tres entradas que lo rompan.
  4. Señalar una cosa bien hecha y una mejorable, con su razón.

Si no consigues completar el primer paso sin ayuda, eso ya es un hallazgo sobre el código, y es el más importante que le puedes devolver.

Se trabaja

150 minutos · dominio nuevo, código heredado y cierre del proyecto

Los dos primeros pasos son los largos: uno escribe desde cero, el otro repara lo que escribió otro. Los tres últimos cierran la unidad.

Paso 1 · Un dominio desconocido · 55 min

Recibirás un enunciado con un dominio distinto del tuyo —una biblioteca, un gimnasio, una liga deportiva, una clínica— descrito en prosa, con datos de ejemplo desordenados y unas cuantas preguntas que hay que poder responder.

1.1 · Primero el modelo

Identifica las entidades y sus propiedades y escríbelas en papel antes de programar. Decide qué campo actúa de identificador y de qué tipo es cada propiedad.

1.2 · Después las consultas

Escribe una función por pregunta. Deben cubrir, como mínimo: listar, buscar por texto, filtrar por un criterio numérico, ordenar por dos campos distintos, calcular un agregado y detectar un caso especial.

1.3 · Y por último las comprobaciones

Valida la entrada en el borde y prueba cada consulta con un caso normal, uno límite y la colección vacía.

La entrega del paso: un módulo con los datos, otro con las consultas, y un principal que responda por consola a las preguntas del enunciado.

Paso 2 · El fichero heredado · 45 min

Recibirás un módulo de unas cien líneas que funciona pero está mal escrito:

  1. Ejecútalo y anota su comportamiento con seis entradas. Esta lista es tu red de seguridad.
  2. Localiza cinco señales de la tabla de la explicación.
  3. Refactoriza en pasos pequeños, comprobando después de cada uno.
  4. Escribe un comentario por cada cambio explicando qué señal atacaba.
  5. Demuestra que el comportamiento es idéntico comparando con la lista del apartado 1.
  6. Reduce el anidamiento máximo a dos niveles en todo el fichero.

Si en algún momento una comprobación deja de coincidir, deshaz ese paso antes de seguir. Refactorizar sobre un cambio de comportamiento no detectado es cómo se pierde una tarde entera.

Paso 3 · La auditoría final · 20 min

Auditoría · el código

  • No queda ningún var, y los let son los que de verdad cambian.
  • Todas las comparaciones usan el triple igual.
  • Toda entrada externa se convierte y se valida al leerla.
  • Las funciones devuelven valores; imprimir es cosa del principal.
  • Ninguna función pasa de veinticinco líneas.
  • No hay números sueltos sin nombre.
  • Los nombres están en un solo idioma y dicen qué contienen.
  • No queda código comentado ni console.log de depuración.

Auditoría · el comportamiento

  • El catálogo vacío no produce NaN ni errores.
  • Una búsqueda sin resultados devuelve una lista vacía, no undefined.
  • Los datos inválidos se rechazan con un mensaje que dice qué falla.
  • Ordenar no altera el catálogo original.
  • La consola no muestra ningún error al cargar.

Paso 4 · Revisión por pares · 20 min

Intercambia proyectos y aplica los cuatro pasos de la explicación, sin preguntar nada a su autor:

  1. Ejecuta el programa y describe qué hace.
  2. Elige dos funciones y explícalas en voz alta.
  3. Búscale tres entradas que lo rompan.
  4. Señala una cosa bien hecha y una mejorable, con su razón.

Devuelve el trabajo con esas cuatro respuestas por escrito. Después recibe la tuya y decide qué aceptas, justificando lo que rechaces.

Paso 5 · Cerrar la entrega y preparar la defensa · 10 min

La carpeta js/ con datos.js, catalogo.js, formato.js y main.js; el enlace único con type="module"; la lista de auditoría marcada; la revisión del compañero por escrito; y un fichero NOTAS.md con las tres decisiones que más te costaron y por qué las tomaste así.

Prepara respuestas de un minuto para estas cuatro preguntas:

Las preguntas de la defensa

  1. Enseña una función y explica qué recibe, qué devuelve y qué pasa si le llega basura.
  2. ¿Por qué elegiste ese método de array y no otro?
  3. Si mañana el catálogo llega desde un servidor en vez de estar escrito en tu fichero, ¿qué tendrías que cambiar?
  4. Enseña un fallo que te costó encontrar y cuenta cómo lo encontraste.

La tercera es la importante, y es la misma pregunta que cerraba la UD1 y la UD2: si has separado datos, lógica y uso, la respuesta debería ser «solo el módulo de datos».

Criterio de evaluación Puntos
Tipos y conversión tratados en los bordes del programa 1,5
Condicionales y bucles que expresan la regla, con sus límites 1,5
Funciones pequeñas que devuelven en lugar de imprimir 2
Consultas del catálogo con el método adecuado a lo que se necesita 2
Modelado con objetos y JSON válido 1
Módulos con una responsabilidad cada uno 1
Validación de la entrada y tratamiento de errores 1

No puntúa que el código sea corto ni ingenioso. Puntúa que se pueda leer, que trate los casos raros —la lista vacía, el texto donde esperabas un número— y que puedas cambiar una decisión pequeña delante de alguien.

Ampliación si has completado el trabajo

Primero termina la entrega. El primer reto separa dos cosas que se confunden siempre; el segundo pone a prueba, de verdad, si tus módulos estaban bien separados.

Reto 1 · El fallo que estaba antes de que llegaras

El fichero heredado del paso 2 esconde además un fallo lógico: no produce ningún error y devuelve un resultado equivocado en cierto caso.

  1. Encuéntralo. La lista de comportamiento del paso 2 no te ayuda aquí, porque el fichero ya lo tenía cuando la escribiste.
  2. Demuestra con una entrada concreta que el resultado es incorrecto, y di cuál debería ser.
  3. Arréglalo en un commit distinto del de la refactorización, o al menos en un bloque de cambios separado y anotado como tal.
  4. Explica en tres líneas por qué no se mezclan las dos cosas. La respuesta tiene que ver con lo que ocurre cuando, dentro de un mes, alguien tenga que averiguar qué cambio rompió qué.
  5. Escribe la comprobación que, añadida al fichero, habría hecho visible ese fallo desde el primer día.

Reto 2 · Cambia el origen de los datos

La tercera pregunta de la defensa dice que, si el catálogo llegara de un servidor, solo habría que tocar el módulo de datos. Compruébalo en lugar de suponerlo.

  1. Sustituye el array escrito a mano de datos.js por un texto JSON, y haz que el módulo lo lea con JSON.parse dentro de un try/catch.
  2. Ejecuta. Cuenta cuántos ficheros has tenido que tocar. Si es más de uno, anota cuál y por qué: ahí hay un acoplamiento que no sabías que tenías.
  3. Ahora haz que ese JSON venga de un fichero externo servido por tu servidor local. Todavía no conoces fetch, así que usa un módulo que exporte el texto; la sustitución completa llega en la UD4.
  4. Introduce en el JSON tres defectos realistas: un producto sin precio, uno con el stock como texto y uno con una clave escrita distinta. ¿Cuántos atraviesan tu validación?
  5. Escribe en cinco líneas qué habría que cambiar en tu proyecto para que el catálogo pudiera venir indistintamente de un fichero, de un servidor o de un formulario. Esa respuesta es el índice de las dos unidades siguientes.
Objetivo mínimoEl dominio nuevo modelado con cuatro de las seis consultas, y cinco mejoras aplicadas al fichero heredado con comportamiento idéntico.
Si lo tienesLas seis consultas con validación y casos límite, la auditoría marcada y la revisión del compañero contestada.
RetoEl fallo lógico separado de la refactorización, y el origen de los datos cambiado tocando un solo fichero.

Cierre

5 minutos · comprobación y recuerdo

Lista de verificación de la entrega

  • Has modelado un dominio nuevo sin copiar del tuyo.
  • Cada pregunta tiene su función, y cada función devuelve.
  • El fichero heredado está refactorizado con el comportamiento demostradamente idéntico.
  • Las dos listas de auditoría están marcadas.
  • Has revisado el proyecto de un compañero con los cuatro pasos.
  • NOTAS.md recoge tus tres decisiones y su motivo.

Antes de cerrar · 3 minutos, sin mirar

  1. ¿Qué es refactorizar, y qué deja de serlo?
  2. Nombra tres señales de que un código necesita revisión.
  3. ¿Cómo demuestras que una refactorización no ha roto nada?
  4. ¿Qué ventaja tienen las salidas tempranas sobre el anidamiento?
  5. Ante un resultado que no es el esperado, ¿qué compruebas y en qué orden?
  6. Si el catálogo pasara a venir de un servidor, ¿qué módulo debería cambiar?
Ver respuestas

1 · Cambiar cómo está escrito un programa sin cambiar lo que hace. En cuanto el comportamiento cambia, es una modificación y hay que probarla como tal.

2 · Por ejemplo: funciones muy largas, nombres de una letra, bloques repetidos, números sueltos, anidamiento profundo o comentarios que explican lo que hace el código.

3 · Anotando el comportamiento con varias entradas antes de tocar, y comparando después de cada paso.

4 · Despachan los casos raros al principio y dejan el camino normal sin anidar, de modo que el cuerpo se lee de arriba abajo.

5 · Qué se esperaba, qué ocurre, y dónde deja de coincidir; después se divide el recorrido en dos con una comprobación intermedia.

6 · Solo el de datos, si la separación en módulos está bien hecha.

Microprueba semanal 6 · 10 minutos

Individual, sin IA y sin apuntes.

  1. Dado un array de objetos, escribe la consulta que responde a una pregunta con dos criterios y un orden.
  2. Señala tres señales de que un código necesita refactorizarse.
  3. Ante un resultado que no es el esperado, ¿qué compruebas y en qué orden?