La lliçó anterior va fixar l'abast general del projecte final de BiblioTech i la seva arquitectura triada. Abans de tocar una sola línia de codi, aquesta lliçó converteix aquest abast en quelcom molt més concret: una llista precisa de requisits funcionals i no funcionals, i un pla de treball en iteracions petites que eviti la temptació d'intentar construir-ho tot de cop. Planificar abans de programar no és burocràcia innecessària: és el que permet, a la Lliçó 3, saber exactament què construir primer i per què, en comptes d'avançar a cegues ensamblant peces en un ordre arbitrari.
Contingut
- Requisits funcionals: casos d'ús concrets
- Requisits no funcionals
- Planificació en fases: quatre iteracions
- Estimació bàsica de tasques per iteració
- Elecció definitiva de tecnologies
- Requisits funcionals: casos d'ús concrets
Un requisit funcional descriu quelcom que el sistema ha de fer: una acció concreta que un usuari (o un client de l'API) pot sol·licitar i esperar-ne un resultat. Per a BiblioTech, la llista de requisits funcionals del projecte final és la següent:
| # | Cas d'ús | Entrada | Resultat esperat |
|---|---|---|---|
| RF1 | Donar d'alta un llibre o revista | Títol, autor, ISBN (o altres dades de Llibre/Revista, Mòdul 3) |
El material s'afegeix a Cataleg |
| RF2 | Donar de baixa un material del catàleg | Identificador del material | El material deixa d'aparèixer al catàleg |
| RF3 | Cercar materials per títol o autor | Text de cerca | Llista de materials que coincideixen (LINQ, Mòdul 4) |
| RF4 | Donar d'alta un soci | Nom del soci | El soci s'afegeix a Socis, amb un Id únic |
| RF5 | Registrar un préstec | ISBN del material, Id del soci |
Es crea un Prestec; el material queda marcat com a no disponible |
| RF6 | Registrar una devolució | Identificador del préstec | S'assigna DataDevolucio; es calcula la sanció si hi ha retard (Mòdul 8, IPoliticaSancio) |
| RF7 | Consultar metadades externes d'un llibre | ISBN | Dades addicionals del servei extern (Mòdul 5), o absència clara si no estan disponibles |
Cadascun d'aquests set requisits correspon, de forma gairebé directa, a un mètode ja existent a
Biblioteca o a una combinació petita d'ells —la mateixa taula és, en si mateixa, un mapa de quina
part del codi ja construït cobreix cada requisit.
- Requisits no funcionals
Un requisit no funcional no descriu una acció, sinó una qualitat que el sistema ha de tenir mentre fa el que fa. Són més difícils de verificar amb un simple cas d'ús, però igual d'importants:
- Rendiment raonable: les operacions de consulta (RF3, llistar el catàleg) han de respondre en un temps acceptable fins i tot amb un catàleg de mida moderada (centenars o pocs milers de materials); no es persegueix aquí cap objectiu de rendiment extrem, només evitar operacions evidentment ineficients (per exemple, carregar tot el catàleg en memòria a cada petició si una consulta a la base de dades ja n'hi hauria prou).
- Seguretat bàsica: l'API no ha d'exposar dades sensibles de forma innecessària (per exemple,
cadenes de connexió o detalls interns de la base de dades en els missatges d'error que retorna al
client); les cadenes de connexió de producció han de viure fora del codi font (Lliçó 5,
configuració per entorn), mai escrites directament a
Program.cs. - Mantenibilitat: gràcies a l'arquitectura del Mòdul 8 (
IRepositoriBiblioteca+ injecció de dependències + proves unitàries), canviar el mecanisme de persistència, afegir un nou endpoint, o corregir un error ha de poder fer-se sense reescriure parts del sistema no relacionades amb el canvi. - Fiabilitat davant de fallades externes: la consulta de metadades externes (RF7) depèn d'un
servei de tercers que pot fallar o no respondre; ja es va veure al Mòdul 5 que aquest cas es
captura amb
try/catchsobreHttpRequestException, retornantnullen comptes de propagar la fallada a qui va demanar les metadades.
A diferència dels requisits funcionals, aquests no es "marquen com a completats" amb una única prova puntual: es verifiquen de forma contínua al llarg de tot el projecte, i es revisen explícitament al checklist de qualitat de la Lliçó 4.
- Planificació en fases: quatre iteracions
Intentar construir les set funcionalitats de l'apartat 1 alhora, sense cap ordre, és la recepta més directa per quedar-se encallat a mig camí sense res que funcioni de cap a cap. En comptes d'això, el projecte s'organitza en quatre iteracions petites, cadascuna lliurant quelcom que funciona per si mateix abans de passar a la següent:
flowchart LR
I1["Iteracio 1<br/>Domini + Persistencia<br/>(ja construits, Moduls 3-5-8)"] --> I2["Iteracio 2<br/>API<br/>(Llico 3)"]
I2 --> I3["Iteracio 3<br/>Client / UI<br/>(Llico 3)"]
I3 --> I4["Iteracio 4<br/>Poliment<br/>(Llicons 4-5)"]
| Iteració | Què lliura | Quins requisits cobreix |
|---|---|---|
| 1. Domini + Persistència | Confirmar que Biblioteca, el model de domini i IRepositoriBiblioteca amb la seva implementació triada (apartat 5) compilen i funcionen de forma aïllada, sense API encara |
Base de RF1-RF7 (ja construïda en mòduls anteriors, només es verifica que segueix en ordre) |
| 2. API | Endpoints HTTP d'ASP.NET Core Minimal API sobre el domini, amb DI ja registrada | RF1-RF7 exposats per HTTP |
| 3. Client / UI | Un client senzill (Blazor, o una consola amb HttpClient) que consumeixi l'API de la Iteració 2 |
Verificació d'extrem a extrem de RF1-RF7 des de fora del procés de l'API |
| 4. Poliment | Proves d'integració, logging, checklist de qualitat, desplegament | Requisits no funcionals de l'apartat 2 |
Aquesta divisió en iteracions no és arbitrària: cadascuna depèn exclusivament de l'anterior, i
cadascuna és, per si mateixa, quelcom verificable —una API que respon correctament a curl, encara
que no tingui client encara, ja és un resultat tangible de la Iteració 2, no una feina a mitges
sense cap valor propi.
- Estimació bàsica de tasques per iteració
Una estimació no necessita ser precisa al minut per ser útil; n'hi ha prou de donar una idea relativa d'esforç que ajudi a prioritzar i a detectar per endavant en quina iteració és més probable encallar-se:
| Iteració | Tasques principals | Esforç relatiu |
|---|---|---|
| 1. Domini + Persistència | Revisar que les quatre implementacions d'IRepositoriBiblioteca (Mòdul 8) segueixen compilant; triar-ne una per a producció |
Baix (ja construït, només verificació) |
| 2. API | Estructura de solució, registre de DI, 5-7 endpoints (un per requisit funcional) | Mitjà-alt (és la iteració amb més codi nou) |
| 3. Client / UI | Un component o pantalla per cas d'ús principal (catàleg, préstec, devolució) | Mitjà |
| 4. Poliment | Proves d'integració, logging, checklist, Dockerfile, configuració per entorn |
Mitjà |
La iteració amb més esforç relatiu (l'API) és, precisament, la que més es recolza en la feina ja feta al Mòdul 8: la major part d'aquesta "càrrega" és ensamblatge i registre de serveis, no lògica nova per inventar des de zero.
- Elecció definitiva de tecnologies
Amb els requisits ja clars, toca fixar, sense ambigüitat, quina tecnologia concreta es farà servir a cada capa —resumint les decisions ja presentades o comparades en mòduls anteriors:
| Capa | Tecnologia triada | Mòdul on es va explicar |
|---|---|---|
| Domini | Classes C# ja existents (MaterialBibliotecari, Llibre, Revista, Soci, Prestec) |
Mòdul 3 |
| Abstracció de persistència | IRepositoriBiblioteca |
Mòdul 8 (Lliçó 3) |
| Persistència concreta en producció | Entity Framework Core sobre SQLite (RepositoriEntityFramework + BibliotecaDbContext) |
Mòdul 5 |
| Injecció de dependències | Contenidor de serveis d'ASP.NET Core (AddScoped/AddSingleton/AddTransient) |
Mòdul 8 (Lliçó 3) |
| API | ASP.NET Core Minimal APIs | Mòdul 7 |
| Client | Blazor (o consumidor HttpClient senzill) |
Mòdul 7, Mòdul 5 |
| Proves | xUnit + Moq | Mòdul 8 (Lliçó 4) |
| Metadades externes | HttpClient contra un servei extern simulat |
Mòdul 5 |
L'elecció d'Entity Framework Core (en comptes de text, JSON o SQLite amb ADO.NET pur) com a
persistència de producció respon a un motiu concret: és l'única de les quatre opcions del Mòdul 5
pensada per escalar còmodament a mesura que el model de dades creixi, i s'integra de forma natural
amb el contenidor de DI d'ASP.NET Core mitjançant AddDbContext (ja vist a 08-03, apartat 7). Res
no impedeix, però, substituir-la per qualsevol de les altres tres en qualsevol moment: aquesta és,
precisament, la garantia que ofereix IRepositoriBiblioteca.
Errors Comuns i Consells
- Confondre requisits funcionals amb tasques d'implementació: "fer servir Entity Framework Core" no és un requisit funcional (no descriu què fa el sistema per a l'usuari), és una decisió tècnica de l'apartat 5; mantenir les dues coses separades evita llistes de requisits confuses.
- Saltar-se els requisits no funcionals per semblar "menys concrets": són tan reals com els funcionals, només que es verifiquen d'una altra manera (revisió contínua, checklist) en comptes d'amb un cas d'ús puntual.
- Planificar iteracions que depenen les unes de les altres de forma circular: si la Iteració 3 (Client) necessités canvis a la Iteració 1 (Domini) per funcionar, la planificació té un problema d'ordre; revisa que cada iteració només depengui de les anteriors, mai de les següents.
- Consell: si una iteració sembla "massa gran" en estimar-la, és bon senyal que es pot dividir en dues iteracions més petites, cadascuna amb el seu propi resultat verificable.
Exercicis
-
Per a cadascun dels set requisits funcionals (RF1-RF7) de la taula de l'apartat 1, indica en quina iteració de l'apartat 3 es cobreix principalment i quin endpoint HTTP (verb + ruta) esperaries que l'implementi a la Iteració 2.
-
Un company d'equip proposa afegir, a mig fer la Iteració 2, un requisit nou: "permetre reservar un llibre que no està disponible, perquè quedi apartat quan es retorni". Explica per què, segons els criteris de planificació d'aquesta lliçó, aquest requisit s'hauria d'anotar per a una futura iteració en comptes d'afegir-se immediatament a la Iteració 2 en curs.
Solucions
| Requisit | Iteració | Endpoint aproximat |
|---|---|---|
| RF1 (alta de material) | 2 | POST /libros |
| RF2 (baixa de material) | 2 | DELETE /libros/{isbn} |
| RF3 (cerca) | 2 | GET /libros?busqueda=... |
| RF4 (alta de soci) | 2 | POST /socios |
| RF5 (préstec) | 2 | POST /prestamos |
| RF6 (devolució) | 2 | POST /prestamos/{id}/devolucion |
| RF7 (metadades externes) | 2 | GET /libros/{isbn}/metadatos |
Afegir un requisit nou a mig fer una iteració en curs trenca el principi central de la planificació per fases: cada iteració ha de lliurar un abast tancat i verificable abans de passar a la següent. Acceptar el canvi immediatament allargaria la Iteració 2 de forma impredictible i retardaria la resta del pla; el correcte és anotar la idea (per exemple, com a "Iteració 5: reserves", fora de l'abast ja tancat d'aquest projecte final) i continuar amb el que ja estava planificat, igual que es faria amb qualsevol funcionalitat nova proposada durant el desenvolupament, tal com ja s'ha advertit a la lliçó anterior.
Conclusió
Aquesta lliçó ha convertit l'abast general de la Lliçó 1 en quelcom molt més concret: set requisits
funcionals traçables a codi ja existent, un conjunt de requisits no funcionals que es vigilen de
forma contínua, un pla en quatre iteracions petites amb dependències clares entre elles, una
estimació relativa d'esforç, i l'elecció definitiva de tecnologia a cada capa. Amb aquest pla ja
tancat, la lliçó següent, Implementació, deixa de planificar i comença a ensamblar: construirà
l'estructura de solució amb diversos projectes, registrarà IRepositoriBiblioteca i Biblioteca
al contenidor de DI d'ASP.NET Core, i exposarà els endpoints corresponents a cadascun dels set
requisits d'aquesta lliçó.
Curs de Programació en C#
Mòdul 1: Introducció al C#
- Introducció al C#
- Configuració de l'Entorn de Desenvolupament
- Programa Hola Món
- Sintaxi i Estructura Bàsica
- Variables i Tipus de Dades
- Arrays i Cadenes de Text
Mòdul 2: Estructures de Control
Mòdul 3: Programació Orientada a Objectes
- Classes i Objectes
- Mètodes
- Constructors i Destructors
- Herència
- Polimorfisme
- Encapsulació
- Abstracció
- Structs i Records: Tipus per Valor i per Referència
Mòdul 4: Conceptes Avançats de C#
- Interfícies
- Delegats i Esdeveniments
- Pattern Matching i Característiques Modernes de C#
- Genèrics
- Col·leccions
- LINQ (Consulta Integrada en el Llenguatge)
- Programació Asíncrona
Mòdul 5: Treballant amb Dades
- Entrada/Sortida de Fitxers
- Serialització
- Connectivitat amb Bases de Dades
- Entity Framework
- Treball amb JSON i Consum d'APIs REST
Mòdul 6: Temes Avançats
- Reflexió
- Atributs
- Programació Dinàmica
- Gestió de Memòria i Recollida d'Escombraries
- Multifil i Programació Paral·lela
Mòdul 7: Construcció d'Aplicacions
Mòdul 8: Bones Pràctiques i Patrons de Disseny
- Estàndards de Codificació i Bones Pràctiques
- Patrons de Disseny
- Injecció de Dependències i Inversió de Control
- Proves Unitàries
- Revisió i Refactorització de Codi
