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
- Requisitos funcionales: casos de uso concretos
- Requisitos no funcionales
- Planificación en fases: cuatro iteraciones
- Estimación básica de tareas por iteración
- Elección definitiva de tecnologías
- 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.
- 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/catchsobreHttpRequestException, devolviendonullen 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.
- 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.
- 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.
- 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
-
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.
-
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#
- Introducción a C#
- Configuración del Entorno de Desarrollo
- Programa Hola Mundo
- Sintaxis y Estructura Básica
- Variables y Tipos de Datos
- Arrays y Cadenas de Texto
Módulo 2: Estructuras de Control
Módulo 3: Programación Orientada a Objetos
- Clases y Objetos
- Métodos
- Constructores y Destructores
- Herencia
- Polimorfismo
- Encapsulamiento
- Abstracción
- Structs y Records: Tipos por Valor y por Referencia
Módulo 4: Conceptos Avanzados de C#
- Interfaces
- Delegados y Eventos
- Pattern Matching y Características Modernas de C#
- Genéricos
- Colecciones
- LINQ (Consulta Integrada en el Lenguaje)
- Programación Asíncrona
Módulo 5: Trabajando con Datos
- Entrada/Salida de Archivos
- Serialización
- Conectividad con Bases de Datos
- Entity Framework
- Trabajo con JSON y Consumo de APIs REST
Módulo 6: Temas Avanzados
- Reflexión
- Atributos
- Programación Dinámica
- Gestión de Memoria y Recolección de Basura
- Multihilo y Programación Paralela
Módulo 7: Construcción de Aplicaciones
- Formularios de Windows
- WPF (Windows Presentation Foundation)
- ASP.NET Core
- Blazor
- Xamarin y .NET MAUI
Módulo 8: Mejores Prácticas y Patrones de Diseño
- Estándares de Codificación y Mejores Prácticas
- Patrones de Diseño
- Inyección de Dependencias e Inversión de Control
- Pruebas Unitarias
- Revisión y Refactorización de Código
