Quiz Final: Evaluación del Proyecto Integrador

Quiz
15 min~5 min lectura

Quiz Interactivo

Pon a prueba tus conocimientos

Concepto clave

El quiz final de este proyecto integrador evalúa tu capacidad para aplicar Prisma ORM en un entorno de producción real. No se trata solo de recordar sintaxis, sino de demostrar que puedes diseñar schemas escalables, ejecutar migraciones seguras y escribir queries optimizadas que funcionen bajo carga. Piensa en esto como el examen final de un piloto: no basta con conocer los controles, debes demostrar que puedes aterrizar el avión en condiciones adversas.

En producción, cada decisión tiene consecuencias. Un schema mal diseñado puede limitar el crecimiento de tu aplicación. Una migración ejecutada sin pruebas puede causar downtime. Una query ineficiente puede saturar tu base de datos. Este quiz simula esas situaciones críticas donde tu conocimiento teórico debe convertirse en acción práctica.

Cómo funciona en la práctica

Imagina que estás desarrollando una API para un e-commerce con 100,000 usuarios activos. Tu tarea es implementar un sistema de pedidos que incluya: usuarios, productos, pedidos y detalles de pedido. Primero, diseñas el schema en Prisma, considerando relaciones, índices y tipos de datos apropiados. Luego, creas y aplicas migraciones sin interrumpir el servicio existente. Finalmente, optimizas las queries para que la página de historial de pedidos cargue en menos de 200ms incluso con miles de registros.

Paso a paso: 1) Analiza los requisitos del negocio y modela las entidades. 2) Define las relaciones (1-a-1, 1-a-muchos, muchos-a-muchos) en el schema. 3) Aplica migraciones en etapas (usando herramientas como prisma migrate dev y prisma migrate deploy). 4) Escribe queries que usen select, include, y where de forma eficiente. 5) Prueba el rendimiento con datos realistas.

Código en acción

Ejemplo de un schema optimizado para producción:

// schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Usuario {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  nombre    String
  pedidos   Pedido[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([email]) // Índice para búsquedas rápidas
}

model Producto {
  id          Int      @id @default(autoincrement())
  nombre      String
  precio      Decimal  @db.Decimal(10, 2)
  stock       Int      @default(0)
  detalles    DetallePedido[]
  createdAt   DateTime @default(now())
}

model Pedido {
  id          Int             @id @default(autoincrement())
  usuarioId   Int
  usuario     Usuario         @relation(fields: [usuarioId], references: [id])
  detalles    DetallePedido[]
  total       Decimal         @db.Decimal(10, 2)
  estado      String          @default("pendiente")
  createdAt   DateTime        @default(now())

  @@index([usuarioId]) // Mejora rendimiento en joins
}

model DetallePedido {
  id         Int      @id @default(autoincrement())
  pedidoId   Int
  productoId Int
  pedido     Pedido   @relation(fields: [pedidoId], references: [id])
  producto   Producto @relation(fields: [productoId], references: [id])
  cantidad   Int
  precioUnitario Decimal @db.Decimal(10, 2)

  @@unique([pedidoId, productoId]) // Evita duplicados
}

Query optimizada para obtener el historial de pedidos de un usuario:

// ANTES: Query ineficiente que carga datos innecesarios
const pedidos = await prisma.pedido.findMany({
  where: { usuarioId: 123 },
  include: {
    detalles: {
      include: { producto: true }
    }
  }
});

// DESPUÉS: Query optimizada con select específico
const pedidosOptimizados = await prisma.pedido.findMany({
  where: { usuarioId: 123 },
  select: {
    id: true,
    total: true,
    estado: true,
    createdAt: true,
    detalles: {
      select: {
        cantidad: true,
        precioUnitario: true,
        producto: {
          select: {
            nombre: true,
            precio: true
          }
        }
      }
    }
  },
  orderBy: { createdAt: 'desc' },
  take: 10 // Paginación para evitar cargar miles de registros
});

Errores comunes

  • No usar índices en campos de búsqueda frecuente: En tablas grandes, buscar por email sin índice puede ser 100x más lento. Solución: Agrega @@index([email]) en el modelo.
  • Migraciones sin respaldo en producción: Ejecutar prisma migrate deploy sin haber probado en staging puede corromper datos. Solución: Siempre prueba migraciones en un entorno idéntico a producción primero.
  • Queries que cargan relaciones completas: Usar include sin select carga todos los campos, incluso los no necesarios. Solución: Especifica solo los campos necesarios con select.
  • Olvidar paginación en listados largos: Un findMany() sin take o skip puede traer millones de registros. Solución: Implementa paginación con take y skip.
  • No manejar transacciones en operaciones críticas: Crear un pedido sin transacción puede dejar datos inconsistentes si falla un paso. Solución: Usa prisma.$transaction() para operaciones multi-paso.

Checklist de dominio

  1. ¿Puedes diseñar un schema Prisma que modele relaciones complejas (muchos-a-muchos, anidadas) correctamente?
  2. ¿Sabes ejecutar migraciones en producción sin downtime usando estrategias como migraciones progresivas?
  3. ¿Escribes queries que usen select en lugar de include cuando solo necesitas campos específicos?
  4. ¿Implementas paginación en todas las queries que pueden devolver muchos resultados?
  5. ¿Usas índices en campos de búsqueda frecuente y claves foráneas?
  6. ¿Manejas transacciones para operaciones que deben ser atómicas (ej: crear pedido con múltiples items)?
  7. ¿Validas datos de entrada antes de pasarlos a Prisma para prevenir inyecciones o errores de tipo?

Optimización de API de Pedidos para Escala

Tu equipo necesita optimizar una API existente que está teniendo problemas de rendimiento bajo carga. La API maneja pedidos para un e-commerce y actualmente tarda más de 2 segundos en cargar el historial de pedidos de usuarios con muchos registros.

  1. Diagnostica el problema: Examina el siguiente código actual y identifica al menos 3 problemas de rendimiento:
  2. // Código actual (problemático)
    async function getHistorialUsuario(usuarioId: number) {
      return await prisma.pedido.findMany({
        where: { usuarioId },
        include: {
          usuario: true,  // Carga todos los campos del usuario
          detalles: {
            include: {
              producto: true  // Carga todos los campos del producto
            }
          }
        }
      });
    }
  3. Rediseña el schema: Si fuera necesario, propone mejoras al schema Prisma para optimizar las consultas. Considera índices, tipos de datos y relaciones.
  4. Reescribe la query: Crea una versión optimizada de la función getHistorialUsuario que:
    • Use select en lugar de include para cargar solo campos necesarios
    • Implemente paginación (limite de 20 pedidos por página)
    • Incluya un orden descendente por fecha de creación
    • Maneje errores adecuadamente
  5. Propón una migración: Si agregaste índices en el paso 2, escribe el comando Prisma para crear y aplicar la migración de forma segura.
Pistas
  • Revisa qué campos son realmente necesarios para mostrar el historial de pedidos. ¿Necesitas todos los campos de usuario y producto?
  • Recuerda que cada include sin select carga TODOS los campos de la relación, lo que puede ser muy costoso.
  • Para paginación, investiga los parámetros take y skip en la documentación de Prisma.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.