Caffè… corretto Aggiungi un commento

15 aprile 2010, 11:37

Ok, il gioco di parole nel titolo sta diventando vecchio. Prometto che è l’ultima volta.

Follow-up alla discussione di ieri: ho trovato quest’ottima serie di slide su alcune buone pratiche nello sviluppo di web applications con Struts. Si riferisce a Struts 1.x per la verità, ma alcune cose non sono cambiate così tanto.

Punti salienti:

Remove business logic to a business facade that the actions can call.
Actions are a necessary evil. Every line of code in an Action is guilty until proven innocent.
E soprattutto:
Do not embed business logic in action classes. [Repetita juvant!]
Avoid exposing Domain Models.
Behind your facade, consider using a data access package. [i.e. Hibernate]

In parole povere, sono portato a considerare che la soluzione più corretta sia la numero 1. Corretta fino a prova contraria, naturalmente.

Fonte: Struts Best Practices (Struts University Series)

Caffè Java macchiato Aggiungi un commento

14 aprile 2010, 16:48

Premetto che usare dei pattern “preconfezionati” senza bene capire ciò che sto facendo, non è quello che voglio.

Sto lavorando ad un progetto Java, una web application che mi ha permesso di inoltrarmi nel favoloso mondo del pattern MVC, di Spring, Struts, Hibernate e quant’altro. Oltre a numerosi mal di testa e problemi nel chiedersi “Cos’è meglio? Quale dei 300 approcci diversi alla soluzione di un problema funziona meglio, è più manutenibile, eccetera?”

Prendiamo ad esempio l’implementazione della parte “Model” nel pattern MVC. Dell’accesso al database se ne occupa il layer di persistenza, è vero, con i suoi puliti DAO che non fanno altro che implementare funzionalità CRUD e quanti tipi di find() siano necessari per entità. Ma chi chiama i DAO e da dove? E dove può risiedere la business logic?

Due dei pattern che ho provato ad implementare sono questi:

  1. Action (Struts) -> Model (Spring, w/ business logic) -> DAO (Spring + Hibernate)

    dove le frecce indicano “Chiama”. Questo pattern mi sembra chiaro e lineare, soprattutto molto lineare, in quanto non si mescolano i punti di accesso ai vari layer dell’applicazione. Ma soffre di duplicazione di codice, con nomi di metodi ripetuti lungo i vari strati e solo l’ultimo veramente significativo. Certo, questo potrebbe non essere un problema.

    Poniamo l’esempio di una serie di save(), che ha come scopo ultimo tradurre dei campi in una form nella riga di una tabella. Il save() della action potrebbe passare come parametro il dato preso da una form sulla pagina. Il save() del modello (che a questo punto, potrebbe anche essere chiamato “servizio” visto che non è solo un modello) potrebbe popolare condizionalmente i campi dell’oggetto in questione. Infine, il save() del DAO andrà ad effettuare l’operazione di persistenza sull’oggetto creato.

  2. Action (Struts) -> Service (Spring, w/ business logic) -> Model (Spring)
    |
    +--> DAO (Spring + Hibernate)

    Un po’ meno lineare e più convoluto, anche se non difficile da capire. Il modello, in questo caso, assomiglia pericolosamente ad un DTO che ritengo poco utile in questo caso, essendo destinato a rimanere nello stesso layer e nello stesso contesto dell’intera applicazione. Quando implementato, il Model risiede in sessione.

    Ha il vantaggio di separare molto chiaramente business logic e dati, ma è davvero necessario quando l’uso di un ORM come Hibernate costringe già l’utente a scrivere delle Entity di puri dati? L’archetipo del modello dovrebbe essere una Entity; tutto il resto è duplicazione o aggregazione.

  3. Action (Struts) -> Service + Model (Spring, w/business logic)
    |
    +--> DAO (Spring + Hibernate)

    basato su alcune invarianti:

    • La Action deve rimanere priva di logica di business.
    • Il Model non chiama il DAO.
    • La Action implementa l’interfaccia ModelDriven.

    In questo modo, una Action può o meno richiamare un Model (e contestualmente, implementare ModelDriven per ragioni di validazione e facilità d’accesso) per dati che richiedono qualche tipo di elaborazione. A sua volta, il Model potrà o meno risiedere in sessione per questioni di performance. Si evitano catene di metodi con lo stesso nome ed in ogni caso, è la Action che si preoccupa di richiedere operazioni di persistenza al DAO.

    Il che è un problema in sé: si ottiene l’effetto di doversi ricordare di chiamare il DAO ogni volta. Dover chiamare metodi nella giusta sequenza non è praticamente mai un indice di buona programmazione.

Mi sto documentando per essere meglio illuminato sui pro e i contro di ognuno di questi approcci. Al momento, il primo mi pare il più flessibile e semplice, perchè permette di implementare funzioni comuni senza fatica (ad esempio, misurare il tempo di esecuzione di alcune operazioni su database senza esporre l’interfaccia ovunque o usare classi statiche). Di certo c’è solo che il mondo Java J2EE è vasto e complesso e passerà molto tempo prima che io possa comprenderlo appieno. Se mai succederà!

Persiste! Persistono! Persistenza con JPA Aggiungi un commento

10 agosto 2009, 11:49

Procedendo nella mia conoscenza e nei lavori con Java, specialmente il progetto di gestione delle caselle, mi sono trovato nella necessità di dover usare un database che si interfacciasse con il linguaggio ed Eclipse.

Dapprima, ho usato MySQL, che non ha bisogno di presentazioni. Ma, specialmente nella seconda iterazione del progetto (sarebbe a dire, archiviare quel poco che avevo fatto e ricominciare da capo), mi sono accorto che usare un DB così complesso e mastodontico sarebbe stato, come dicono gli americani, overkill; ed è uno dei più leggeri tra quelli di largo uso!

Così, ho rivolto la mia attenzione verso i database embedded. Ne esistono di vario tipo, forme e dimensioni, tutti accomunati dall’aver bisogno di un solo driver che il motore di persistenza della vostra applicazione (o Eclipse) deve trovare per connettersi ad un database.

Dovrei dire a questo punto che io, fino a due settimane fa al massimo, sapevo poco o niente di queste cose. Soprattutto di quelle parole, “motore di persistenza”: la persistenza, in questo caso, si riferisce alla trasformazione (qualcosa di mistico?) tra un oggetto Java caricato nella JVM (e quindi in memoria) e una riga, o un insieme di righe, in una tabella di un database, nella maggior parte dei casi saldamente ancorato al disco fisso. Sapevo anche cos’è un database, naturalmente, e quel poco di SQL che mi ha permesso di non cominciare da zero con le query al lavoro (ma che ho già molto migliorato. Le SELECT innestate sono un gran divertimento, vero?).

Come motore di persistenza, ho da subito scelto JPA, per l’ottimo tutorial fornito dalla SUN, che raccomando. Il motore di persistenza è quello che si occupa di trasferire certi comandi da oggetti Java (tra cui find(), persist(), merge(), remove()) alle rispettive query SQL (in questo caso SELECT, INSERT, UPDATE, DELETE). Ricordando che in informatica si parla più che altro per astrazioni, non deve stupire sapere che ci sono più implementazioni di uno stesso motore di persistenza. Queste, per supportare un qualche database, devono conoscere il necessario dialetto (o sottoinsieme) del linguaggio SQL, che, ahimé, non è così uno standard come il suo nome potrebbe suggerire. Dopo un tentativo andato a vuoto con EclipseLink, ho scelto Oracle Toplink Essentials, sempre perchè ben documentato nel tutorial.

A questo punto, il primo database a cui ho rivolto la mia attenzione è stato SQLite. Nome accattivante, piccole dimensioni, documentato: sembrava che avessi trovato ciò che faceva al caso mio, ma al primo tentativo di persistere qualche oggetto mi sono trovato davanti ad errori nella sintassi SQL su query generate da JPA e, quindi, presumibilmente giuste. Il problema era un altro: Toplink non implementa il subset SQL necessario a SQLite (che tra l’altro, come ho imparato più tardi, è in qualche modo limitato) e, perciò, sbaglia. In seguito, sono tornato alle buone abitudini che non sbagliano mai: fare ciò che c’è scritto nei tutorial, prima di lanciarsi nell’ignoto; un po’ come le ricette per torte, che finiscono in catastrofe quando non le seguo. Per cui, sono passato ad Apache Derby Embedded: leggero, ugualmente facile da installare e soprattutto, riconosciuto da Toplink.

Il divertimento maggiore è stato (ed è ancora) definire il mapping tra entità nel database e POJOs, semplici oggetti Java. Questo può avvenire in due modi: mediante annotazioni direttamente sul codice, o mediante il file orm.xml, da inserire nella root del progetto. (Per inciso, questo, come il resto di JPA, fa parte della specifica EJB 3.0, con cui avrò a che fare anche per lavoro). Le annotazioni mi sono sembrate più semplici, per cui le ho scelte. Tutto ciò che si deve fare per definire una classe come entità è aggiungere @Entity prima della definizione di classe; per definire nome e altre proprietà, come vincoli di unicità, in una tabella, si usa l’annotazione @Table(...) e così via. Rimando alla lista completa delle annotazioni Toplink per ulteriori approfondimenti.

Dopo qualche perplessità, sono riuscito a sistemare tutte le dipendenze dal mio progetto e a persistere le mie prime tabelle. Tutto il resto è buona progettazione del database, che oltre ad essere dannatamente complicata, è una storia del tutto diversa.

Ricapitolando:

  • Per un’applicazione Java 2 SE che necessiti di salvare POJO‘s (Plain Old Java Objects) su un database, sviluppata sotto Eclipse con motore JPA, ho trovato utili TopLink e il database Derby.
  • Toplink è parte del bundle GlassFish: TopLink Essentials è scaricabile dalla pagina di download dell’implementazione di riferimento, il primo nella tabella chiamata GlassFish v2.1 branch. Eseguire il comando suggerito nella pagina porterà ad avere una directory con alcuni jar. Il file da includere è toplink-essentials.jar .
  • Derby è scaricabile dalla pagina di download del progetto. Il file .zip contiene una serie di jar, il file da includere per un’applicazione desktop che necessiti del solo DB è lib/derby.jar .
  • Ricordare note di copyright e licenze! Anche se entrambe le librerie sono open source, è comunque necessario includere le originali licenze.
  • Nel dubbio, seguire i tutorial. Se non aiutano, seguire una delle leggi fondamentali di Internet: qualcuno ha già avuto il tuo stesso problema. Qualcuno lo ha già risolto.

Buona persistenza a tutti.