<html>
  <head>
    <meta content="text/html; charset=windows-1252"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">Simone Magnaschi wrote:<br>
    </div>
    <blockquote
cite="mid:CAOZ-zm_nQLBvBEJ3ohkiPH3yp_ErmcViCyYS+zYm6EmiMEE5=g@mail.gmail.com"
      type="cite">
      <div dir="ltr">
        <div>Ciao a tutti,</div>
        <div>volevo chiedervi un consiglio su come impostare una
          determinata sezione di un progetto su cui stiamo lavorando.</div>
        <div>Perdonatemi la lunghezza ma cerco di spiegarmi al meglio
          per inquadrarvi bene la situazione.</div>
        <div>Il cuore del problema è il Data Mapper Pattern e come
          gestire al meglio le classi che entrano in gioco.</div>
        <div><br>
        </div>
        <div>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.</div>
        <div><br>
        </div>
        <div>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).</div>
        <div>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).</div>
        <div><br>
        </div>
        <div>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.</div>
        <div>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.</div>
        <div><br>
        </div>
        <div>I problemi che sto avendo sono di natura architetturale e
          ora cerco di entrare nel merito.</div>
        <div><br>
        </div>
        <div>Il progetto su cui stiamo lavorando è legato alla gestione
          di artisti musicali e dati correlati.</div>
        <div><br>
        </div>
        <div>Nel nostro caso abbiamo diversi livelli di dati differenti
          sparsi su N tabelle che rappresentano l'artista. </div>
        <div><br>
        </div>
        <div>PUNTO 1: DATI CHE DEFINISCONO L'ARTISTA</div>
        <div><br>
        </div>
        <div><span class="" style="white-space:pre">    </span>a. dati di
          base (id, nome, tipo)</div>
        <div><span class="" style="white-space:pre">    </span>b. dati
          estesi (nazionalità, data di nascita / morte, biografia,
          discografia ecc)</div>
        <div><span class="" style="white-space:pre">    </span>c. aliases
          (nomi alternativi, nomignoli ecc)</div>
        <div><span class="" style="white-space:pre">    </span>d. relazioni
          con altri entità di tipo artista (membri della band/ band con
          cui l'artista ha suonato ecc)</div>
        <div><span class="" style="white-space:pre">    </span>e. relazioni
          con altre entità (genitori, fratelli ecc)</div>
        <div><span class="" style="white-space:pre">    </span>f. meta dati
          vari (profilo deezer, sito ufficiale, fb, tw, g+ ecc)</div>
        <div><span class="" style="white-space:pre">    </span>g. indice di
          copertura (identifica quanto l'artista è coperto dai nostri
          contenuti)</div>
        <div><br>
        </div>
        <div><br>
        </div>
        <div>PUNTO 2: ENTITA' ESTERNE CHE IN LINEA TEORICA SONO
          RELAZIONABILI ALL'ARTISTA</div>
        <div><br>
        </div>
        <div><span class="" style="white-space:pre">    </span>- articoli /
          news che lo riguardano</div>
        <div><span class="" style="white-space:pre">    </span>- recensioni</div>
        <div><span class="" style="white-space:pre">    </span>- videoclip</div>
        <div><span class="" style="white-space:pre">    </span>- foto</div>
        <div><span class="" style="white-space:pre">    </span>- citazioni</div>
        <div><span class="" style="white-space:pre">    </span>- ...</div>
        <div><br>
        </div>
        <div><br>
        </div>
        <div>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. </div>
        <div><br>
        </div>
        <div>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:</div>
        <div><span class="" style="white-space:pre">    </span>- Alias
          punto c</div>
        <div><span class="" style="white-space:pre">    </span>- Meta punto
          f</div>
        <div><span class="" style="white-space:pre">    </span>- Relazioni
          punto d/e</div>
        <div><span class="" style="white-space:pre">    </span>- Copertura
          e ranking punto g (..ehm..)</div>
        <div><br>
        </div>
        <div>Il tutto mi va bene, ho il typehinting, la logica sta nelle
          classi e ok.</div>
        <div><br>
        </div>
        <div>L'ArtistRepository è un oggetto piuttosto grande che manda
          avanti e indietro questi dati (complessivamente) tra tutte le
          tabelle coinvolte. </div>
        <div>Ha classici metodi pubblici da repository:</div>
        <div><span class="" style="white-space:pre">    </span>- findById</div>
        <div><span class="" style="white-space:pre">    </span>- persist
          (gestisce sia insert che update)</div>
        <div><span class="" style="white-space:pre">    </span>- remove</div>
        <div><span class="" style="white-space:pre">    </span>- ...</div>
        <div><br>
        </div>
        <div>Questo è ok ma ora mi si presentano diversi problemi che
          non so bene come risolvere. Questi i primi che mi vengono in
          mente:</div>
        <div><br>
        </div>
        <div>1) PROBLEMI DI PERFORMANCE</div>
        <div><br>
        </div>
        <div>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.</div>
        <div><br>
        </div>
        <div>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.</div>
        <div>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.</div>
        <div>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.</div>
        <div>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.</div>
        <div><br>
        </div>
        <div>Questo mi genera una serie di perplessità:</div>
        <div><span class="" style="white-space:pre">    </span>- dal punto
          di vista dell'entità il concetto di cosa è stato idratato o
          meno non ha assolutamente senso</div>
        <div><span class="" style="white-space:pre">    </span>- l'aggiunta
          di metodi come withBaseData o withRelations rende il
          repository troppo specifico e difficilmente astraibile in
          un'interfaccia repository generica. </div>
        <div><span class="" style="white-space:pre">            </span>- questo mi
          blocca nel caso volessi usare un decorator per aggiungere un
          livello di logging piuttosto che di caching tramite file /
          redis ecc</div>
        <div><span class="" style="white-space:pre">            </span>- potrei
          certo costruire un'interfaccia ad hoc ma sto cercando di
          capire se può essere ripensato il tutto per salvare capra e
          cavoli</div>
        <div><br>
        </div>
      </div>
    </blockquote>
    <br>
    Non ho una risposta precisa ma ti posso raccontare cosa e' stato
    fatto per eZPublish:<br>
    <br>
    v3/4:<br>
    - tutti gli oggetti 'entity' sono dotati di proprerties con lazy
    loading. $artist->albums va a effettuare la query nel momento in
    cui si vi si accede<br>
    - non ci sono repositories, pattern usata: activerecord<br>
    - ogni volta che si modifica una property di una entity, questa si
    salva il suo stato dirty, che poi usa per la serializzazione<br>
    - ogni entity va salvata singolarmente<br>
    pros:<br>
    - veloce e poca ram sprecata se si vuole caricare il dataset minimo
    di una entity<br>
    - facile scrivere codice conciso, ma se si vuole l'autocompletion
    delle ide occcorre scrivere una gran massa di phpdoc<br>
    cons:<br>
    - poco uso di joins<br>
    - pattern activerecord => brutta tendenza ad avere god classes<br>
    - lazy loading => difficile avere il controllo sulle
    performances. Ci sono sviluppatori che p.e. accederanno ad un dato
    tramite query del tipo
    $artist->albums[0]->collaborators['singer']->albums[0]->picture,
    ovviamente in un loop...<br>
    <br>
    v5:<br>
    - introdotti i repository services: 1 repo (magari vari repo nel tuo
    caso, visto che hai vari db) con grossomodo 1 service per ogni
    entity<br>
    - no more lazy loading: tutto viene caricato esplicitamente a mano
    (in php): $artistService->fetchRelationsById($artistId)<br>
    - ogni service e' quindi specifico, e ha in se la logica per
    persistere la entity in modo 'sparpagliato'<br>
    - 'sotto' i repository services esistono gli storage services, che
    interagiscono coi vari db/nosql/filesystem<br>
    - nelle chiamat REST, per evitare la chattines del protocollo,
    quando si carica una entity si puo' chiedere quale parte del dataset
    si vuole avere indietro, come proponi tu: pochi dati per
    compattezza, oppure tutti in una volta sola<br>
    pros:<br>
    - introdurre caching e logging e' stato fatto a livello  degli
    storage services => facile!<br>
    cons:<br>
    - codice verboso => si scrive bene solo con una ide<br>
    - architettura a lasagna con molti strati => impossibile
    debuggare senza una ide<br>
    - architettura a lasagna con molti strati => non e' facile
    ottenere delle query ottimizzate<br>
    <br>
    I dati esterni sono trattati secondo lo stesso schema.<br>
    <br>
    Disclaimer: in eZP, il modello dati e' EAV, ovvero le classi entity
    non sono tipizzate.Esistono poche classi: 'contenuto', 'location',
    'sezione' etc... non 'artista', 'pagina', 'album', 'track', 'casa
    discografica'.<br>
    Questo fa si che i repository services non siano decine e decine.<br>
    <br>
    Ciao<br>
    Gaetano<br>
    <br>
    <blockquote
cite="mid:CAOZ-zm_nQLBvBEJ3ohkiPH3yp_ErmcViCyYS+zYm6EmiMEE5=g@mail.gmail.com"
      type="cite">
      <div dir="ltr">
        <div>2) PROBLEMI DI RECUPERO DATI ESTERNI</div>
        <div><br>
        </div>
        <div>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.</div>
        <div>Gli articoli o le foto ad esempio dovrebbero essere entità
          a sè con il loro repository ecc. Come faccio a legare i due?</div>
        <div><br>
        </div>
        <div>Perdonatemi la lunghezza, e grazie in anticipo :)</div>
        <div><br>
        </div>
        <div>Simone</div>
        <div><br>
        </div>
      </div>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <br>
      <pre wrap="">_______________________________________________
Milano mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Milano@ml.grusp.org">Milano@ml.grusp.org</a>
<a class="moz-txt-link-freetext" href="http://ml.grusp.org/listinfo.cgi/milano-grusp.org">http://ml.grusp.org/listinfo.cgi/milano-grusp.org</a>
</pre>
    </blockquote>
    <br>
  </body>
</html>