Onze mòduls després d'aquell print("Hola, món!"), tens totes les peces sobre la taula: un paquet papyrus amb models, errors i tests, dues maneres de servir-lo per la web i un laboratori de dades que respon preguntes de negoci. El que encara no has fet és construir un sistema sencer tu sol, des d'un full de requisits fins a un lliurable. Aquest salt — de seguir lliçons a decidir, implementar i verificar sense xarxa — és exactament el que separa qui "ha fet un curs de Python" de qui "sap construir amb Python". El mòdul 12 és el teu examen final autodidacta: Papyrus Online, la versió integral de la llibreria de l'Anna. Aquesta primera lliçó defineix el contracte: què es construeix, com es mesura que està bé, i què queda deliberadament fora.
Contingut
- Per què un projecte integrador (i per què ara)
- Què és Papyrus Online: el sistema complet
- Requisits funcionals (RF1-RF7)
- Requisits no funcionals (RNF1-RNF4)
- Criteris d'acceptació mesurables
- Abast: el que queda fora (i per què)
- Dos itineraris: API Flask o web Django
- Mapa de requisits → mòduls del curs
- Com treballar aquest mòdul
Per què un projecte integrador
Fins ara, cada lliçó et donava el problema i la manera de resoldre'l. A la feina real, ningú no ho fa, això: reps requisits (sovint vagues), i les decisions — quina estructura, quins errors, què provar — són teves. Un projecte integrador entrena tres músculs que cap lliçó aïllada no pot entrenar:
- Decisió sota ambigüitat: triar entre alternatives vàlides i assumir-ne les conseqüències (itinerari A o B, dict o llista, JSON o CSV).
- Integració: les peces que funcionen soles fallen juntes de maneres noves — rutes relatives que es trenquen, floats que no quadren, imports circulars. Depurar entre capes és una habilitat diferent de depurar dins d'una funció.
- Tancament: decidir quan una cosa està "feta" i lliurar-la. Els projectes personals solen morir al 80 %; aquest mòdul et dona criteris d'acceptació explícits perquè el 100 % existeixi i sigui assolible.
Les lliçons d'aquest mòdul no et donaran tot el codi. Et donaran estructura, esquelets, contractes i punts de control; tu implementes. Allà on una peça integri massa coses alhora (com el servei de vendes), hi haurà solució completa comentada. Per a la resta, solucions orientatives: si la teva és diferent però passa els criteris, és tan vàlida com la nostra.
Què és Papyrus Online
Papyrus Online és el sistema que l'Anna faria servir de veritat: gestiona el catàleg i els socis, registra vendes aplicant tarifes i cupons, ho persisteix tot a disc, ho exposa per una interfície web i genera cada mes un informe amb dades i un gràfic.
flowchart LR
subgraph Interficie["Interfície"]
API["API Flask (itinerari A)<br/>o web Django (itinerari B)"]
end
subgraph Core["Paquet papyrus (domini)"]
M["models: Llibre, Soci"]
S["serveis: vendes, cupons"]
E["errors: jerarquia ErrorPapyrus"]
end
subgraph Persistencia["Persistència"]
J["cataleg.json / socis.json"]
C["vendes.csv"]
end
subgraph Analisi["Anàlisi"]
I["informe mensual<br/>pandas + Matplotlib"]
end
API --> Core
Core --> Persistencia
Persistencia --> Analisi
Core -. "logging → dades/papyrus.log" .-> L[(papyrus.log)]
Fixa't en la direcció de les fletxes: la interfície usa el core, mai a l'inrevés. És la regla que M10 anomenava "la web tradueix, el paquet resol", i a 12-02 la convertirem en arquitectura.
Requisits funcionals
Numerats per poder referir-nos-hi durant tot el mòdul (a 12-04 cadascun tindrà el seu test):
- RF1 — Gestió de catàleg (CRUD): alta, consulta, modificació i baixa de llibres. Cada llibre té títol, autor, preu i estoc. No hi pot haver dos llibres amb el mateix títol (el títol és la clau, com a tot el curs).
- RF2 — Socis i descomptes: registre de socis amb codi únic (format
NOM-NNN, comLLUIS-001). Un soci identificat obté el 5 % de descompte (DESCOMPTE_SOCI = 0.05) sobre el preu amb IVA. Un codi inexistent s'ha de rebutjar ambSociInvalidError. - RF3 — Vendes amb cupons i control d'estoc: vendre N unitats d'un títol verifica l'estoc (si en falta,
EstocInsuficientErrori no es modifica res), aplica tarifa de soci si escau i cupó si escau (PAPYRUS10→ 10 %,SOCI5→ 5 %; cupó desconegut →CupoInvalidError), descompta estoc i registra la venda. - RF4 — Persistència: catàleg i socis en JSON; vendes en CSV amb columnes
data,titol,unitats,quantia. El sistema arrenca carregant els fitxers i no perd dades si una escriptura falla a mitges (guardat atòmic, com elTransaccioCatalegde M8). - RF5 — Interfície (a triar): itinerari A, API REST amb Flask (
GET/POST/PUT/DELETE /api/llibres,POST /api/vendes, errors 404/409/400 en JSON); itinerari B, web Django (llistat, detall, formulari de venda ambModelForm, admin actiu). - RF6 — Informe de dades mensual: a partir del CSV de vendes, un script genera: total d'unitats i quantia del mes, top 3 de títols, comparativa per dia de la setmana, i un gràfic guardat com a PNG. Amb
vendes_2026.csvha de reproduir els números canònics de M11 (520 unitats gen-jun, dissabte com a millor dia amb 130). - RF7 — Registre (logging): tota venda, error de negoci i operació de persistència queda registrada a
dades/papyrus.logamb el nivell adequat (INFOoperacions,WARNINGrebuigs de negoci,ERRORerrors tècnics).
Requisits no funcionals
- RNF1 — Tests: la lògica de negoci (RF1-RF4) coberta amb pytest. Mínim exigible: la suite de 12-04 (uns 25 tests) en verd. Els criteris d'acceptació de sota són l'especificació d'aquests tests.
- RNF2 — Type hints: totes les funcions públiques del paquet
papyrusanotades (paràmetres i retorn), com vas aprendre a 08-01. - RNF3 — Errors propis: cap error de negoci no es comunica amb
ValueErrorgenèric ni ambprint; sempre la jerarquiaErrorPapyrusde M7. La interfície els tradueix a codis HTTP o missatges d'usuari. - RNF4 — README: un
README.mdamb què és el projecte, com instal·lar-lo (venv +requirements.txt), com usar-lo i com executar els tests. Plantilla completa a 12-05.
Criteris d'acceptació mesurables
"Funciona" no és un criteri; això sí. Cada fila és verificable amb una acció concreta:
| Requisit | Criteri d'acceptació (verificable) |
|---|---|
| RF1 | Donar d'alta "Faust" dues vegades produeix error (409 a l'API / missatge al form); després d'esborrar un llibre, consultar-lo retorna LlibreNoTrobatError (404). |
| RF2 | Vendre L'Odissea a LLUIS-001 cobra 12.35 €; a la Júlia (sense soci), 13.00 €; amb codi PEPE-999, SociInvalidError. |
| RF3 | Vendre 5 Odissees amb estoc 4 llança EstocInsuficientError i l'estoc continua sent 4; Faust + soci + PAPYRUS10 cobra 18.67 €; cupó NOEXISTEIX → CupoInvalidError. |
| RF4 | Després de vendre i reiniciar el programa, l'estoc llegit de cataleg.json reflecteix la venda; matar el procés durant un guardat no deixa un JSON corrupte. |
| RF5 | A: els 6 endpoints responen amb els codis correctes (provat amb el test client). B: llistat, detall, venda i admin operatius (provat amb Client). |
| RF6 | Executar l'informe sobre vendes_2026.csv imprimeix 520 unitats totals i dissabte com a millor dia (130 u), i deixa informe_2026.png a disc. |
| RF7 | Després d'una venda rebutjada per estoc, dades/papyrus.log conté una línia WARNING amb el títol i les unitats demanades. |
| RNF1-4 | pytest en verd; mypy (o revisió manual) sense funcions públiques sense anotar; la cerca d'except Exception genèrics sense justificar dona zero; el README permet a una altra persona arrencar el projecte sense preguntar-te res. |
Les quanties surten de la fórmula de tot el curs: preu × 1.04 (IVA) × 0.95 (soci), arrodonit a 2 decimals, i el cupó s'aplica sobre aquest resultat. Verifica-ho amb els quatre llibres canònics: L'Odissea 12.50 → 13.00 / 12.35; Hamlet 9.95 → 10.35 / 9.83; El Quixot 15.90 → 16.54 / 15.71; Faust 21.00 → 21.84 / 20.75.
Abast: el que queda fora
Tan important com el què és el què no. Decidir l'abast és enginyeria; voler fer-ho tot és la manera més segura de no acabar res.
| Fora de l'abast | Per què | On reprendre-ho |
|---|---|---|
| Autenticació real (usuaris, contrasenyes, sessions) | Requereix seguretat seriosa (hashing, CSRF, tokens); mal feta és pitjor que absent | Extensions a 12-05 |
| Pagaments | Integració amb passarel·les externes, fora del temari | Extensions a 12-05 |
| Desplegament a producció | Servidors, HTTPS, dominis: un altre ofici | Extensions a 12-05 |
| Base de dades SQL a l'itinerari A | JSON/CSV són suficients per al volum de Papyrus i són el que has practicat a M6 | Extensions a 12-05 |
| Front-end elaborat (JavaScript, CSS avançat) | El curs és de Python; un HTML mínim és suficient | Extensions a 12-05 |
Si en acabar et quedes amb ganes, perfecte: 12-05 ordena aquestes extensions per dificultat. Però primer es lliura l'abast acordat.
Dos itineraris
RF5 es compleix per un de dos camins. Tria segons què vulguis reforçar, no segons quin "sona millor":
| Itinerari A — API Flask | Itinerari B — web Django | |
|---|---|---|
| Què construeixes | API REST JSON sobre el teu paquet papyrus |
Aplicació web amb plantilles, forms i admin |
| Base del curs | 10-02 i 10-03 | 10-04 i 10-05 |
| Persistència | Els teus repositoris JSON/CSV (RF4 íntegre) | ORM de Django per al catàleg; les vendes segueixen en CSV |
| Esforç relatiu | Menor en interfície, major en persistència (tot és teu) | Major en interfície (plantilles, forms), menor en persistència (l'ORM regala molt) |
| Reforça | Disseny d'APIs, codis HTTP, separació de capes | Frameworks complets, convencions, ORM |
| Risc típic | Oblidar validar l'entrada JSON | Ficar lògica de negoci a les vistes |
| Tria'l si… | T'estira el backend pur o el treball amb dades | T'estira el desenvolupament web de producte |
Els dos itineraris comparteixen el 70 % del projecte (tot el core, la persistència de vendes, l'informe i els tests de negoci). La decisió afecta només la fita H4 de la planificació.
Mapa de requisits → mòduls del curs
Res d'aquest projecte no és nou. Cada requisit apunta a mòduls on ja ho vas aprendre — aquesta taula és la teva xuleta d'"on repassar":
| Requisit | Què necessita | Mòdul(s) on es va aprendre |
|---|---|---|
| RF1 catàleg | dataclass Llibre, diccionaris com a índex, funcions del magatzem |
M5 (05-06), M4 (04-03), M3 |
| RF2 socis | Validació, SociInvalidError, constants |
M2, M7 (07-04), M1 |
| RF3 vendes i cupons | Condicionals, excepcions pròpies, aplicar_cupo, arrodoniment |
M2, M7, M3, M1 (floats) |
| RF4 persistència | JSON, CSV, pathlib, guardat atòmic amb context manager |
M6, M8 (08-04) |
| RF5-A API Flask | Rutes, JSON, codis d'estat, errorhandler |
M10 (10-02, 10-03) |
| RF5-B web Django | Models, vistes, plantilles, ModelForm, admin |
M10 (10-04, 10-05) |
| RF6 informe | pandas (groupby), Matplotlib (savefig) |
M11 (11-03, 11-04) |
| RF7 logging | logging amb nivells i fitxer |
M7 (07-05) |
| RNF1 tests | pytest, fixtures, parametrize, tmp_path |
M9 (09-01 a 09-03) |
| RNF2 type hints | Anotacions com a especificació | M8 (08-01) |
| RNF3 errors | Jerarquia ErrorPapyrus |
M7 (07-04) |
| RNF4 README | Entorns virtuals, pip, requirements | M1 (01-06) |
I M11 complet, amb la seva regressió? Reapareix a 12-05: l'informe final inclourà una recomanació a l'estil de la comanda de Sant Jordi (predicció 172, comanda de l'Anna 190 — el model recomana, la persona decideix).
Com treballar aquest mòdul
Les cinc lliçons segueixen el cicle de vida real d'un projecte: requisits (aquesta), disseny (12-02), construcció (12-03), verificació (12-04) i lliurament (12-05). Treballa amb l'editor obert: cada lliçó acaba amb fites que has de completar abans de la següent. Reutilitza el teu codi de mòduls anteriors sense vergonya — reutilitzar el que és propi és el que fan els professionals — però copia'l a un projecte nou i neteja'l en passar-lo: el projecte final mereix començar en una carpeta neta.
Errors Comuns i Consells
- Començar a programar avui mateix. La temptació és enorme i l'error, clàssic: sense el disseny de 12-02 acabaràs reescrivint. Un dia de disseny estalvia tres dies de refactor.
- Ampliar l'abast a mig camí ("ja que hi soc, li poso login…"). Se'n diu scope creep i mata més projectes personals que cap bug. Apunta la idea per a 12-05 i continua.
- Triar l'itinerari B "perquè Django és més professional". Cap dels dos no és més professional; són oficis diferents. Tria pel que vulguis reforçar.
- Tractar els criteris d'acceptació com a decoratius. Són el contracte: a 12-04 es converteixen un a un en tests. Si un criteri et sembla ambigu ara, redacta'l millor ara — és molt més barat que descobrir l'ambigüitat amb el codi escrit.
- Saltar-se les quanties canòniques. 12.35, 9.83, 15.71, 20.75 fa tot el curs que són la veritat. Si el teu sistema dona un altre número, el bug és teu, no de la taula.
Exercicis
Aquest mòdul substitueix els exercicis de pràctica per fites de projecte: treball real sobre el teu lliurable, amb criteris de verificació.
- Fita 0.1 — Tria itinerari i deixa-ho per escrit. Crea la carpeta del projecte (
papyrus_online/) amb un fitxerDECISIONS.mdi escriu-hi 3-5 línies: quin itinerari tries i per què, en termes de què vols reforçar. Aquest fitxer creixerà durant tot el mòdul. - Fita 0.2 — Auditoria de peces reutilitzables. Recorre el teu codi de M1-M11 i llista a
DECISIONS.mdquins fitxers reutilitzaràs (amb el seu origen) i quins faràs de zero. Mínim: revisamodels.py,errors.py,cupons.py,magatzem.py, els teus tests de M9 i la teva app de M10. - Fita 0.3 — Un criteri més. Redacta un criteri d'acceptació addicional per al requisit que pitjor entenguis, amb el format de la taula (acció concreta → resultat verificable). Redactar-lo t'obligarà a entendre el requisit.
Solucions
Orientatives — l'important és que existeixin i siguin concretes:
- Exemple vàlid: «Itinerari A. A M10, Django em va resultar més guiat i Flask em va deixar més dubtes sobre codis HTTP i validació d'entrada; vull tancar aquests dubtes. A més, l'itinerari A m'obliga a fer la persistència sencera, que és on em sento menys segur.»
- Reutilitzables típics:
models.py(M5, afegint-hiSoci),errors.py(M7, tal qual),cupons.py(M7, tal qual),aplicar_cupoi constants de M1; de zero o molt retocats:magatzem.py(passarà a serveis + repositoris a 12-02), la interfície (es refà sobre el disseny nou), l'informe (guió nou sobre el que has après a M11). - Exemple per a RF4: «Executo una venda, mato el procés, torno a arrencar: el catàleg carrega sense error i l'estoc és coherent (o la venda completa es va aplicar, o no es va aplicar res — mai a mitges).» Si el teu criteri no diu com verificar-lo, no és un criteri: és un desig.
Conclusió
Ja tens el contracte: set requisits funcionals, quatre de no funcionals, criteris d'acceptació que es poden comprovar (i que a 12-04 es convertiran en tests), un abast amb fronteres clares i dos itineraris entre els quals ja has triat. També has vist que no hi ha res de nou per aprendre: cada requisit apunta a un mòdul on ja vas viure la solució. El que és nou és l'acoblament — i l'acoblament comença pel plànol. A la propera lliçó convertirem aquests requisits en un pla: fites ordenades, arquitectura en capes, esquemes de dades i contractes de funcions escrits abans de programar. Resisteix un dia més la temptació de l'editor: primer el plànol, després els maons.
Curs de Programació en Python
Mòdul 1: Introducció a Python
- Introducció a Python
- Configuració de l'Entorn de Desenvolupament
- Sintaxi de Python i Tipus de Dades Bàsics
- Variables i Constants
- Entrada i Sortida Bàsica
- Entorns Virtuals i Gestió de Paquets
Mòdul 2: Estructures de Control
Mòdul 3: Funcions i Mòduls
- Definició de Funcions
- Arguments de Funció
- Funcions Lambda
- Mòduls i Paquets
- Visió General de la Biblioteca Estàndard
Mòdul 4: Estructures de Dades
Mòdul 5: Programació Orientada a Objectes
Mòdul 6: Gestió de Fitxers
- Lectura i Escriptura de Fitxers
- Treball amb Fitxers CSV
- Gestió de Dades JSON
- Operacions amb Fitxers i Directoris
Mòdul 7: Gestió d'Errors i Excepcions
- Introducció a les Excepcions
- Gestió d'Excepcions
- Llançament d'Excepcions
- Excepcions Personalitzades
- Bones Pràctiques i Registre d'Errors amb logging
Mòdul 8: Temes Avançats
- Anotacions de Tipus (type hints)
- Decoradors
- Generadors
- Gestors de Context
- Concurrència: Fils i Processos
- Asyncio per a la Programació Asíncrona
Mòdul 9: Proves i Depuració
- Introducció a les Proves
- Proves Unitàries amb unittest
- Proves amb pytest
- Desenvolupament Guiat per Proves
- Tècniques de Depuració
- Ús de pdb per a la Depuració
Mòdul 10: Desenvolupament Web amb Python
- Introducció al Desenvolupament Web
- Fonaments del Framework Flask
- Construcció d'APIs REST amb Flask
- Introducció a Django
- Construcció d'Aplicacions Web amb Django
Mòdul 11: Ciència de Dades amb Python
- Introducció a la Ciència de Dades
- NumPy per a la Computació Numèrica
- Pandas per a la Manipulació de Dades
- Matplotlib per a la Visualització de Dades
- Introducció a l'Aprenentatge Automàtic amb scikit-learn
