La lección anterior fijó el alcance general del proyecto final de BiblioTech y su arquitectura elegida. Antes de tocar una sola línea de código, esta lección convierte ese alcance en algo mucho más concreto: una lista precisa de requisitos funcionales y no funcionales, y un plan de trabajo en iteraciones pequeñas que evite la tentación de intentar construirlo todo de golpe. Planificar antes de programar no es burocracia innecesaria: es lo que permite, en la Lección 3, saber exactamente qué construir primero y por qué, en vez de avanzar a ciegas ensamblando piezas en un orden arbitrario.

Contenido

  1. Requisitos funcionales: casos de uso concretos
  2. Requisitos no funcionales
  3. Planificación en fases: cuatro iteraciones
  4. Estimación básica de tareas por iteración
  5. Elección definitiva de tecnologías

  1. Requisitos funcionales: casos de uso concretos

Un requisito funcional describe algo que el sistema debe hacer: una acción concreta que un usuario (o un cliente de la API) puede solicitar y esperar un resultado. Para BiblioTech, la lista de requisitos funcionales del proyecto final es la siguiente:

# Caso de uso Entrada Resultado esperado
RF1 Dar de alta un libro o revista Título, autor, ISBN (u otros datos de Libro/Revista, Módulo 3) El material se añade a Catalogo
RF2 Dar de baja un material del catálogo Identificador del material El material deja de aparecer en el catálogo
RF3 Buscar materiales por título o autor Texto de búsqueda Lista de materiales que coinciden (LINQ, Módulo 4)
RF4 Dar de alta un socio Nombre del socio El socio se añade a Socios, con un Id único
RF5 Registrar un préstamo ISBN del material, Id del socio Se crea un Prestamo; el material queda marcado como no disponible
RF6 Registrar una devolución Identificador del préstamo Se asigna FechaDevolucion; se calcula la sanción si hay retraso (Módulo 8, IPoliticaSancion)
RF7 Consultar metadatos externos de un libro ISBN Datos adicionales del servicio externo (Módulo 5), o ausencia clara si no están disponibles

Cada uno de estos siete requisitos corresponde, de forma casi directa, a un método ya existente en Biblioteca o a una combinación pequeña de ellos —la propia tabla es, en sí misma, un mapa de qué parte del código ya construido cubre cada requisito.

  1. Requisitos no funcionales

Un requisito no funcional no describe una acción, sino una cualidad que el sistema debe tener mientras hace lo que hace. Son más difíciles de verificar con un simple caso de uso, pero igual de importantes:

  • Rendimiento razonable: las operaciones de consulta (RF3, listar el catálogo) deben responder en un tiempo aceptable incluso con un catálogo de tamaño moderado (cientos o pocos miles de materiales); no se persigue aquí ningún objetivo de rendimiento extremo, solo evitar operaciones evidentemente ineficientes (por ejemplo, cargar todo el catálogo en memoria en cada petición si una consulta a la base de datos bastaría).
  • Seguridad básica: la API no debe exponer datos sensibles de forma innecesaria (por ejemplo, cadenas de conexión o detalles internos de la base de datos en los mensajes de error que devuelve al cliente); las cadenas de conexión de producción deben vivir fuera del código fuente (Lección 5, configuración por entorno), nunca escritas directamente en Program.cs.
  • Mantenibilidad: gracias a la arquitectura del Módulo 8 (IRepositorioBiblioteca + inyección de dependencias + pruebas unitarias), cambiar el mecanismo de persistencia, añadir un nuevo endpoint, o corregir un error debe poder hacerse sin reescribir partes del sistema no relacionadas con el cambio.
  • Fiabilidad ante fallos externos: la consulta de metadatos externos (RF7) depende de un servicio de terceros que puede fallar o no responder; ya se vio en el Módulo 5 que este caso se captura con try/catch sobre HttpRequestException, devolviendo null en vez de propagar el fallo a quien pidió los metadatos.

A diferencia de los requisitos funcionales, estos no se "marcan como completados" con una única prueba puntual: se verifican de forma continua a lo largo de todo el proyecto, y se revisan explícitamente en el checklist de calidad de la Lección 4.

  1. Planificación en fases: cuatro iteraciones

Intentar construir las siete funcionalidades del apartado 1 a la vez, sin ningún orden, es la receta más directa para bloquearse a mitad de camino sin nada que funcione de principio a fin. En su lugar, el proyecto se organiza en cuatro iteraciones pequeñas, cada una entregando algo que funciona por sí mismo antes de pasar a la siguiente:

flowchart LR
    I1["Iteracion 1<br/>Dominio + Persistencia<br/>(ya construidos, Modulos 3-5-8)"] --> I2["Iteracion 2<br/>API<br/>(Leccion 3)"]
    I2 --> I3["Iteracion 3<br/>Cliente / UI<br/>(Leccion 3)"]
    I3 --> I4["Iteracion 4<br/>Pulido<br/>(Lecciones 4-5)"]
Iteración Qué entrega Qué requisitos cubre
1. Dominio + Persistencia Confirmar que Biblioteca, el modelo de dominio y IRepositorioBiblioteca con su implementación elegida (apartado 5) compilan y funcionan de forma aislada, sin API todavía Base de RF1-RF7 (ya construida en módulos anteriores, solo se verifica que sigue en orden)
2. API Endpoints HTTP de ASP.NET Core Minimal API sobre el dominio, con DI ya registrada RF1-RF7 expuestos por HTTP
3. Cliente / UI Un cliente sencillo (Blazor, o una consola con HttpClient) que consuma la API de la Iteración 2 Verificación de extremo a extremo de RF1-RF7 desde fuera del proceso de la API
4. Pulido Pruebas de integración, logging, checklist de calidad, despliegue Requisitos no funcionales del apartado 2

Esta división en iteraciones no es arbitraria: cada una depende exclusivamente de la anterior, y cada una es, por sí misma, algo verificable —una API que responde correctamente a curl, aunque no tenga cliente todavía, ya es un resultado tangible de la Iteración 2, no un trabajo a medias sin ningún valor propio.

  1. Estimación básica de tareas por iteración

Una estimación no necesita ser precisa al minuto para ser útil; basta con dar una idea relativa de esfuerzo que ayude a priorizar y a detectar de antemano en qué iteración es más probable atascarse:

Iteración Tareas principales Esfuerzo relativo
1. Dominio + Persistencia Revisar que las cuatro implementaciones de IRepositorioBiblioteca (Módulo 8) siguen compilando; elegir una para producción Bajo (ya construido, solo verificación)
2. API Estructura de solución, registro de DI, 5-7 endpoints (uno por requisito funcional) Medio-alto (es la iteración con más código nuevo)
3. Cliente / UI Un componente o pantalla por caso de uso principal (catálogo, préstamo, devolución) Medio
4. Pulido Pruebas de integración, logging, checklist, Dockerfile, configuración por entorno Medio

La iteración con mayor esfuerzo relativo (la API) es, precisamente, la que más se apoya en trabajo ya hecho en el Módulo 8: la mayor parte de esa "carga" es ensamblaje y registro de servicios, no lógica nueva que inventar desde cero.

  1. Elección definitiva de tecnologías

Con los requisitos ya claros, toca fijar, sin ambigüedad, qué tecnología concreta se usará en cada capa —resumiendo las decisiones ya presentadas o comparadas en módulos anteriores:

Capa Tecnología elegida Módulo donde se explicó
Dominio Clases C# ya existentes (MaterialBibliotecario, Libro, Revista, Socio, Prestamo) Módulo 3
Abstracción de persistencia IRepositorioBiblioteca Módulo 8 (Lección 3)
Persistencia concreta en producción Entity Framework Core sobre SQLite (RepositorioEntityFramework + BibliotecaDbContext) Módulo 5
Inyección de dependencias Contenedor de servicios de ASP.NET Core (AddScoped/AddSingleton/AddTransient) Módulo 8 (Lección 3)
API ASP.NET Core Minimal APIs Módulo 7
Cliente Blazor (o consumidor HttpClient sencillo) Módulo 7, Módulo 5
Pruebas xUnit + Moq Módulo 8 (Lección 4)
Metadatos externos HttpClient contra un servicio externo simulado Módulo 5

La elección de Entity Framework Core (en vez de texto, JSON o SQLite con ADO.NET puro) como persistencia de producción responde a un motivo concreto: es la única de las cuatro opciones del Módulo 5 pensada para escalar de forma cómoda a medida que el modelo de datos crezca, y se integra de forma natural con el contenedor de DI de ASP.NET Core mediante AddDbContext (ya visto en 08-03, apartado 7). Nada impide, sin embargo, sustituirla por cualquiera de las otras tres en cualquier momento: esa es, precisamente, la garantía que ofrece IRepositorioBiblioteca.

Errores Comunes y Consejos

  • Confundir requisitos funcionales con tareas de implementación: "usar Entity Framework Core" no es un requisito funcional (no describe qué hace el sistema para el usuario), es una decisión técnica del apartado 5; mantener ambas cosas separadas evita listas de requisitos confusas.
  • Saltarse los requisitos no funcionales por parecer "menos concretos": son tan reales como los funcionales, solo que se verifican de otra forma (revisión continua, checklist) en vez de con un caso de uso puntual.
  • Planificar iteraciones que dependen unas de otras de forma circular: si la Iteración 3 (Cliente) necesitara cambios en la Iteración 1 (Dominio) para funcionar, la planificación tiene un problema de orden; revisa que cada iteración solo dependa de las anteriores, nunca de las siguientes.
  • Consejo: si una iteración parece "demasiado grande" al estimarla, es buena señal de que puede dividirse en dos iteraciones más pequeñas, cada una con su propio resultado verificable.

Ejercicios

  1. Para cada uno de los siete requisitos funcionales (RF1-RF7) de la tabla del apartado 1, indica en qué iteración del apartado 3 se cubre principalmente y qué endpoint HTTP (verbo + ruta) esperarías que lo implemente en la Iteración 2.

  2. Un compañero de equipo propone añadir, a mitad de la Iteración 2, un requisito nuevo: "permitir reservar un libro que no está disponible, para que quede apartado cuando se devuelva". Explica por qué, según los criterios de planificación de esta lección, ese requisito debería anotarse para una futura iteración en vez de añadirse de inmediato a la Iteración 2 en curso.

Soluciones

Requisito Iteración Endpoint aproximado
RF1 (alta de material) 2 POST /libros
RF2 (baja de material) 2 DELETE /libros/{isbn}
RF3 (búsqueda) 2 GET /libros?busqueda=...
RF4 (alta de socio) 2 POST /socios
RF5 (préstamo) 2 POST /prestamos
RF6 (devolución) 2 POST /prestamos/{id}/devolucion
RF7 (metadatos externos) 2 GET /libros/{isbn}/metadatos

Añadir un requisito nuevo a mitad de una iteración en curso rompe el principio central de la planificación por fases: cada iteración debe entregar un alcance cerrado y verificable antes de pasar a la siguiente. Aceptar el cambio de inmediato alargaría la Iteración 2 de forma impredecible y retrasaría el resto del plan; lo correcto es anotar la idea (por ejemplo, como "Iteración 5: reservas", fuera del alcance ya cerrado de este proyecto final) y continuar con lo ya planificado, igual que se haría con cualquier funcionalidad nueva propuesta durante el desarrollo, como ya se advirtió en la lección anterior.

Conclusión

Esta lección ha convertido el alcance general de la Lección 1 en algo mucho más concreto: siete requisitos funcionales trazables a código ya existente, un conjunto de requisitos no funcionales que se vigilan de forma continua, un plan en cuatro iteraciones pequeñas con dependencias claras entre ellas, una estimación relativa de esfuerzo, y la elección definitiva de tecnología en cada capa. Con este plan ya cerrado, la siguiente lección, Implementación, deja de planificar y empieza a ensamblar: construirá la estructura de solución con varios proyectos, registrará IRepositorioBiblioteca y Biblioteca en el contenedor de DI de ASP.NET Core, y expondrá los endpoints correspondientes a cada uno de los siete requisitos de esta lección.

Curso de Programación en C#

Módulo 1: Introducción a C#

Módulo 2: Estructuras de Control

Módulo 3: Programación Orientada a Objetos

Módulo 4: Conceptos Avanzados de C#

Módulo 5: Trabajando con Datos

Módulo 6: Temas Avanzados

Módulo 7: Construcción de Aplicaciones

Módulo 8: Mejores Prácticas y Patrones de Diseño

Módulo 9: Proyecto Final

© Copyright 2026. Todos los derechos reservados