[pugMI] Dubbi su architettura / data mapper / repository ecc... HELP! :)

Simone Magnaschi simone.magnaschi a gmail.com
Gio 16 Lug 2015 02:05:24 PDT


Ciao a tutti,
volevo chiedervi un consiglio su come impostare una determinata sezione di
un progetto su cui stiamo lavorando.
Perdonatemi la lunghezza ma cerco di spiegarmi al meglio per inquadrarvi
bene la situazione.
Il cuore del problema è il Data Mapper Pattern e come gestire al meglio le
classi che entrano in gioco.

Premetto che non ho esperienze di DDD o particolari esperienze con ORM e
similari quindi alcune cose che dirò potrebbero sembrarvi stupide o
completamente senza senso.

Nell'ottica di ristrutturare le classi che gestiscono gli "oggetti" su cui
operiamo, ho iniziato a sviluppare un insieme di classi che si
avvicinassero più o meno al data mapper pattern. Quindi ho le mie entità
che sono POPOs con i loro metodi necessari per la logica delle entità
stesse. Queste classi non hanno nessuna conoscenza del database (anche se
hanno tra le proprietà gli id che a ben vedere con le entità c'entrano poco
o niente).
Ho poi costruito le mie classi repository che vanno a fare avanti e
indietro tra db e entità (idratano gli oggetti e allo stesso tempo fanno la
persistenza mappando le proprietà cn i campi del db).

Non ho usato ORM come Doctrine (che tra l'altro non ho mai usato) o
similari perchè l'applicazione che stiamo usando purtroppo è una legacy
application in cui i dati sono sparsi tra due DB differenti (sql server +
mysql). Ho preferito iniziare a costruire una semplice soluzione in casa
piuttosto che sbattere la testa con una libreria che non sono sicuro che
possa coprire il nostro caso.
L'approccio che ho usato, in sè, ci ha portato dei vantaggi, soprattutto
per quanto riguarda il salvataggio e la persistenza dei dati che ovviamente
ora sono in un unica classe ecc ecc.

I problemi che sto avendo sono di natura architetturale e ora cerco di
entrare nel merito.

Il progetto su cui stiamo lavorando è legato alla gestione di artisti
musicali e dati correlati.

Nel nostro caso abbiamo diversi livelli di dati differenti sparsi su N
tabelle che rappresentano l'artista.

PUNTO 1: DATI CHE DEFINISCONO L'ARTISTA

a. dati di base (id, nome, tipo)
b. dati estesi (nazionalità, data di nascita / morte, biografia,
discografia ecc)
c. aliases (nomi alternativi, nomignoli ecc)
d. relazioni con altri entità di tipo artista (membri della band/ band con
cui l'artista ha suonato ecc)
e. relazioni con altre entità (genitori, fratelli ecc)
f. meta dati vari (profilo deezer, sito ufficiale, fb, tw, g+ ecc)
g. indice di copertura (identifica quanto l'artista è coperto dai nostri
contenuti)


PUNTO 2: ENTITA' ESTERNE CHE IN LINEA TEORICA SONO RELAZIONABILI ALL'ARTISTA

- articoli / news che lo riguardano
- recensioni
- videoclip
- foto
- citazioni
- ...


Nel mio caso specifico l'entità artista può essere definita completamente
con il punto 1. E' possibile costruire un artista istanziando un oggetto di
tipo Artist.

L'oggetto è un grafo in cui ho delle proprietà di base che coprono i punti
a/b e ho delle collezioni di altri oggetti (ognuno definitio a parte) che
gestiscono:
- Alias punto c
- Meta punto f
- Relazioni punto d/e
- Copertura e ranking punto g (..ehm..)

Il tutto mi va bene, ho il typehinting, la logica sta nelle classi e ok.

L'ArtistRepository è un oggetto piuttosto grande che manda avanti e
indietro questi dati (complessivamente) tra tutte le tabelle coinvolte.
Ha classici metodi pubblici da repository:
- findById
- persist (gestisce sia insert che update)
- remove
- ...

Questo è ok ma ora mi si presentano diversi problemi che non so bene come
risolvere. Questi i primi che mi vengono in mente:

1) PROBLEMI DI PERFORMANCE

Se uso questo repository così com'è nell'applicazione ho dei problemi di
performance (lasciando da parte il caching a cui arriverò dopo).
Immaginiamo una scheda degli Oasis, se prendo gli oasis tramite repository
e voglio rappresentare anche tutti i vari componenti, andrò a prendermi le
relazioni, da qui creerò altri oggetti artista completi per poter
semplicemente mostrare a video i loro nomi. Risultato, se per un artista mi
ci vogliono 7-10 query nel DB, qui le moltiplico per tutti i componenti per
nulla.

Allora ho pensato a questa cosa: il repository potrebbe avere dei metodi
-con fluent interface eventualmente- del tipo withBaseData / withMeta ecc
che dicono al repository quali parti dell'oggetto Artista andare a
recuperare.
Quindi il mio $repo->fetchById() potrebbe diventare al caso
$repo->withBaseData()->withRelations->fetchById() per andare a prendere un
artista con i suoi dati di base ma anche le relazioni e nient' altro.
Il problema è che se poi lanciassi un persist mi cancellerebbe tutti i dati
che non ho recuperato xè per il repository quell'artista non ha alias
metadata o altro.
Quindi dovrei tenere traccia all'interno dell'entità artista di quali
"parti" sono state idratate e quali no. In modo che all'atto del persist il
repository può verificare cosa deve toccare e no.

Questo mi genera una serie di perplessità:
- dal punto di vista dell'entità il concetto di cosa è stato idratato o
meno non ha assolutamente senso
- l'aggiunta di metodi come withBaseData o withRelations rende il
repository troppo specifico e difficilmente astraibile in un'interfaccia
repository generica.
- questo mi blocca nel caso volessi usare un decorator per aggiungere un
livello di logging piuttosto che di caching tramite file / redis ecc
- potrei certo costruire un'interfaccia ad hoc ma sto cercando di capire se
può essere ripensato il tutto per salvare capra e cavoli

2) PROBLEMI DI RECUPERO DATI ESTERNI

In questa situazione come è meglio recuperare i dati esterni? Come recupero
ad esempio le foto o le news dell'artista? Devo renderli metodi
dell'ArtistRepository e mapparli come relazioni nell'entità artista
esattamente come faccio per gli altri dati? Così facendo non farei che
peggiorare il punto sopra.
Gli articoli o le foto ad esempio dovrebbero essere entità a sè con il loro
repository ecc. Come faccio a legare i due?

Perdonatemi la lunghezza, e grazie in anticipo :)

Simone
-------------- parte successiva --------------
Un allegato HTML è stato rimosso...
URL: <http://ml.grusp.org/pipermail/milano-grusp.org/attachments/20150716/8335b8cd/attachment.htm>


Maggiori informazioni sulla lista Milano