A Definició del projecte va quedar tancat el què: un document d'una pàgina amb el problema, l'abast en calaixos MoSCoW, els requisits numerats i els seus criteris d'acceptació. Ara toca el com, i encara no toca teclejar codi. Dissenyar és prendre per avançat les decisions cares: quines entitats existeixen i si són classes o diccionaris, en quin format es desen les dades, com es reparteix el programa en mòduls, què veu l'usuari a la pantalla i quins algorismes calen. Cadascuna d'aquestes decisions, presa sobre paper, costa deu minuts; presa a mitja implementació costa una tarda de reescriptura. Al final de la lliçó tindràs també el pla de treball: la llista de tasques petites, estimades i ordenades, que converteix «fer un projecte» en «fer la tasca següent».

Contingut

  1. Què és dissenyar i quant disseny n'hi ha prou
  2. Model de dades: entitats i atributs
  3. Diccionari, classe o llista?
  4. El diagrama de classes del projecte
  5. Persistència: triar el format del fitxer
  6. Arquitectura en capes
  7. Disseny de la interfície
  8. Algorismes no trivials en pseudocodi
  9. Planificació temporal per sessions
  10. Preparar el repositori i l'entorn
  11. Errors comuns i consells
  12. Exercicis
  13. Conclusió

  1. Què és dissenyar i quant disseny n'hi ha prou

Dissenyar és decidir la forma del programa abans de construir-lo: les seves peces, les seves responsabilitats i com es parlen entre elles. La pregunta raonable és quant. La resposta, per a un projecte d'aquesta mida, és: el just per poder començar a programar sense dubtes la primera hora, i prou.

Un disseny suficient per al teu projecte final cap en tres o quatre fulls i conté sis coses:

Peça del disseny Pregunta que respon Format
Model de dades Quines coses existeixen i què en deso, de cadascuna? Taula d'entitats i atributs
Estructura triada Classe, diccionari o llista per a cada entitat? Decisió justificada en una línia
Persistència On i com es desen? Format de fitxer amb un exemple real
Arquitectura Quins mòduls hi ha i de què depèn cadascun? Diagrama de dependències
Interfície Què veu i tria l'usuari? Mapa del menú i esbós de pantalles
Algorismes Quines parts no són òbvies? Pseudocodi amb prova d'escriptori

El que no és disseny a aquest nivell: escriure totes les funcions per endavant, decidir el nom de cada variable o fer diagrames de vint caixes. Això s'anomena paràlisi per anàlisi i consumeix el temps del projecte. Si dubtes entre dues opcions i cap no és clarament pitjor, tria la més simple i continua: al mòdul 8 vas aprendre a refactoritzar, i refactoritzar existeix precisament perquè cap disseny inicial no és perfecte.

  1. Model de dades: entitats i atributs

Una entitat és un substantiu important del teu domini: alguna cosa de la qual deses diversos exemplars i de la qual vols saber coses. La manera més ràpida de trobar-les és subratllar els substantius dels requisits de 09-01. A LesMevesDespeses, els RF parlen de despesa, ingrés, import, categoria, data, concepte i mes.

D'aquesta llista cal separar el gra de la palla amb dues preguntes:

  • En deso molts exemplars, d'això? «Despesa» sí; «mes» no, és només un criteri de filtratge.
  • Té atributs propis més enllà del seu nom? «Categoria» a LesMevesDespeses només té nom, així que no cal que sigui una entitat: n'hi ha prou amb una cadena dins del moviment.

Aquest segon descart és el que més simplifica un primer projecte. Aplicat a LesMevesDespeses queda una sola entitat real:

Entitat Atribut Tipus Obligatori Regles
Moviment id int Automàtic, únic, correlatiu
data date No futura; buit = avui
concepte str 1 a 60 caràcters, sense espais sobrants
quantitat float Diferent de 0; negatiu = despesa, positiu = ingrés
categoria str En minúscules; una de les categories conegudes

Fixa't en la decisió de l'última fila de la quantitat: en lloc d'un camp tipus amb els valors "despesa" o "ingres", el signe de l'import codifica el tipus. És una decisió de disseny amb conseqüències bones —el saldo del mes és una simple suma— i una conseqüència dolenta: cal recordar-la i documentar-la, perquè no és evident. Aquest tipus de decisió és exactament el que et preguntaran a Presentació del projecte, així que anota-la ara amb el seu perquè.

A més de les entitats, defineix les constants del domini: a LesMevesDespeses, les categories permeses.

CATEGORIES = ("menjar", "transport", "oci", "llar", "salut", "ingressos", "altres")

És una tupla i no una llista perquè no canvia durant l'execució (05-04), i és en un únic lloc perquè afegir una categoria sigui editar una línia, no buscar per tot el codi.

  1. Diccionari, classe o llista?

Amb les entitats identificades cal triar la seva representació en Python, aplicant la taula de decisió de Tuples i estructures imbricades i el que vas aprendre a De les dades als objectes:

Fes servir... Quan... A LesMevesDespeses
Llista Només hi ha una seqüència de valors del mateix tipus, sense nom propi Els imports d'un mes per sumar-los
Tupla Un grup petit i fix de valors que no canvia CATEGORIES; el parell (categoria, total) d'un informe
Diccionari Camps amb nom, estructura que canvia o dades que vénen de JSON El resultat d'agrupar per categoria: {"menjar": -212.4, ...}
Classe Les dades tenen comportament: es validen, es formaten, es comparen Moviment

La regla que resol gairebé tots els dubtes és aquesta: si a més de desar dades escriuràs funcions que operen sempre sobre aquestes dades, és una classe. A LesMevesDespeses, un moviment es valida en crear-se (import diferent de zero, categoria coneguda, data no futura), es mostra formatat en una línia de taula i es compara per data per ordenar. Tres comportaments: classe, sens dubte.

I hi ha una segona classe que no és una entitat del domini però sí una peça del disseny, exactament com Agenda a TascaFàcil: la col·lecció amb lògica. Llibre és una entitat; Biblioteca és la classe que sap cercar, filtrar i resumir. A LesMevesDespeses es diu Quadern.

  1. El diagrama de classes del projecte

classDiagram
    class Moviment {
        +int id
        +date data
        +str concepte
        +float quantitat
        +str categoria
        +es_despesa() bool
        +to_dict() dict
        +from_dict(d) Moviment
        +__str__() str
    }
    class Quadern {
        -list moviments
        -int seguent_id
        +afegir(mov) Moviment
        +eliminar(id) bool
        +cercar(id) Moviment
        +del_mes(aaaa_mm) list
        +total_per_categoria(aaaa_mm) dict
        +saldo(aaaa_mm) float
        +__len__() int
        +__iter__()
    }
    class MovimentInvalid {
        <<exception>>
    }
    Quadern "1" o-- "*" Moviment : conte
    Moviment ..> MovimentInvalid : llanca

El diagrama diu tres coses d'un cop d'ull. Primera, que Quadern conté moviments: és composició (07-03), la mateixa relació que Agenda tenia amb Tasca. Segona, que la validació viu a Moviment i llança la seva pròpia excepció MovimentInvalid, igual que TascaInvalida a TascaFàcil: les dades es protegeixen a si mateixes i cap altra capa no pot crear un moviment invàlid. I tercera, una cosa que es veu pel que no hi apareix: ni Moviment ni Quadern no saben res de fitxers ni de print. Aquesta absència és l'arquitectura de l'apartat 6 dibuixada per omissió.

Dibuixa el teu diagrama amb dues o tres classes com a màxim. Si te'n surten sis, gairebé segur que unes quantes són atributs disfressats de classe.

  1. Persistència: triar el format del fitxer

Reprenent Desar dades en fitxers, tens tres opcions realistes:

Format Va bé quan Va malament quan Cost
Text pla Les dades són línies soltes sense estructura (notes, log) Hi ha camps per separar; arriben comes o salts de línia Mínim, però et toca inventar el format
CSV Registres plans i uniformes que algú obrirà al full de càlcul Hi ha llistes dins d'un camp o estructures imbricades Baix; csv de la biblioteca estàndard
JSON Hi ha imbricació, camps opcionals o tipus variats El fitxer s'ha d'obrir a Excel sense conversió Baix; json de la biblioteca estàndard

Per a LesMevesDespeses: JSON com a format principal, CSV com a exportació. El perquè és el que has de saber defensar: JSON conserva els tipus (un float torna com a float, no com la cadena "12.5"), admet créixer amb camps opcionals sense trencar els fitxers antics i json.load valida l'estructura per tu. CSV entra només on té avantatge real —RF-7, obrir el mes en un full de càlcul—, i com a sortida d'un sol sentit: s'exporta, no s'importa, cosa que estalvia tota la feina de reconstruir tipus des de text.

I ara l'important: escriu el format concret amb un exemple real abans de programar res. Aquest és despeses.json:

{
  "versio": 1,
  "seguent_id": 4,
  "moviments": [
    {"id": 1, "data": "2026-08-01", "concepte": "Compra setmanal", "quantitat": -62.35, "categoria": "menjar"},
    {"id": 2, "data": "2026-08-01", "concepte": "Abonament transport", "quantitat": -32.0, "categoria": "transport"},
    {"id": 3, "data": "2026-08-03", "concepte": "Nomina agost", "quantitat": 1450.0, "categoria": "ingressos"}
  ]
}

Tres detalls deliberats, i tots tres tenen justificació:

  • versio al principi. Avui no serveix de res; el dia que canviïs el format, el teu codi podrà llegir els fitxers vells en lloc de trencar-se. Costa una línia.
  • seguent_id desat, no recalculat. Si el calculessis com «el màxim id més un», en esborrar l'últim moviment reutilitzaries el seu id, i un id reutilitzat és una font de confusió.
  • Dates com a cadena AAAA-MM-DD. JSON no té tipus data. Aquest format és l'estàndard ISO 8601, es converteix amb date.fromisoformat() i, a més, ordena alfabèticament igual que cronològicament, cosa que simplifica filtres i ordenacions.

  1. Arquitectura en capes

Un programa se separa en capes per la raó que ja coneixes de Descompondre un programa en funcions i Mòduls, paquets i importacions: cada peça té una única raó per canviar. Si el càlcul del total per categoria estigués barrejat amb els print, no el podries provar sense simular la pantalla, ni canviar la presentació sense arriscar-te a tocar el càlcul.

Les quatre capes i el seu fitxer:

Capa Fitxer Responsabilitat Què té prohibit
Model model.py Entitats i les seves regles de validació print, input, fitxers
Lògica quadern.py Col·lecció i operacions: afegir, cercar, filtrar, agregar totals print, input, fitxers
Magatzem magatzem.py Llegir i escriure JSON i exportar CSV print, input
Interfície interficie.py Menú, input, print, format de pantalla Càlculs del domini
flowchart TD
    M["__main__.py<br/>arrencada"] --> I["interficie.py<br/>menu i pantalles"]
    I --> C["quadern.py<br/>logica de colleccio"]
    I --> A["magatzem.py<br/>JSON i CSV"]
    A --> C
    C --> MO["model.py<br/>Moviment i validacio"]
    A --> MO

Les fletxes van sempre cap avall: la interfície coneix la lògica, la lògica coneix el model, i el model no coneix ningú. Cap fletxa no puja. Aquesta regla, que sembla trivial, és la que permet escriure proves del model i de la lògica sense tocar la pantalla, i és la mateixa estructura que ja has vist funcionant a TascaFàcil (model.py, agenda.py, magatzem.py, interficie.py, __main__.py).

Afegeix __init__.py perquè el directori sigui un paquet i __main__.py per poder executar python -m lesmevesdespeses, exactament com es va fer a 07-04.

  1. Disseny de la interfície

Un menú mal dissenyat es nota a la demostració. Dibuixa el mapa abans de programar-lo:

flowchart TD
    Menu["MENU PRINCIPAL"] --> O1["1 Registrar despesa"]
    Menu --> O2["2 Registrar ingres"]
    Menu --> O3["3 Moviments del mes"]
    Menu --> O4["4 Resum per categoria"]
    Menu --> O5["5 Esborrar moviment"]
    Menu --> O6["6 Exportar mes a CSV"]
    Menu --> O0["0 Sortir"]
    O1 --> Menu
    O2 --> Menu
    O3 --> Menu
    O4 --> Menu
    O5 --> Conf["Confirmar s/n"] --> Menu
    O6 --> Menu
    O0 --> Fin["Desar i acabar"]

Tres regles de disseny que es llegeixen en aquest mapa: tot camí torna al menú (no deixis mai l'usuari en un lloc sense sortida), una sola pantalla de profunditat (res de submenús en un primer projecte) i les accions destructives demanen confirmació. L'opció 0 per sortir és convenció: el 0 és sempre al mateix lloc encara que la llista creixi.

Després esbossa cada pantalla en text, tal com la vols veure. No és cosmètica: en escriure l'esbós descobreixes quines dades necessites calcular.

=========================================
  RESUM DE 2026-08                   (4)
=========================================
  menjar          -212,40 EUR   38,1 %
  transport       -132,00 EUR   23,7 %
  llar             -98,50 EUR   17,7 %
  oci              -57,20 EUR   10,3 %
  altres           -57,00 EUR   10,2 %
-----------------------------------------
  Despeses        -557,10 EUR
  Ingressos      +1450,00 EUR
  SALDO           +892,90 EUR
=========================================

Aquest esbós acaba de generar tres requisits de càlcul que no eren explícits: cal el percentatge sobre el total de despeses, cal ordenar de major a menor despesa i cal separar despeses d'ingressos al peu. Dibuixar la pantalla és la manera més barata de trobar feina oculta.

  1. Algorismes no trivials en pseudocodi

La major part del teu projecte és codi evident. Però sempre hi ha dos o tres punts on no ho és, i aquests —només aquests— s'escriuen abans en pseudocodi, amb la tècnica de Del problema a l'algorisme. A LesMevesDespeses són dos.

Algorisme 1: total per categoria d'un mes.

FUNCIO total_per_categoria(moviments, mes):
    totals <- diccionari buit
    PER A CADA m EN moviments:
        SI m.data comenca per mes LLAVORS
            totals[m.categoria] <- totals.obtenir(m.categoria, 0) + m.quantitat
    RETORNA totals ordenat per valor ascendent

Dues decisions concretes aquí. La comparació per prefix de cadena ("2026-08-03" comença per "2026-08") funciona perquè el format ISO ho permet, la decisió de l'apartat 5 pagant dividends. I obtenir(clau, 0) és el patró d'acumulació en diccionari de Diccionaris i conjunts, que evita el if clau not in totals. L'ordre ascendent per valor posa primer els imports més negatius, és a dir, les despeses més grans, que és el que demana l'esbós de l'apartat 7.

Prova d'escriptori amb quatre moviments i mes = "2026-08":

Pas Moviment Coincideix? totals després
1 2026-07-30, -20,00, menjar No {}
2 2026-08-01, -62,35, menjar {menjar: -62,35}
3 2026-08-01, -32,00, transport {menjar: -62,35, transport: -32,00}
4 2026-08-04, -15,00, menjar {menjar: -77,35, transport: -32,00}

Resultat ordenat: [("menjar", -77,35), ("transport", -32,00)]. Correcte: la despesa de juliol queda fora i les dues compres de menjar s'acumulen a la mateixa clau. Aquesta taula, feta en tres minuts sobre paper, és la que evita descobrir a la demostració que el filtre de mes agafava també l'any equivocat.

Algorisme 2: assignar el següent identificador.

FUNCIO afegir(quadern, moviment):
    moviment.id <- quadern.seguent_id
    quadern.seguent_id <- quadern.seguent_id + 1
    afegir moviment a la llista
    RETORNA moviment

Sembla massa simple per escriure'l, i precisament per això convé: escrit així es veu que el comptador s'ha de persistir amb les dades (apartat 5) i que hi ha un cas límit, la primera arrencada sense fitxer, on seguent_id val 1.

  1. Planificació temporal per sessions

Un projecte de 15 a 25 hores no es planifica «per setmanes»: es parteix en tasques d'una a tres hores, cadascuna amb un resultat visible. Si una tasca no cap en tres hores, parteix-la; si no la saps estimar, és que encara no l'entens i cal dissenyar-la una mica més.

# Tasca Est. Depèn de Resultat visible
T1 Repositori, entorn, esquelet que arrenca i surt 1 h python -m lesmevesdespeses mostra el menú i surt
T2 Classe Moviment amb validació i MovimentInvalid 2 h T1 Es crea un moviment des de l'intèrpret
T3 tests/test_model.py 1 h T2 pytest en verd
T4 Classe Quadern: afegir, cercar, eliminar, __len__ 2 h T2 Alta i baixa des de l'intèrpret
T5 magatzem.py: desar i carregar JSON 2 h T2 El fitxer es crea i es rellegeix
T6 tests/test_magatzem.py amb tmp_path 1 h T5 Cicle desar/carregar provat
T7 Interfície: menú, registrar despesa (RF-1) de cap a cap 3 h T4, T5 Primera funcionalitat completa
T8 Llistar moviments del mes (RF-3) 2 h T7 Pantalla de llistat
T9 total_per_categoria i saldo + proves (RF-4) 3 h T4, T3 Pantalla de resum
T10 Registrar ingrés (RF-2) i esborrar (RF-5) 2 h T7 Menú complet dels Must
T11 Exportar CSV (RF-7) 2 h T8 Fitxer obert al full de càlcul
T12 Robustesa: try/except, logging, revisió d'entrades 2 h T10 Cap entrada no trenca el programa
T13 README, docstrings, black i ruff, etiqueta v1.0 2 h T12 Repositori presentable

Total estimat: 25 hores. I ara la regla que gairebé ningú no aplica la primera vegada: multiplica la teva estimació per 1,5. No perquè siguis lent, sinó perquè totes les estimacions de principiant ometen el temps de buscar errors. Si el resultat no cap en el temps de què disposes, no acceleris: treu un Should.

flowchart LR
    H1["Fita 1<br/>Arrenca i surt<br/>T1"] --> H2["Fita 2<br/>Model provat<br/>T2 T3"]
    H2 --> H3["Fita 3<br/>Desa i carrega<br/>T4 T5 T6"]
    H3 --> H4["Fita 4<br/>Primer RF complet<br/>T7"]
    H4 --> H5["Fita 5<br/>Tots els Must<br/>T8 T9 T10"]
    H5 --> H6["Fita 6<br/>v1.0 presentable<br/>T11 T12 T13"]

El principi que ordena tot això: l'esquelet que arrenca ha d'existir el primer dia. Un python -m lesmevesdespeses que mostri el menú i surti, encara que les opcions no facin res, resol de cop l'entorn, l'estructura del paquet i l'execució, que són justament els problemes que bloquegen qui comença. A partir d'aquí el programa no torna a estar trencat mai: cada tasca el deixa executable.

  1. Preparar el repositori i l'entorn

Abans de la primera línia de codi, deixa el terreny a punt. És la tasca T1 i són quinze minuts, reprenent Entorns de desenvolupament i Control de versions:

mkdir lesmevesdespeses-projecte && cd lesmevesdespeses-projecte
python -m venv .venv
source .venv/bin/activate        # a Windows: .venv\Scripts\activate
pip install pytest black ruff
pip freeze > requirements-dev.txt

git init
mkdir lesmevesdespeses tests
touch lesmevesdespeses/__init__.py lesmevesdespeses/__main__.py lesmevesdespeses/model.py
touch lesmevesdespeses/quadern.py lesmevesdespeses/magatzem.py lesmevesdespeses/interficie.py

El .gitignore, amb el que no ha d'entrar mai al repositori:

.venv/
__pycache__/
*.pyc
despeses.json
*.log
.pytest_cache/

Repara en despeses.json: les dades personals no es versionen. Al repositori hi va dades_exemple.json amb moviments inventats, i el fitxer real de treball queda fora. És el mateix criteri pel qual tascafacil.log estava exclòs a TascaFàcil.

I el primer commit, que ja deixa constància del disseny:

git add .
git commit -m "Estructura inicial del projecte i document de definicio"

Errors Comuns i Consells

  • Dissenyar de més. Diagrames de quinze classes, jerarquies d'herència per si de cas, una capa d'abstracció sobre el fitxer «per si algun dia és una base de dades». Aquest dia no arribarà en aquest projecte. Dissenya per al que hi ha al calaix Must.
  • Convertir en classe tot el que es mou. Si una entitat només té nom i cap comportament —com categoria a LesMevesDespeses—, és una cadena. Una classe d'un sol atribut gairebé sempre sobra.
  • Triar el format de dades per costum. CSV sembla més simple fins que necessites desar una llista dins d'un camp o recuperar un número que va tornar com a cadena. Tria amb la taula de l'apartat 5, no per inèrcia.
  • Saltar-se l'esbós de pantalles. És el pas que més feina oculta descobreix: a LesMevesDespeses van aparèixer tres càlculs que cap requisit no esmentava.
  • Planificar en tasques grans. «Fer la interfície» no és una tasca, és un mes de sensació de no avançar. Una tasca és «registrar una despesa de cap a cap»: tres hores i un resultat que es veu.
  • Consell: escriu el perquè de cada decisió. Una línia per decisió al DEFINICIO.md («JSON perquè conserva tipus i admet camps nous»). A 09-04 hauràs de defensar-les i no te'n recordaràs.
  • Consell: si dubtes entre dos dissenys, tria el que sigui més fàcil de desfer. És gairebé sempre el més simple, i ja saps refactoritzar (08-05).

Exercicis

Continuen el projecte que vas definir a 09-01. Desa els resultats en un DISSENY.md al costat del DEFINICIO.md.

Exercici 1: Model de dades i diagrama de classes

Subratlla els substantius dels teus requisits i munta la taula d'entitats amb els seus atributs, tipus, obligatorietat i regles de validació. Justifica en una línia per entitat si serà classe, diccionari o llista. Dibuixa el diagrama de classes en mermaid, incloent-hi la classe col·lecció i l'excepció pròpia. Màxim tres classes.

Exercici 2: Persistència, capes i interfície

Tria el format de fitxer amb la taula de l'apartat 5 i escriu un exemple real del teu fitxer de dades amb tres registres. Reparteix el codi en els mòduls de les quatre capes i dibuixa el diagrama de dependències. Dibuixa el mapa del menú i esbossa en text les dues pantalles més importants del teu programa.

Exercici 3: Algorismes i pla de treball

Identifica els dos o tres algorismes no trivials del teu projecte, escriu-los en pseudocodi i fes una prova d'escriptori d'almenys un amb quatre o cinc dades d'entrada. Després munta la taula de tasques d'una a tres hores amb estimació i dependències, multiplica el total per 1,5 i comprova si cap en el teu temps disponible. Si no hi cap, indica quin Should elimines.

Solucions

Solució 1. Els apartats 2, 3 i 4 són la solució per a LesMevesDespeses: una única entitat Moviment (classe, perquè valida, formata i es compara), la categoria reduïda a cadena, i Quadern com a col·lecció amb lògica. El descart de Categoria com a classe és el punt interessant: només tenia nom. Si el teu projecte necessités pressupost per categoria, la decisió s'invertiria, perquè aleshores sí que tindria atributs i comportament propis. Rúbrica: tens tres classes o menys? Cada classe té almenys dos comportaments que justifiquin ser-ho? Cada atribut té tipus i regla de validació? Hi ha una excepció pròpia per a les dades invàlides?

Solució 2. Apartats 5, 6 i 7. Els criteris que has de poder defensar: JSON perquè hi ha tipus numèrics i el format pot créixer; CSV només com a exportació d'un sentit; les capes separades per poder provar la lògica sense pantalla; el menú d'una sola profunditat amb confirmació en l'esborrat. Rúbrica: l'exemple de fitxer és JSON o CSV vàlid de debò, amb tres registres reals? Totes les fletxes del diagrama de dependències van cap avall, sense cicles? El teu esbós de pantalla t'ha descobert algun càlcul que no havies previst? Si no n'ha descobert cap, mira-te'l una altra vegada: gairebé sempre n'hi ha un.

Solució 3. Apartats 8 i 9. Observa que les tretze tasques de LesMevesDespeses segueixen l'ordre model → proves → lògica → magatzem → interfície → extres, amb T1 (l'esquelet que arrenca) en primer lloc i T7 marcant la fita de la primera funcionalitat completa. Aquest és l'ordre de construcció que desenvolupa Implementació i proves. Rúbrica: cap tasca no passa de tres hores? Cada tasca té un resultat visible i verificable? Hi ha una tasca T1 d'una hora que deixa el programa arrencant? Has aplicat el factor 1,5? El teu pseudocodi és independent de Python, és a dir, el podries traduir a un altre llenguatge?

Conclusió

Dissenyar és prendre per avançat les decisions cares, i per a un projecte d'aquesta mida cap en tres o quatre fulls. El model de dades surt de subratllar els substantius dels requisits i descartar els que no tenen ni exemplars múltiples ni atributs propis; cada entitat es representa com a llista, tupla, diccionari o classe segons la taula de 05-04 i 07-01, amb la regla que allò que a més de dades té comportament és una classe. A les entitats s'hi suma la classe col·leccióAgenda a TascaFàcil, Quadern a LesMevesDespeses— que concentra la lògica de cercar, filtrar i resumir, i una excepció pròpia per a les dades invàlides.

La persistència es tria amb criteri: text pla per a línies sense estructura, CSV per a registres plans que veurà un full de càlcul, JSON quan hi ha tipus, imbricació o camps que creixeran; i s'escriu el format concret amb un exemple real abans de programar, amb detalls que després estalvien hores —número de versió, comptador d'identificadors persistit i dates en ISO AAAA-MM-DD, que ordenen alfabèticament igual que en el temps—. L'arquitectura en capes reparteix el codi en model, lògica, magatzem i interfície, amb les dependències sempre cap avall i el model sense conèixer ningú, que és el que permet provar sense pantalla. La interfície es dissenya amb un mapa de menú d'una sola profunditat on tot camí torna a l'inici i les accions destructives confirmen, més un esbós en text de cada pantalla que gairebé sempre descobreix càlculs ocults. Els dos o tres algorismes no trivials s'escriuen en pseudocodi i es validen amb una prova d'escriptori abans de traduir-los. I el pla de treball parteix tot en tasques d'una a tres hores amb resultat visible, ordenades per dependència, estimades i multiplicades per 1,5, amb l'esquelet que arrenca com a primeríssima tasca i el repositori i l'entorn preparats abans d'escriure una línia.

Amb el què i el com tancats, ja no queda res que impedeixi començar. A Implementació i proves construirem de debò: l'estratègia incremental que manté el programa sempre executable, l'ordre de construcció capa per capa amb les proves escrites alhora que el codi, què fer quan alguna cosa falla i no saps per què, i la checklist que decideix quan la implementació està acabada.

© Copyright 2026. Tots els drets reservats