Amb la v0.21 el projecte està documentat, aguanta els errors, té historial i vuit proves que el verifiquen en centèsimes de segon. Falta l'últim, i és el que separa un programa que funciona d'un del qual un se sent orgullós: com està escrit. Perquè un programa s'escriu una vegada i es llegeix desenes: cada vegada que hi tornes, cada vegada que busques un error, cada vegada que algú nou entra al projecte. A TascaFàcil hi ha funcions a interficie.py que han crescut fins a les quaranta línies, el número 52 apareix solt en tres llocs, hi ha noms heretats de quan això era un exercici i blocs de codi que es repeteixen amb dues paraules canviades. Aquesta lliçó ho arregla tot: la guia d'estil oficial de Python, les eines que l'apliquen soles, l'art de posar bons noms, les olors de codi que delaten un problema i un catàleg de refactoritzacions que milloren el codi sense canviar el que fa —recolzant-te, precisament, en les proves que vas escriure a la lliçó anterior.
Contingut
- PEP 8: la guia d'estil de Python
- Convencions de noms
- El Zen de Python
- Eines: formatadors i linters
- Posar bons noms
- Olors de codi
- Què és refactoritzar (i què no)
- Catàleg de refactoritzacions
- TascaFàcil v1.0: revisat, formatat i refactoritzat
- Errors habituals i consells
- Exercicis
- Conclusió
- PEP 8: la guia d'estil de Python
PEP 8 és el document oficial que defineix com s'escriu Python. No canvia el comportament de res: defineix l'aspecte, i el seu valor rau en el fet que tothom escriu igual, així que qualsevol codi Python et resulta familiar des del primer minut. Aquestes són les seves regles pràctiques:
| Regla | Com es fa | Exemple |
|---|---|---|
| Indentació | 4 espais, mai tabuladors | return total |
| Longitud de línia | Màxim 79 caràcters (molts projectes fan servir 88) | Parteix la línia abans de passar-te'n |
| Línies en blanc | 2 entre funcions o classes de nivell superior, 1 entre mètodes | Separa les idees |
| Espais als operadors | Un a cada costat: a = b + c, no a=b+c |
total = dies * tarifa |
| Espais als arguments | Sense espai al voltant de l'= d'un valor per defecte |
def f(dies=1): |
| Comes | Espai al darrere, mai al davant | f(a, b), no f(a , b) |
| Imports | Un per línia i a dalt del fitxer | import json |
| Ordre dels imports | Estàndard → tercers → propis, separats per línia en blanc | Vegeu l'exemple |
# 1. Biblioteca estandard
import json
import logging
from pathlib import Path
# 2. Paquets de tercers (aqui no n hi ha: TascaFacil no en fa servir cap)
import pytest
# 3. Moduls propis del projecte
from .model import Tasca, PRIORITATS
from .agenda import AgendaAquest ordre no és un caprici: en mirar la capçalera d'un fitxer saps d'un cop d'ull què depèn de fora i què és del projecte. I una nota important sobre la longitud de línia: el límit existeix per poder llegir dos fitxers en paral·lel i perquè el diff de Git sigui llegible, no per nostàlgia de les pantalles antigues.
- Convencions de noms
El curs fa servir aquestes convencions des de Variables i tipus de dades; ara els posem el seu nom oficial:
| Estil | Es fa servir per a | Exemples del projecte |
|---|---|---|
snake_case |
Variables, funcions i mètodes | dies_restants, resum_per_responsable |
PascalCase |
Classes | Tasca, TascaRecurrent, Agenda |
MAJUSCULES |
Constants | PRIORITATS, EQUIP, AMPLE |
_privat |
Ús intern; «no toquis això des de fora» | _tasques, _normalitzar |
modul.py |
Mòduls i paquets: curts i en minúscula | model.py, magatzem.py |
El guió baix inicial mereix un aclariment, perquè a Python no impedeix res: agenda._tasques és perfectament accessible. És un acord entre programadors, no una barrera tècnica: significa «això és un detall intern, pot canviar demà i no hi hauries de dependre». Aquest acord és justament el que va permetre a 07-03 canviar per dins la llista d'Agenda sense trencar res a ningú.
- El Zen de Python
Escriu import this a l'intèrpret i apareixeran dinou aforismes que resumeixen la filosofia del llenguatge. Aquests cinc són els que més et serviran:
- «Explicit is better than implicit» (explícit millor que implícit). Per això
import formatguanya afrom format import *, i per això una funció que retornaTasca | Noneho diu a la seva signatura en lloc de deixar que ho descobreixis en fallar. - «Simple is better than complex» (simple millor que complex). Una cerca lineal en una llista de 200 tasques és la solució correcta; l'índex i l'arbre binari són una complexitat que ningú no ha demanat.
- «Readability counts» (la llegibilitat compta). És la raó de ser d'aquesta lliçó sencera: entre dues solucions igual de vàlides, guanya la que es llegeix millor.
- «Errors should never pass silently» (els errors mai no haurien de passar en silenci). Exactament el que vam dir a 08-02 sobre
except: pass. - «There should be one obvious way to do it» (hi hauria d'haver una manera òbvia de fer-ho). Per això el projecte sencer fa servir un sol estil de docstring i una sola manera de validar.
No són regles obligatòries sinó criteris per desempatar. Quan dubtis entre dues maneres d'escriure alguna cosa, pregunta't quina de les dues és més explícita, més simple i més llegible; gairebé sempre és la mateixa.
- Eines: formatadors i linters
El millor de tot l'anterior és que gairebé res d'això no s'ha de fer a mà. Hi ha dues famílies d'eines: els formatadors, que reescriuen el codi perquè compleixi l'estil, i els linters, que l'analitzen i avisen de problemes.
| Eina | Tipus | Què fa |
|---|---|---|
black |
Formatador | Reformata el fitxer sencer. No es configura: no hi ha discussió possible |
ruff |
Linter (i formatador) | Detecta problemes d'estil i de codi. Extremadament ràpid |
flake8 |
Linter | El clàssic: comprova PEP 8 i errors freqüents |
pylint |
Linter | El més exhaustiu i el més primmirat; puntua el teu codi |
mypy |
Comprovador de tipus | Verifica les anotacions de 08-01 sense executar el programa |
pip install black ruff mypy black tascafacil/ # reformata tot el paquet black --check tascafacil/ # nomes diu si faria canvis, sense tocar res ruff check tascafacil/ # llista els problemes trobats ruff check --fix tascafacil/ # arregla els que pot arreglar sol mypy tascafacil/ # comprova la coherencia dels tipus
La diferència entre els dos tipus és important: black no opina sobre el teu codi, només sobre el seu aspecte; et treu per sempre les discussions sobre cometes, espais i salts de línia. ruff sí que opina: et dirà que has importat alguna cosa que no fas servir, que una variable està definida i mai no es llegeix o que una funció és massa complexa. A VS Code s'integren en dos clics: instal·la l'extensió de Python, tria black com a formatador i activa «Format on Save»; a partir d'aquí l'estil deixa de ser una preocupació teva.
- Posar bons noms
És l'única cosa d'aquesta lliçó que cap eina no pot fer per tu, i probablement el que més influeix en la llegibilitat. Un bon nom diu què és o què fa, sense abreviatures críptiques ni informació redundant:
| Abans | Després | Per què |
|---|---|---|
d, x, tmp |
dies, tasca, pendents |
Una lletra només val en bucles molt curts |
llista_de_tasques_de_l_equip |
tasques |
Si el context ja ho diu, sobra |
processar(dades) |
normalitzar_prioritat(text) |
«Processar» no significa res |
flag |
esta_completada |
Els booleans es llegeixen com una pregunta |
get_t() |
cercar(titol) |
El nom ha de dir què retorna |
calcular() |
calcular_dies_restants() |
Calcular què? |
Tres criteris que ho resumeixen tot: els booleans comencen per un verb d'estat (esta_, hi_ha_, te_), les funcions comencen per un verb que diu què fan (cercar, desar, normalitzar) i les col·leccions van en plural (tasques, responsables). I si un nom necessita un comentari al costat per entendre's, el nom està malament.
- Olors de codi
Una olor de codi (code smell) no és un error: el programa funciona. És un senyal que alguna cosa donarà problemes aviat. Aquestes són les set que trobaràs una vegada i una altra:
| Olor | Com es reconeix | Solució |
|---|---|---|
| Funció massa llarga | No cap a la pantalla; fa diverses coses | Extreure funció |
| Massa paràmetres | Cinc o més; ningú no recorda l'ordre | Agrupar en un objecte o fer servir dataclass |
| Codi duplicat | El mateix bloc amb dues paraules canviades | Extreure una funció amb paràmetres |
| Números i cadenes màgics | 52, 0.21, "alta" solts per allà |
Substituir per constant amb nom |
| Imbricació profunda | Tres o més if ficats els uns dins dels altres |
Clàusula de guarda |
| Noms críptics | d, tmp2, processar |
Reanomenar |
| Comentari explicatiu | Un comentari que aclareix un tram confús | Extreure aquest tram a una funció ben anomenada |
L'últim és el més subtil i el més útil d'aprendre. Un comentari del tipus # aqui calculem el recarrec i apliquem el descompte està assenyalant, sense voler, que aquell bloc és una funció que encara no té nom. Extreu-lo i anomena'l aplicar_recarrec_i_descompte(): el comentari desapareix perquè ja no cal, i de passada el tros esdevé provable de manera aïllada.
- Què és refactoritzar (i què no)
Refactoritzar és canviar l'estructura interna del codi sense canviar en absolut el que fa. Aquesta segona part és la definició completa, i d'ella en surten dues conseqüències que convé tenir molt clares:
- No és refactoritzar afegir una funcionalitat, arreglar un error ni millorar el rendiment. Tot això canvia el comportament; refactoritzar, no.
- Mai no es fan les dues coses alhora. Si refactoritzes i afegeixes una funció al mateix commit i alguna cosa es trenca, no sabràs què ho ha trencat. Primer una cosa, després l'altra, cadascuna amb el seu commit (08-03).
I d'aquí en surt la regla d'or: abans de refactoritzar cal tenir proves. Les proves de 08-04 són les que responen a l'única pregunta que importa mentre reorganitzes el codi —«continua fent exactament el mateix?»— i les que converteixen l'operació en una cosa segura. El cicle és sempre aquest: proves en verd, un canvi petit, executar les proves, commit; i tornar a començar. Si en algun moment es posen en vermell, saps amb total certesa què ho ha provocat, perquè acabes de fer un sol canvi.
- Catàleg de refactoritzacions
Aquestes sis resolen la immensa majoria dels casos. Extreure funció parteix un bloc llarg en peces amb nom:
# ABANS: un bloc que fa tres coses
def mostrar_fitxa(tasca):
print("=" * 52)
print(f"{tasca.titol.upper():^52}")
print("=" * 52)
barra = "#" * int(tasca.progres() / 10) + "-" * (10 - int(tasca.progres() / 10))
print(f"Avanc: [{barra}] {tasca.progres():.0f}%")
# DESPRES: cada idea, amb el seu nom
def capcalera(text: str) -> str:
"""Retorna el text centrat entre linies de separacio."""
return f"{'=' * AMPLE}\n{text.upper():^{AMPLE}}\n{'=' * AMPLE}"
def barra_progres(percentatge: float) -> str:
"""Retorna una barra de 10 caselles per a aquest percentatge."""
plenes = int(percentatge / 10)
return "#" * plenes + "-" * (10 - plenes)Extreure variable explicativa converteix una expressió il·legible en una cosa que s'entén sola, i substituir el número màgic per una constant fa el mateix amb els valors solts:
# ABANS
if tasca.dies > 20 and tasca.prioritat == "alta" and not tasca.completada:
total *= 0.9
# DESPRES
DIES_PROJECTE_LLARG = 20
DESCOMPTE_LLARG = 0.9
es_projecte_llarg_urgent = (tasca.dies > DIES_PROJECTE_LLARG
and tasca.prioritat == "alta"
and not tasca.completada)
if es_projecte_llarg_urgent:
total *= DESCOMPTE_LLARGInvertir la condició i fer servir una clàusula de guarda aplana la imbricació profunda, que és l'olor que més costa de llegir:
# ABANS: tres nivells d imbricacio
def desar(agenda, ruta):
if agenda is not None:
if len(agenda) > 0:
if ruta.parent.exists():
escriure_json(agenda, ruta)
# DESPRES: els casos impossibles es descarten primer i se surt
def desar(agenda, ruta):
if agenda is None or len(agenda) == 0:
return
if not ruta.parent.exists():
raise FileNotFoundError(f"No existeix la carpeta {ruta.parent}")
escriure_json(agenda, ruta)Unificar duplicats i substituir una cadena d'if per un diccionari de despatx tanquen el catàleg. La segona és especialment rendible als menús:
# ABANS: una cadena que creix amb cada opcio nova
if opcio == "1":
crear_tasca(agenda)
elif opcio == "2":
llistar_tasques(agenda)
elif opcio == "3":
completar_tasca(agenda)
# DESPRES: un diccionari de despatx (funcions com a valors, 04-05)
ACCIONS = {"1": crear_tasca, "2": llistar_tasques, "3": completar_tasca}
accio = ACCIONS.get(opcio)
if accio is not None:
accio(agenda)Fixa't en el que ha guanyat la segona versió: afegir una opció nova és una línia al diccionari en lloc de dues a la cadena, el conjunt d'opcions vàlides és en un únic lloc i ACCIONS.keys() serveix directament per validar l'entrada de l'usuari. És la mateixa idea de les funcions com a valors de 04-05, aplicada al problema real.
- TascaFàcil v1.0: revisat, formatat i refactoritzat
Primer, les eines, amb les proves en verd abans de començar:
$ pytest -q 8 passed in 0.05s $ black tascafacil/ tests/ reformatted tascafacil/interficie.py reformatted tascafacil/agenda.py All done! 2 files reformatted, 4 files left unchanged. $ ruff check tascafacil/ tascafacil/interficie.py:12:1: F401 [*] `csv` imported but unused tascafacil/interficie.py:48:5: C901 `gestionar_opcio` is too complex (14) tascafacil/magatzem.py:7:1: E501 Line too long (92 > 88) Found 3 errors (1 fixable with `--fix`).
ruff ha assenyalat exactament les dues funcions que sabíem que estaven malament: gestionar_opcio, amb la seva cadena de catorze elif, i mostrar_fitxa, amb el bloc de format. La primera s'arregla amb el diccionari de despatx i la segona extraient capcalera() i barra_progres(), tal com acabes de veure. Després de cada canvi, la comprovació que ho justifica tot:
$ pytest -q 8 passed in 0.05s $ ruff check tascafacil/ All checks passed! $ git commit -am "Refactoritzar interficie.py: despatx per diccionari i extraccio" $ git tag -a v1.0 -m "TascaFacil 1.0: documentat, robust, versionat i provat"
Les vuit proves continuen en verd sense haver-ne tocat ni una, i això és la demostració que la refactorització va ser una refactorització de debò: el comportament és idèntic. El projecte arriba així a la v1.0, el número que segons el versionatge semàntic de 08-01 significa «això ja és estable». Mira d'on ve:
| Versió | Què era TascaFàcil |
|---|---|
| v0.1 (mòd. 2) | Quatre variables i un print amb f-strings |
| v0.4 (mòd. 3) | Un menú en un bucle while amb condicionals |
| v0.8 (mòd. 4) | Funcions, un main() i la lògica separada de la interfície |
| v0.11 (mòd. 5) | Llistes i diccionaris, amb desat en JSON i CSV |
| v0.13 (mòd. 6) | Cerques, ordenacions i consciència del cost |
| v0.17 (mòd. 7) | Classes Tasca i Agenda al paquet tascafacil/ |
| v0.18 | Documentat: docstrings, anotacions de tipus i README.md |
| v0.19 | Robust: try/except, TascaInvalida i logging |
| v0.20 | Versionat: repositori Git amb historial i .gitignore |
| v0.21 | Provat: carpeta tests/ amb vuit proves en verd |
| v1.0 | Formatat amb black, revisat amb ruff i refactoritzat |
Errors Habituals i Consells
- Discutir sobre estil. És temps perdut: instal·la
black, activa'l en desar i dedica aquesta energia al que sí que importa. - Refactoritzar sense proves. És reescriure a cegues. Primer les proves en verd, després el canvi.
- Refactoritzar i canviar el comportament al mateix commit. Si alguna cosa es trenca, no sabràs què ha estat. Un commit, una intenció.
- La refactorització gegant. Canvis petits amb les proves executades entre l'un i l'altre; mai una reescriptura de tres dies.
- Confondre «curt» amb «llegible». Una línia de codi que s'ha de llegir tres vegades no és millor que tres línies clares.
- Fer cas cec al linter. Avisa, no mana. Si tens una raó per deixar alguna cosa com està, deixa-la (i anota el perquè en un comentari).
- Consell: aplica la regla del campament. Deixa cada fitxer que toques una mica millor que com el vas trobar: un nom, una constant, una funció extreta. En uns mesos el projecte sencer està net sense haver-te aturat mai a netejar-lo.
Exercicis
Exercici 1: Estil i noms
Reescriu aquest fragment aplicant PEP 8, les convencions de noms i les constants que calguin:
import json,csv
def PROC(l,f):
r=[]
for x in l:
if x['p']=='alta' and x['d']>20:r.append(x)
return rExercici 2: Detectar olors
Enumera les olors de codi d'aquesta funció, digues quina refactorització correspon a cadascuna i reescriu-la:
def informe(tasques, tipus):
if tipus == "curt":
for t in tasques:
print(f"{t.titol[:30]:<30} {t.responsable:<10}")
elif tipus == "llarg":
for t in tasques:
print(f"{t.titol[:30]:<30} {t.responsable:<10} {t.dies:>3} dies")
elif tipus == "csv":
for t in tasques:
print(f"{t.titol},{t.responsable},{t.dies}")Exercici 3: Clàusula de guarda i despatx
Refactoritza aquesta funció fent servir una clàusula de guarda i un diccionari de despatx, i explica per què el resultat és més fàcil d'ampliar:
def aplicar_accio(tasca, accio):
if tasca is not None:
if not tasca.completada:
if accio == "completar":
tasca.completar()
elif accio == "posposar":
tasca.dies += 1
elif accio == "urgent":
tasca.prioritat = "alta"Solucions
Solució 1.
import csv
import json
DIES_PROJECTE_LLARG = 20
PRIORITAT_URGENT = "alta"
def filtrar_urgents_llargues(tasques: list[dict]) -> list[dict]:
"""Retorna les tasques de prioritat alta que superen els 20 dies."""
return [
tasca
for tasca in tasques
if tasca["prioritat"] == PRIORITAT_URGENT
and tasca["dies"] > DIES_PROJECTE_LLARG
]Els canvis són set: indentació de 4 espais, un import per línia i en ordre alfabètic, nom de funció en snake_case i descriptiu (PROC no diu res i a més semblava una classe), variables amb nom complet, les claus 'p' i 'd' llegibles, els números màgics convertits en constants i l'if d'una línia desplegat. Ah, i el paràmetre f no es feia servir: ruff ho hauria detectat a l'acte.
Solució 2.
Hi ha tres olors: codi duplicat (el bucle es repeteix tres vegades idèntic), una cadena d'if sobre un valor (candidata a diccionari de despatx) i cadenes màgiques ("curt", "llarg", "csv" soltes). La refactorització que correspon és extreure el format d'una línia a funcions i despatxar per diccionari:
FORMATS = {
"curt": lambda t: f"{t.titol[:30]:<30} {t.responsable:<10}",
"llarg": lambda t: f"{t.titol[:30]:<30} {t.responsable:<10} {t.dies:>3} dies",
"csv": lambda t: f"{t.titol},{t.responsable},{t.dies}",
}
def informe(tasques: list[Tasca], tipus: str = "curt") -> None:
"""Imprimeix l informe de tasques en el format indicat."""
formatar = FORMATS.get(tipus)
if formatar is None:
raise ValueError(f"Format no valid: {tipus!r}. Fes servir {list(FORMATS)}.")
for tasca in tasques:
print(formatar(tasca))El bucle apareix una sola vegada i l'única cosa que varia —el format de la línia— viu al diccionari. Afegir un format nou és ara una línia, els formats vàlids són en un únic lloc i el missatge d'error els enumera sol. És exactament la idea de les funcions com a valors de 04-05 posada a treballar.
Solució 3.
def aplicar_accio(tasca: Tasca | None, accio: str) -> None:
"""Aplica una accio a una tasca pendent."""
if tasca is None or tasca.completada: # clausula de guarda
return
ACCIONS[accio](tasca)
ACCIONS = {
"completar": lambda t: t.completar(),
"posposar": lambda t: setattr(t, "dies", t.dies + 1),
"urgent": lambda t: setattr(t, "prioritat", "alta"),
}La clàusula de guarda descarta al principi els casos en què no hi ha res a fer, i el cos real de la funció queda sense imbricació: es llegeix de dalt a baix sense sostenir condicions al cap. I ampliar és trivial: una acció nova és una entrada a ACCIONS, sense tocar la funció. En un projecte real convé anar un pas més enllà i substituir aquestes lambda amb setattr per mètodes de Tasca (posposar(), marcar_urgent()), perquè el comportament d'una tasca pertany a la classe Tasca: és la lliçó de 07-02 aplicada aquí.
Conclusió
El codi es llegeix moltes més vegades de les que s'escriu, i per això l'estil no és cosmètica. PEP 8 fixa el bàsic —4 espais d'indentació, línies de menys de 79 (o 88) caràcters, línies en blanc que separen idees, espais al voltant dels operadors i imports ordenats en estàndard, tercers i propis— i les convencions de noms posen nom oficial al que el curs venia fent des de 02-01: snake_case per a variables i funcions, PascalCase per a classes, MAJUSCULES per a constants i _privat com a acord entre programadors que Python no imposa. El Zen de Python (import this) aporta els criteris per desempatar: explícit millor que implícit, simple millor que complex, la llegibilitat compta, els errors mai no haurien de passar en silenci i hi hauria d'haver una manera òbvia de fer les coses. Gairebé tot això ho apliquen soles les eines: black reformata sense discussió, ruff, flake8 i pylint detecten problemes, mypy comprova les anotacions de 08-01, i VS Code ho executa en desar. L'única cosa que no es pot automatitzar són els noms: verbs per a les funcions, plural per a les col·leccions, esta_/hi_ha_ per als booleans i mai una abreviatura que necessiti un comentari. Les olors de codi —funció massa llarga, massa paràmetres, duplicació, números i cadenes màgics, imbricació profunda, noms críptics i el comentari que explica un tram confús— assenyalen on actuar. I refactoritzar és millorar l'estructura sense canviar el comportament, mai barrejat amb una altra cosa al mateix commit i sempre amb proves en verd abans de començar: extreure funció, extreure variable explicativa, substituir número màgic per constant, invertir la condició amb una clàusula de guarda, unificar duplicats i substituir la cadena d'if per un diccionari de despatx.
TascaFàcil és la v1.0: formatat amb black, revisat amb ruff, amb interficie.py refactoritzada i amb les mateixes vuit proves en verd, que és la prova que res no va canviar per fora. I amb això es tanca el mòdul 8 i, de fet, tot el recorregut tècnic del curs. Vas començar sense saber què era una variable i ara tens el llenguatge (tipus, operadors, entrada i sortida), les estructures de control, les funcions, les estructures de dades amb la seva persistència en fitxers, els algorismes de cerca i ordenació amb el seu cost, la programació orientada a objectes amb mòduls i paquets, i les cinc eines professionals d'aquest mòdul: documentació, depuració i gestió d'errors, control de versions, proves automatitzades i refactorització. Això és exactament l'equipatge amb què treballa un programador.
Només queda una cosa per fer, i és la més important de totes: construir alguna cosa sencera des de zero, tu sol. Fins ara cada peça de TascaFàcil venia proposada; al mòdul 9 el projecte el tries tu, el dissenyes, el planifiques, l'implementes, el proves i el presentes. Comencem a Definició del projecte, decidint què val la pena construir i —tan important com això— on posar el límit per acabar-lo.
Fonaments de la Programació
Mòdul 1: Introducció a la Programació
- Què és la programació?
- Història de la programació
- Llenguatges de programació
- Entorns de desenvolupament
- Del problema a l'algorisme
Mòdul 2: Conceptes Bàsics
- Variables i tipus de dades
- Operadors i expressions
- Entrada i sortida de dades
- Conversió de tipus i validació de dades
Mòdul 3: Estructures de Control
Mòdul 4: Funcions i Procediments
- Definició i ús de funcions
- Paràmetres i retorn de valors
- Àmbit de variables
- Descompondre un programa en funcions
- Funcions com a valors: lambda i ordre superior
Mòdul 5: Estructures de Dades
- Llistes i arrays
- Cadenes de caràcters
- Diccionaris i conjunts
- Tuples i estructures imbricades
- Desar dades en fitxers: text, CSV i JSON
Mòdul 6: Algorismes Bàsics
Mòdul 7: Objectes i Organització del Codi
- De les dades als objectes: classes i instàncies
- Atributs, mètodes i constructor
- Col·leccions d'objectes
- Mòduls, paquets i importacions
Mòdul 8: Bones Pràctiques i Eines
- Documentació i comentaris
- Depuració i gestió d'errors
- Control de versions
- Proves automatitzades
- Estil, llegibilitat i refactorització
