|
..Chi controlla il presente controlla il passato. George Orwell
|
|
| Home Page |
|
| Articoli |
|
| News |
|
| Forum |
|
| Classi |
|
|
|
|
|
Convention over configuration
By
Alessandro Rocca e Stefano Rossini
26 febbraio 2009
|
 |
|
In questo articolo parleremo di “Convention Over Configuration” (CoC) e di "Don't Repeat Yourself" (DRY), due paradigmi di Design alla base di importanti attuali framework come Grails, Seam, EJB3, Rails e Junit.
 << Figura 1: Rails, Grails, Maven & Junit>>
|
|
|
Convention Over Configuration (CoC) e Don’t Repeat Yourself (DRY)
|
top
|
Convention over Configuration è un concetto abbastanza semplice: sistemi, librerie e framework dovrebbero assumere dei valori di default ragionevoli per funzionare senza obbligo di inserire o maneggiare configurazioni.
Questo tipo di approccio semplifica notevolmente la programmazione, soprattutto agli stadi iniziali dello studio di un nuovo framework, senza necessariamente perdere in flessibilità; lo sviluppatore ha bisogno di configurare soltanto ciò che differisce dalle convenzioni.
Don't Repeat Yourself è un Design pattern della programmazione secondo il quale bisogna evitare il più possibile la duplicazione del codice, poiché questa complica la mantenibilità e la leggibilità del codice stesso.
Un codice DRY riduce al minimo le informazioni ridondati e le duplicazioni, risultando quindi essere più “pulito”, leggibile e mantenibile.
Il Convention over Configuration sostiene la filosofia del Don’t Repeat Yourself.
Vediamo ora alcuni esempi di software che utilizzano i due pattern appena introdotti.
|
|
JUnit
|
top
|
|
JUnit , il noto framework di test open source creato da Erich Gamma e Kent Beck, utilizza convenzioni per semplificare la scrittura di test d’unità. Ogni metodo di test deve iniziare con il prefisso “test”. Il framework JUnit utilizza la reflection per individuare questi metodi ed invocarli. Sempre per convenzione, prima e dopo l’esecuzione di ogni metodo di test, vengono eseguiti rispettivamente i metodi setUp() e tearDown().
Ad esempio, la semplice classe di test MySampleTest dichiara due metodi di test: testGoodEmail e testBadEmail.
public class MySampleTest extends TestCase {
public void setUp(){ }
public void tearDown(){ }
public void testGoodEmail(){ . . . . }
public void testBadEmail(){ . . . } } Eseguendo la classe di test il framework JUnit invoca automaticamente i metodi setUp(), testGoodEmail(), tearDown(), setUP(), testBadEmail() e tearDown().  << Figura 2: Esempio di JUnit >>
|
|
Maven
|
top
|
Maven è un altro esempio di utilizzo di Convention Over Configuration. Come convenzione, nelle sue impostazioni di default, Maven organizza i file sorgenti in una directory src, i file compilati nella directory target/classes, e così via. Per ogni progetto la struttura convenzionale che si genera è questa:

<< Figura 3: Convenzione di Maven >>
Rispetto quindi ad ANT la struttura dei progetti non è da configurare e di conseguenza anche i comandi hanno una sintassi standard; ad esempio per compilare basta eseguire il comando “mvn compile”, per eseguire i test “mvn test” e così via.
|
|
EJB3
|
top
|
EJB3, è stato introdotto il CoC per semplificare la gestione della persistenza. Il framework assume che il nome delle tabelle e delle colonne in esse contenute vengano associati rispettivamente ai nomi delle classi e delle proprietà. Esiste anche il modo, in caso di necessità, di scavalcare queste impostazioni di default, ma, nella maggior parte dei casi, il comportamento di default permette un più rapido sviluppo del progetto.
Ad esempio il seguente Entity Bean:
@Entity public class Book{
@Id @GeneratedValue private Long id; private String title;
public Book() { }
public Book(String title) { this.title = title; } }
viene, di default, associato alla tabella Book contenente i due campi:
1. Id: mappato in un tipo Long e primary key (specificata dall’annotation @Id). 2. Title: mappato in un String.
Questa convenzione ha un’ulteriore implicazione molto comoda nel caso di integrazione del frame work ORM Hibernate a supporto della persistenza, ovvero si eliminano i file di xml di mapping snellendo la fase di sviluppo e di manutenzione.
Anche la Dependency Injection introdotta nelle specifiche EJB3 è conforme al CoC. Volendo creare un’oggetto, DAO, che metta a disposizione le classiche operazioni CRUD sulla tabella Book, si può pensare di implementare uno Stateless Bean locale avente tale ruolo. Per raggiungere questo scopo è sufficiente definire un’interfaccia locale (@Local) che dichiari i metodi CRUD import javax.ejb.Local;
@Local public interface BookCRUD { Book createOrUpdate(Book book); void remove(Book book); Book find(Object id); } e implementare tale interfaccia attraverso uno Stateless Bean (@Stateless)
@Stateless public class BookDAO implements BookCRUD { @PersistenceContext private EntityManager em;
public Book createOrUpdate(Book book) { return em.merge(book); } public void remove(Book book) { em.remove(em.merge(book)); } public Book find(Object id) { return em.find(com.abien.Book.class, id); } }
in cui iniettare un contesto di persistenza (@PersistenceContext). Tale contesto di persistenza viene associato, di default, al data source configurato nel file persistence.xml secondo le specifiche di persistenza degli EJB3:
<?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="sample" transaction-type="JTA"> <jta-data-source>jdbc/sample</jta-data-source> </persistence-unit> </persistence>
Non dichiarando altri persistence-unit, nello Stateless Bean viene iniettata la configurazione di default, sollevando dall’onere di doverla configurare all’interno dell’EJB stesso.
|
|
Spring MVC
|
top
|
Spring MVC, utilizza il pattern Convention over Configuration per il mapping degli URL.
La classe ControllerClassNameHandlerMapping è un HandlerMapping che adotta una convenzione per determinare la corrispondenza tra l’URL richiesta e il controller incaricato di gestire tale richiesta. In quest’ottica ogni Controller è incaricato di gestire una richiesta per una determinata pagina.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<!-- maps request URLs to Controller names --> <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
<!-- this bean with the well known name generates view names for us --> <bean class="x.y. AccountsController "> <!-- inject dependencies as necessary --> </bean>
</beans>
Seguendo il file di configurazione precedente, una richiesta all’URL “mywebsite.com/accounts” viene passata automaticamente al controller AccountsController, cioè la classe avente per convenzione il nome corrispondente all’azione (accounts) con postfisso Controller.
|
|
JBoss Seam
|
top
|
JBoss Seam: application framework basato su modello a componenti, oltre a integrare tecnologie come Asynchronous JavaScript e XML (AJAX), Java Server Faces (JSF), Enterprise Java Beans (EJB3), JPA, Java Portlets e Business Process Management (JBPM), sottolinea l’adozione di CoC attraverso l’ausilio delle annotation introdotte nella specifica Java 5.
In Seam, esiste il file components.xml dove vengono specificati i componenti, standard e custom, da utilizzare all’interno di un’applicazione. Nel caso di componenti custom è necessaria una classe package-info.java, all’interno del package di riferimento, a supporto della configurazione per definire il name space del componente stesso.
package com.mycompany.mycomponents
@Name("myComponent") public class MyComponent {
... ...
}
e relativo name space dichiarato all’interno della classe package-info.java @Namespace(value="http://mycompany.com/mycomponents ") package com.mycompany.mycomponents;
per poi referenziarlo all’interno del file components.xml nel seguente modo
<components xmlns="http://jboss.com/products/seam/components" xmlns:custom="http://mycompany.com/mycomponents " ... ... <custom:myComponent... />
Adottando CoC, è possibile omettere la definizione del name space e quindi della classe package-info.java, riferendo il nostro componente direttamente con il nome utilizzato nell’annotation @Name
<component name="myComponent"> <property name="someDecimalValue" value="22.2" /> <property name="componentMapping"> <key>someKey</key> <value>someValue</value> ... ... </property> ... ... </component>
|
|
Rails e Grails
|
top
|
Arriviamo agli esempi più illustri di uso congiunto di CoC e DRY come Rails e Grails.

<< Figura 4: Rails & Grails >>
Creare una semplice applicazione Grails è veramente semplice.
Con il comando %GRAILS_HOME%\bin\grails create-app kokHello viene create una struttura di directory standard, indipendente dall’IDE e decisamente ordinata.  << Figura 5: L’alberatura delle directory generata da Grails >>
Per creare una classe di Dominio è sufficiente digitare il comado %GRAILS_HOME%\bin\grails create-domain-class person e inserire (in modalità Groovy) due proprietà:
class Person { String name String email }
Il passo successivo è la definizione di un Controller, che gestisca le operazioni relative alla nostra classe di dominio.
Ovviamente, Grails ci viene in aiuto. Dalla riga di comando è sufficiente digitare: %GRAILS_HOME%\bin\grails create-controller person
Attiviamo ora il Dynamic Scaffolding. Il termine "scaffolding" (letteralmente "impalcatura") è stato portato alla ribalta da Ruby on Rails e sta ad indicare tutto quel codice che in se per se non "fa" nulla, ma che è necessario per interpretare i campi del form di una pagina web, ad esempio, e di trasformarli in attributi di un oggetto di dominio.
Grails permette sia di generare staticamente tutto il codice di scaffolding del controller o delle pagine che di generare lo stesso codice direttamente a run-time.
class PersonController { def scaffold = Person }
Lanciamo l’applicazione: grails run-app
Lo skeleton dell’applicazione è già pronto e funzionante all’URL: http://localhost:8080/kokHello/

<< Figura 6: L’esempio Grails >>
|
|
Conclusioni
|
top
|
I pattern Convention over Configuration e Don’t Repeat Yourself sono alla base di importanti Framework di nuova generazione. Nel rispettare tali principi, lo sviluppo di nuove applicazioni vede semplificare notevolmente la programmazione, soprattutto agli stadi iniziali di apprendimento di un nuovo framework. Inoltre il codice generato risulta molto più pulito, mantenibile e leggibile.
|
|
|

Eccetto dove diversamente specificato, i contenuti di questo sito sono rilasciati sotto licenza Creative Commons
|
|
|