Commit 8f2429a7 authored by jg5dev's avatar jg5dev 💬
Browse files

better

parent 5bb66951
Loading
Loading
Loading
Loading
+35 −8
Original line number Diff line number Diff line
@@ -252,7 +252,7 @@ Sigui com sigui que en diguem, la tria no és una qüestió de gust ni de quanti
canvia és on va a parar el cost.

Amb un framework opinionat, moltes decisions ja estan preses: on van els fitxers, com es valida, com
s'autentica, com es fan les migracions. Les convencions són compartides més enllà de l'equip, de
s'autentica, com es fan les [migracions](#migracions-de-lesquema) de l'esquema de la base de dades. Les convencions són compartides més enllà de l'equip, de
manera que qui arriba nou a un projecte Django o Laravel ja sap on mirar. Funcionen, de fet, com les
[decisions explícites](./arquitectura.md#decisions-explícites-els-adr) de què parlàvem: algú va
decidir per tu i no cal tornar-ho a discutir. A canvi, hi ha molt a aprendre abans de ser productiu,
@@ -355,6 +355,35 @@ explícites i els canvis passen per changesets. Renunciant a l'abstracció, la p
secció deixa de tenir sentit, i de passada el problema N+1 costa molt més de provocar sense
adonar-se'n. És la direcció que assenyala també Drizzle a Node: menys màgia i més a prop del SQL.

## Migracions de l'esquema

L'ORM no només decideix com llegeixes les dades: també decideix com canvia la taula on són. Una
**migració** és un canvi de l'esquema de la base de dades guardat com un fitxer al projecte, amb
un ordre i un identificador, de manera que qualsevol còpia es pot posar al dia aplicant les que li
falten. Per què calen i com afecten el desplegament és a
[Evolució de l'esquema](../persistencia/persistencia.md#evolució-de-lesquema); aquí ens interessa qui
les escriu, perquè això sí que ho decideix el framework.

La paraula tapa tres maneres de fer molt diferents, i la tria decideix **on és la font de veritat de
l'esquema**:

- **Generades a partir dels models** (Django, Doctrine, Entity Framework Core, i opcionalment
  Alembic). L'eina compara les classes amb l'historial de migracions i escriu el fitxer. La font de
  veritat és el codi. És molt còmode, però convé llegir el que genera abans d'aplicar-ho: un canvi de
  nom de camp el veu sovint com esborrar una columna i crear-ne una altra, i això és perdre dades.
- **Escrites a mà amb l'API del framework** (Rails, Laravel, Ecto). El framework posa el versionat i
  el generador del fitxer buit, i el contingut el decideixes tu, escrit en el teu llenguatge. Res no
  endevina res, a canvi d'escriure més.
- **Escrites en SQL** (Flyway, Liquibase, `golang-migrate`). La font de veritat és el SQL, i el codi
  no hi té cap paper. És l'opció habitual quan la base de dades és
  [d'integració](../persistencia/persistencia.md#base-de-dades-daplicació-o-dintegració) i la
  comparteixen diverses aplicacions, o quan qui mana l'esquema no és l'equip de desenvolupament.

És una decisió que va lligada al patró de mapatge de la secció anterior: amb Active Record l'esquema
surt dels models gairebé sempre, i amb un framework prim la tria torna a ser teva. El que no convé
és barrejar-ne dues, per exemple generar-ne i després editar l'esquema per fora, que és la manera
segura d'acabar amb un entorn que ningú no sap reproduir.

## Testabilitat

A [Arquitectura](./arquitectura.md#llegir-els-senyals-de-les-proves) dèiem que la dificultat
@@ -596,11 +625,11 @@ que és una decisió de desplegament abans que de codi.

| Framework | ORM habitual | Patró de mapatge | Migracions | Vista per defecte |
| --- | --- | --- | --- | --- |
| Django | Django ORM | Active Record | Integrades, generades | Django Templates |
| Django | Django ORM | Active Record | Integrades | Django Templates |
| Rails | Active Record | Active Record | Integrades | ERB, amb Hotwire |
| Spring | JPA amb Hibernate | Data Mapper | Flyway o Liquibase | Thymeleaf |
| Laravel | Eloquent | Active Record | Integrades | Blade |
| Symfony | Doctrine | Data Mapper | Bundle de Doctrine | Twig |
| Symfony | Doctrine | Data Mapper | Doctrine Migrations | Twig |
| ASP.NET Core | Entity Framework Core | Data Mapper | EF Core Migrations | Razor o Blazor |
| Express | A triar | El de l'ORM triat | Les de l'ORM triat | Cap, motors opcionals |
| FastAPI | A triar, sovint SQLAlchemy | Data Mapper | Alembic | Cap, JSON |
@@ -611,12 +640,10 @@ que és una decisió de desplegament abans que de codi.

Als microframeworks el patró de mapatge no el marca el framework sinó l'ORM que triïs, i n'hi ha que
et deixen triar a tu. La columna de la vista, per la seva banda, deixa veure a simple cop d'ull quins
frameworks esperen servir HTML i quins esperen servir dades. I la de migracions amaga una decisió
que es paga cara si es descobreix tard: allà on són generades a partir dels models (Django, Doctrine,
Entity Framework Core) la font de veritat de l'esquema és el codi, mentre que amb Flyway o
`golang-migrate` la font de veritat és el SQL que escrius tu. I a Rails el nom de l'ORM és literalment
frameworks esperen servir HTML i quins esperen servir dades. I a Rails el nom de l'ORM és literalment
Active Record, cosa que explica per què el patró es coneix tant: Rails el va convertir en la manera
per defecte de fer aplicacions web durant una dècada.
per defecte de fer aplicacions web durant una dècada. La columna de migracions es llegeix amb les
tres famílies de [Migracions de l'esquema](#migracions-de-lesquema).

### Seguretat

+10 −0
Original line number Diff line number Diff line
@@ -101,6 +101,16 @@ Una base de dades **d'aplicació** es controla i accedeix des d'una sola aplicac

La recomanació general és la d'evitar bases de dades d'integració. En general, les bases de dades d’integració comporten problemes greus perquè la base de dades esdevé un punt d’acoblament entre les aplicacions que hi accedeixen. Generalment es tracta d'un acoblament profund que augmenta significativament el risc que suposa canviar aquestes aplicacions i dificulta la seva evolució.

## Evolució de l'esquema

Decidit qui és l'amo de la base de dades, queda saber com la canvia. L'esquema no és fix: al llarg de la vida de l'aplicació hi apareixen taules noves, columnes que canvien de tipus i índexs que s'afegeixen. Una **migració** és un d'aquests canvis guardat com un fitxer al projecte, amb un ordre i un identificador, de manera que qualsevol còpia de la base de dades es pot posar al dia aplicant les que li falten.

En desenvolupament sembla una complicació innecessària, perquè sempre pots esborrar la base de dades i tornar-la a crear. **En producció no pots**: allà hi ha dades reals que no es poden perdre, i l'esquema ha de canviar amb elles a dins. Les migracions són el que fa possible que el mateix canvi arribi igual a la màquina de cada persona de l'equip, a l'entorn de proves i a producció, que es pugui revisar abans d'aplicar-lo i que es pugui repetir sense sorpreses. Sense això, l'esquema de producció acaba sent el resultat d'una successió de canvis manuals que ningú no recorda i que no es poden reproduir enlloc.

Això té una conseqüència que sorprèn el primer cop: **el codi nou i l'esquema nou no arriben alhora**. Mentre dura el desplegament conviuen la versió antiga i la nova de l'aplicació, i totes dues han de poder treballar amb la base de dades. Per això els canvis es fan en dos passos, primer afegint i després retirant: s'afegeix la columna nova, es desplega el codi que la fa servir i, en un desplegament posterior, s'esborra la vella. Canviar les coses de lloc de cop trenca l'aplicació que encara s'està aturant.

Dues coses no canvien mai: les migracions són codi, i per tant van al repositori i es revisen com la resta, i s'apliquen al desplegament, no a mà. Qui les escriu, en canvi, depèn de l'eina, i sovint la decideix el framework: ho veiem a [Migracions de l'esquema](../fonaments/frameworks.md#migracions-de-lesquema).

## Model relacional vs NoSQL

Les bases de dades actuals responen majoritàriament al **model relacional**, que ha triomfat gràcies a l'establiment de l'**SQL** com a estàndard. En paral·lel han guanyat pes les bases de dades **NoSQL** (key-value, document, column-family i graf), afavorides pel Big Data i les aplicacions en temps real. Sovint són sistemes [sense esquema](https://martinfowler.com/articles/schemaless/), i poden conviure amb solucions relacionals en models de [persistència poliglota](https://en.wikipedia.org/wiki/Polyglot_persistence).