PDA

View Full Version : [JAVA] Ora il DAO è considerato anti-pattern?


Matrixbob
06-02-2013, 14:35
Riferendomi a
http://rrees.me/2009/07/11/the-dao-anti-patterns/

solo perchè non segue EJB?

javacomelava
07-02-2013, 15:14
Diciamo che ci sono correnti di pensiero diverse a riguardo e che,leggendo l'articolo che hai postato,mi trovo completamente in disaccordo con l'autore:

Sicuramente un modulo DAO,con la nascita degli applicativi ORM,perde un pochino del suo significato rispetto ai tempi in cui si utilizzava sql puro nei moduli software. Il perchè sta nel fatto che un ORM (come ad esempio Hibernate,TopLink,JPA etc) astrae dalle istruzioni di basso livello relative alle operazioni che si effettuano su db. Se prima si utilizzava un dao inserire un record in una tabella attraverso l'operazione "INSERT into ...."(che può dipendere dallo specifico database) , lo stesso dao ora utilizzerbbe l'astrazione fornita dall'orm utilizzato,qualcosa del tipo: ORMHandler.insert(domain),che già astrare dallo specifico db sottostante.

Il DAO nasceva proprio con l'idea di isolare i moduli software che avevano la responsabilità di accedere in lettura/scrittura al DB,in modo da rendere piu flessibile e manutenibili le applicazioni,seprando la logica di business dalla logica di accesso ai dati (che può essere fortemente accoppiata con la specifico db). Un software ORM deresponsabilizza lo sviluppatore da questa astrazione.

Tuttavia a, mio modo di vedere il pattern DAO rimane comunque un importante pattern di cui tenere conto in fase di design del software (soprattutto se il software sarà di grandi dimensioni e verrà toccato da piu sviluppatori),in quanto,ogni modulo software deve avere una sua responsabilità ben precisa.

1. Utilizzando i Dao si ha una maggiore MODULARITA' dell'applicativo:

1a) Modularità implica Riusabilità: Se nella mia applicazione scrivo un DAO che recupera l'utente dato l'username,potrò riutilizzare lo stesso modulo ovunque mi possa servire all'interno dell'applicazione,senza riscrivere codice.

2a) Modularità implica Manutenibilità: Se nella mia applicazione dovrò cambiare il comportamento del modulo DAO che si occupare di recupere l'utente tramite l'username,a parità di interfaccia,dovrò cambiare esclusivamente il modulo DAO,e non tutte le parti dell'applicativo che lo utilizzano. Immagina di non avere utilizzato i dao e che devi andare a trovare e cambiare in tutta l'applicazione quelle porzioni di codice di cui è cambiato il significato....un inferno....

3a) Manutenibiità e Riusabilità implicano Efficienza. A fronte di un tempo leggermente maggiore in fase di sviluppo dovuto alla creazione dell'infrastruttura dei moduli DAO,ci si guadagna largamente quando sarà il tempo di manutenere o ampliare. E ti assicuro che è prassi comune!

Ciao

Matrixbob
20-02-2013, 14:57
Effettivamente i conti tornano, c'è un po' di più di overload dovuto agli strati di SW, ma rimane tutto + gestibile.

Matrixbob
20-02-2013, 16:02
<snip>

Modularità implica Riusabilità: Se nella mia applicazione scrivo un DAO che recupera l'utente dato l'username,potrò riutilizzare lo stesso modulo ovunque mi possa servire all'interno dell'applicazione,senza riscrivere codice.

Modularità implica Manutenibilità: Se nella mia applicazione dovrò cambiare il comportamento del modulo DAO che si occupare di recupere l'utente tramite l'username,a parità di interfaccia,dovrò cambiare esclusivamente il modulo DAO,e non tutte le parti dell'applicativo che lo utilizzano. Immagina di non avere utilizzato i dao e che devi andare a trovare e cambiare in tutta l'applicazione quelle porzioni di codice di cui è cambiato il significato....un inferno....

Manutenibiità e Riusabilità implicano Efficienza. A fronte di un tempo leggermente maggiore in fase di sviluppo dovuto alla creazione dell'infrastruttura dei moduli DAO,ci si guadagna largamente quando sarà il tempo di manutenere o ampliare. E ti assicuro che è prassi comune!



Ho trovato un esempio che pare cercare di mettere una toppa alla ridondanza di codice scritto per i vari DAO con una specie di unicoAstrattoDao.

Delle interfaccie per le caratteristiche dell'oggetto come

public interface Person extends Serializable {dichiarazione relativi getter/setter}
public interface Recapito extends Serializable {dichiarazione relativi getter/setter}


, delle implementazioni alle interfaccie

public class PersonImpl implements Person {definizione relativi getter/setter}
public class RecapitoImpl implements Recapito {definizione relativi getter/setter}


, DAO astratto in funzione dei Generics

public abstract class AbstractDao<T> {
protected abstract String actualClass();
...
// routine code
}


, specializzazione instanziabile del DAO astratto

public class PersonDao extends AbstractDao<Person> {
@Override
protected String actualClass() {
return PersonImpl.class.getName();
}
}


Domanda:
bisognava per forza usare le interfaccie?

javacomelava
28-02-2013, 11:47
Assolutamente si,le operazioni comuni per l'accesso ai dati vengono generalizzate in una classe astratta,che tutti i dao specifici andaranno ad estendere,proprio come nell'esempio che hai trovato:



public abstract class AbstractDao<T>{

// Qui tutte le operazioni generiche (inser,update,findByPk) //etc.etc.

}

public interface IUserDao
{
// Le operazioni specifiche su un "User" che una specifica //implementazione dovrà rispettare
// Es.: Una query che restituisca tutti gli utenti di una città
}

public class UserDao extends AbstractDao implements IUserDao
{
//Implementazione delle operazioni specifiche su un "User":
// Es.: Una query che restituisca tutti gli utenti di una città
}



Nota bene: Usare le interfacce non è OBBLIGATORIO,ma è indispensibile per poter scrivere applicazioni in modo modulare (con tutte le sue implicazioni).

L'idea è quella che OGNI STRATO APPLICATIVO DEVE COMUNICARE CON LO STRATO APPLICATIVO SOTTOSTANTE ESCLUSIVAMENTE TRAMITE INTERFACCE (Pattern LAYER). Perchè questo? Perchè cosi facendo uno strato applicativo CONOSCE solo la definizione dei servizi esposti dallo strato sottostante disinteressandosi delle reali implementazioni (e quindi disaccoppiandosi da queste).

Matrixbob
28-02-2013, 15:06
Nota bene: Usare le interfacce non è OBBLIGATORIO,ma è indispensibile per poter scrivere applicazioni in modo modulare (con tutte le sue implicazioni).

L'idea è quella che OGNI STRATO APPLICATIVO DEVE COMUNICARE CON LO STRATO APPLICATIVO SOTTOSTANTE ESCLUSIVAMENTE TRAMITE INTERFACCE (Pattern LAYER). Perchè questo? Perchè cosi facendo uno strato applicativo CONOSCE solo la definizione dei servizi esposti dallo strato sottostante disinteressandosi delle reali implementazioni (e quindi disaccoppiandosi da queste).

Grazie,
infatti la mia domanda era specifica dell'esempio trovato (esmpio DAO). Quindi l'esempio avrebbe funzionato anche con il codice fortemente dipendente.
Ovvio che le interaccie servano a disaccoppiare, infatti mi pare che la'mbiente business JEE si basi su interfaccie proprio per questo motivo.
Correct?

javacomelava
04-03-2013, 21:50
Da un punto di vista meramente tecnico,potresi scrivere tutto il codice in una classe,a prescindere.

Ci sono in gioco due concetti diversi:
1. Come progettare un sistema (Design patterns in generale e nel nostro caso il pattern DAO).
2. Che tecncologie utilizzare per implementare il sistema progettato. (J2EE,quindi EJB etc etc)

Nulla vieta,da un punto di vista esclusivamente tecnico,che si possa utilizzare la piattaforma J2EE senza un mimimo di progetazione. Inutile dire che nemmeno un pazzo si sognerbbe di sviluppare un sistema destinato all'"enterprise" (e che quindi deve garantire diversi standard di affidabilità performance etc come può essere una bamca) senza basarsi su regole di progettazione basilari(vedi design patterns).

Matrixbob
06-04-2013, 14:13
Forse è il DTO ad essere un AntiPattern adesso?
Io in verità non ho mai incontrato in 15 mesi di programmazione Java un DTO e non so bene cosa siano, ma dalla definizione Wikipedia sembrano degli strumenti per valorizzare gli oggetti della mia Applicazione.

Sapreste dirmi di + al riguardo?

Matrixbob
06-04-2013, 14:54
Provo a rispondermi da solo riportando uno snip da un thread su StackOverFlow (http://stackoverflow.com/questions/1440952/why-are-data-transfer-objects-an-anti-pattern) che secondo me fila come discorso.


La natura peso della entity bean nelle specifiche EJB prima di EJB 3.0, ha comportato l'utilizzo di modelli di progettazione, come oggetti di trasferimento dati (DTO). DTOS divenne gli oggetti leggeri (che avrebbe dovuto essere il bean di entità stessi in primo luogo), utilizzati per l'invio dei dati attraverso i livelli ... ora specifiche EJB 3.0 rende il modello entity bean come Plain Old Java oggetto (POJO). Con questo modello POJO nuovo, non sarà più necessario creare un DTO per ogni entità o per un insieme di entità ... Se si desidera inviare le entità EJB 3.0 in tutto il livello li rendono solo attuare java.io.Serialiazable



Non credo DTO sono un anti-modello per sé, ma ci sono antipatterns associati con l'uso di DTO. Bill si riferisce a Dudney esplosione DTO come esempio:

http://www.softwaresummit.com/2003/speakers/DudneyJ2EEAntiPatterns.pdf

Ci sono anche una serie di abusi di DTO qui menzionati:

http://anirudhvyas.com/root/2008/04/19/abuses-of-dto-pattern-in-java-world/

Si sono formati a causa di tre sistemi di primo livello (in genere utilizzando la tecnologia EJB) come mezzo per passare i dati tra i vari livelli. La maggior parte dei moderni sistemi di giorno Java basati su framework come Spring avere una visione alternativa semplificata utilizzando POJO come oggetti di dominio (spesso annotato con JPA, ecc ..) in un unico livello ... L'uso di questo DTO è superflua.



DTOS non sono un anti-modello. Quando si sta inviando alcuni dati attraverso il cavo (per esempio, in una pagina web in una chiamata ajax), si vuole essere sicuri di conservare la larghezza di banda solo l'invio di dati che la destinazione verranno utilizzati. Inoltre, spesso è conveniente per il livello di presentazione per avere i dati in un formato leggermente diverso da un oggetto business nativo.

So che questo è un java-oriented domanda, ma in. NET i tipi anonimi, serializzazione, e LINQ permettono DTOS da costruire on-the-fly, che riduce la configurazione e l'overhead di usarle.

javacomelava
08-04-2013, 10:09
Un DTO è una classe java semplicissima,utilizzata per trasportare i dati attraverso i layer applicativi dell'applicazione.

Segue la struttura STANDARD JavaBean,cioe:

1. Costruttore di Default
2. Getters & Setters per ogni proprietà
3. Possibilità di implementare Serializable


public class UserDTO
{
private String nome;

public String getNome()
{
return this.nome;
}

public void setNome(String nome)
{
this.nome = nome;
}
}


Non hanno nulla a che vedere con la specigica EJB in particolare.

Prima degli ejb 3.0 erano un must in quanto gli ejb di tipo Entity (ovvero gli ejb che mappavano il dominio applicativo),dovevano implementare tutta una serie di interfaccie,contenenendo internamente tutta una serie di logiche infrastrutturali e non,che prescindevano dalla natura di contenitore di dati della classe stessa. Quindi non potevano essere usati ANCHE come classi per trasportarsi i dati tra un livello e l'altro dell'applicazione.
Da qui la nascita di questi oggetti semplicissimi,detti DTO,con la funzione specifica di fare da semplici wrapper di dati.

Con il rilascio della specifica EJB 3.0,agli ejb di tipo entity (e in generale a tutti i tipi di ejb) sono stati nettamente semplificati. Ora un ejb di tipo entity non è niente altro che un JavaBean (semplice classe con proprietà,getters e setters) con delle annotazioni particolari,che rendono la classe GESTIBILE dal motore di persistenza scelto (di solito jpa,ma anche hibernate etc). Per specifica,un entity ejb,ha un particolare ciclo di vita (http://sqltech.cl/doc/oas10gR31/web.1013/b28221/undejbs003.htm). Quando una entity si trova in stato DETACHED (cioè,non è piu gestito dal mtore di persistenza) la specifica dice che questo può essere considerato alla stregua di una normalissima classe JavaBean. Teoricamente quindi potrebbero essere utilizzate le Entity per trasportare i dati tra i vari livelli applicativi. Questo è il motivo per cui qualcuno parla ora dei DTO come antipattern.

Per me questa strategia è assolutamente sbagliata,per almeno due motivi principali,che provo a spiegarti:

1. Utilizzare le entity come oggetto di scambio tra i layer applicativi introduce una dipendenza forte tra i layer stessi.

Esempio: L'applicazione è divisa nei tre classici layer: Web - Business(Services) - Persistence(Dao) . Se tra tutti i layer vengono scambiati gli stessi oggetti,significa che tutti i layer applicativi dipendono da queesti ultimi. Questo è male in quanto eventuali modifiche non saranno localizzate in un solo punto,ma spalmate su tutto lo stack architetturale.

2. Le sole entity potrebbero non bastare a modellare i dati dei quali si desidera usufruire

Esempio: Si vogliono mostare nel layer WEB una seire di dati. Questa serie di dati potrebbero essere rappresentati da piu entity in correlazione tra loro,e non da una signola entity. Che succede? Dovrai necessariamente costuirti un oggetto Wrapper (toh...un dto che wrappa entity) che wrappi tutte le entità proprietarie di quei dati. Questa non è una cosa bella,in quanto trascinarsi oggetti compositi tra i layer,che contegnono anche dati che in realtà non ti servono per quella data funzionalità,introduce un overhead non sempre trascurabile (gli oggetti java sono pesanti...). Immagina se poi stai progettando un sistema dove i dati devono viaggiare in remoto(business esposto tramite webservices,oggi è prassi). Brutta soluzione davvero.

L'idea di base è quella di costruirsi DTO appositi che vanno a rappresentare solo le informazioni che una data funzionalità si presuppone di recuperare.

Hai bisogno dei dati A,B,C che a livello di dominio (e quindi di entity) sono rappresentate dalle entiy 1,2,3 ? Perchè trascinarsi tutto dietro? Si crea un DTO WrapperDTO con le sole proprietà A,B,C. Il business avrà la responsabilità di recuparare le enitity (tramite i dao) lavorarle e infine copiare SOLO I DATI CHE SERVONO nel DTO,che infine verrà restituio al layer piu alto.

Di solito il business restituisce DTO e utilizza i DAO per recuperare i dati. I DAO lavorano solo con le entity.

Matrixbob
10-04-2013, 07:58
Scusami, abbi pazienza sono un po' testone.

Vorrei provare a capire 2 cose.

1]
Supponiamo di avere un DAO che implementi questa interfaccia.

public interface IMovieDAO {
public Movie getMovie(String id);
public void getStars(String title);
public List<Movie> getMovies(String sql);
public List<Movie> getAllMovies();
public void insertMovie(Movie m);
public void updateMovie(Movie m);
public void deleteMovie(String id);
public void deleteAllMovies();
}


, riferita ad un JavaBean

public class Movie {
private Long id;
private String title;
private Date releaseDate;

/* costruttori */
public Movie() {
super();
}

public Movie(String title) {
this();
this.title = title;
}

/* getter e setter */
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public Date getReleaseDate() {
return releaseDate;
}

public void setReleaseDate(Date releaseDate) {
this.releaseDate = releaseDate;
}

@Override
public String toString() {
return "Movie [id=" + id + ", title=" + title + ", releaseDate=" + releaseDate + "]";
}
}


Un relativo DTO quale potrebbe essere se già il DAO restituisce una lista di Movie?

2]
Tu che differenza fai tra le seguenti locuzioni:
VO - POJO - JavaBean?
Per me sono tutte la stesa cosa, secondo i 3 principi fondamentali di Java:
Incapsulamente
...
...

javacomelava
10-04-2013, 14:29
Parto dal presupposto che l'oggetto Movie sia una Entity (un ejb di tipo entity per la precisione).

Se il dao è utilizzato da un servizio che ha la responsabilità di resituire un "Movie" allora il DTO restiituito dal servizio sarà un oggetto MovieDTO identico all'entity Movie,che possiede solo i dati che tu vuoi far restituire dal servizio.

Esempio:

Nel business esponi un servizio:


public MovieDTO loadMovieById(int movieId);


Mettiamo il caso che il client di questo servizio (un modulo web) non abbia bisogno del dato Date releaseDate presente nell'entity. Il tuo DTO,wrappera solo i dati che ti servono,escludendo quindi releaseDate. Immagina che la tua entity Movie abbia relazioni 1-n con altre entity (e che queste entity abbiano a loro volta altre relazioni con altre entity). Non vorrai mica tirare su tutto il database per recuperare un Movie????

Mettiamo caso che tu debba sviluppare un servizio che restituisca tutti i titoli dei Movie e il relativo nome del regista. Hai due entity ( magari in relazione tra loro): Movie e Director. Quale entity tiri su?
Movie? non basta
Director? non basta
Necessiti per forza di un oggetto composito che come minimo wrappi entrambe le entity. Anche creando questo oggetto composito,tireresti su un mondo di dati che al servizio non servono! Inoltre andresti a sviluppare logiche ingarbugliatissime per wrappare!

L'idea è quella di farsi un oggetto proprio,contenente solo i dati necessari. In questo caso ad esempio potrebbe essere:


MovieInfoDTO
{
private String movieName;
private String directorName;
}


e la firma del servizio:


public MovieInfoDTO loadMovieWithDirectorInfoById(int id)
{
// recupera il movie tramie il relativo Dao
....
// recupera il Director del Movie tramite il relativo Dao (o direttamente tramite la relazione con il movie)
....

// Copia le info necessarie dalle entity Movie e Director nel DTO da restituire

}


Questa strategia ti offre tre super vantaggi:
1. PERFORMANCE: I servizi caricheranno SOLO ed ESCLUSIVAMENTE i DATI che il client si aspetta
2. DISACCOPPIAMENTO: I layer ad alto livello non dipenderanno dai layer di basso livello (dao e relative entity)
3. Estrema facilità nelle logiche di wrapping: Devi solo copiare i dati che desideri dalle entity ai dto,senza inventarti chissa quali strutture dati per cercare di caricare dati compositi (presi da piu entity)


VO (Value Object) sono oggetti particolari (un pò wrapper e pò di business) relativi ad un altro stile architetturale,piu orientato al dominio,denominato DDD (Domanin Driven Design).Seguono standard di sviluppo precisi. Evitali,anche perchè non avrebbero senso in un contesto architetturale non orientato al dominio. Io,personalmente,odio il ddd con tutto me stesso. L'esperienza mi ha insegnato a tenermi lontano da questo obbrobrio.

POJO: Plain Old Java Object. Per definizione sono oggetti java semplicissimi,senza uno STANDARD STRETTO DA SEGUIRE per lo sviluppo.Non estendono ne implementano interfacce/classi particolari ne posseggono annotazioni. Sono quindi oggetti "CROSS APPLICATION,CROSS FRAMEWORK",teoricamente compatibili e portabili su ogni sistema.

JavaBean: (e qui ricadono i nostri DTO). Praticamente sono dei POJO la cui struttura è RIGOROSAMENTE DEFINITA: Posseggono proprietà e relativi Getters & Setters ,con costruttore di default. Se una di questa condizioni viene a mancare allora jnon si può parlare di JavaBean.

P.S.:
Mi rendo conto comunque che la maggior parte delle cose che sto esponendo possano sembrare solo "pippe filosodofiche" di non facile e immediata comprensione. Inizialmente il mio consiglio è di seguire questi principi anche senza vederne direttamente l'utilità. Appena di addentrerai nello sviluppo di sistemi leggermente piu complessi esclamerai: "Grazie a DIO,mi sono fatte le pippe filosofiche". D'altra parte,se esistono ci sarà un perchè.