Regole Di Buona Programmazione Java
Regole Di Buona Programmazione Java
Regole generali
13. Nel costrutto switch case prevedere sempre un default (controllo attivo)
35. Inserire lo statement di break nel costrutto switch case (controllo attivo)
54. Il metodo equals usato per comparare array incompatbili (controllo attivo)
57. Il method call passa parametri nulli al posto di non nulli (ALL_TARGETS_DANGEROUS)
(controllo attivo)
58. Il method call passa parametri nulli al posto di non nulli (controllo attivo)
59. Mappe e set di URL che comportano problemi di performance (controllo attivo)
60. Equals and HasCode che comportano problemi di performance (controllo attivo)
62. String non costanti passate a metodi execute all'interno di statement SQL (controllo attivo)
Indice
Indice
La classe System espone una serie di funzionalità che permettono alle classi della Java Virtual
Machine di interagire con il sistema esterno. Esempi possono essere la scrittura sullo stream di
output o sullo stream di error.
Indice
Il campo in della classe System offre diretto accesso allo standard input dell’ambiente di
esecuzione. Il suo utilizzo può quindi bloccare l’application server e pertanto va assolutamente
evitato.
I campi out e err danno accesso agli stream rispettivamente di output e di error. L’accesso a
queste risorse causa una contention con l’application server stesso per il loro utilizzo, con
conseguente degrado delle prestazioni del sistema. Ne deriva che per la scrittura di log (con
informazioni, errori, warning, ecc…) occorre utilizzare librerie opportune. Un corollario a
questa regola è che anche per la tracciatura delle eccezioni non bisogna appoggiarsi al metodo
printStackTrace che scrive sullo stream di errore di default.
Indice
La gestione della memoria all’interno dell’application server, e in generale della Java Virtual
Machine, è regolata da sofisticati algoritmi che, nel caso di applicazioni ben progettate, non
necessitano di interventi esterni per poter regolare in modo ottimale l’utilizzo dell’heap (area di
memoria in cui sono allocati dinamicamente gli oggetti).
Richiamare direttamente l’intervento del Garbage Collector (GC) dalla classe System è
una pratica sconsigliata in quanto interferisce con le politiche di gestione automatica della
memoria, dando luogo a potenziali rallentamenti invece che benefici.
Inoltre, si tenga presente che l’invocazione del metodo System.gc(); è un invito allo start del
GC, lasciando al sistema la decisione del “se” e “quando” far partire questa operazione.
Nei casi in cui si registri un crescente utilizzo della memoria da parte dell’application
server, il problema si deve probabilmente identificare nell’allocazione di troppi oggetti che
continuano a rimanere referenziati nonostante l’applicazione non li utilizzi più. Lo scrivere
codice seguendo le linee guida della programmazione Java, mette al riparo dai picchi di
allocazione di memoria di oggetti software. Di contro la soluzione al problema non consiste
nel richiamare il GC.
Indice
E’ vietato l’utilizzo dei metodi di accesso in lettura e scrittura alle proprietà di sistema, ad
esempio con i metodi:
L’unica eccezione consiste nella lettura delle variabili d’ambiente definite dal Facility
Management. Tuttavia l’accesso a queste variabili non deve essere disperso nel codice, ma
concentrato in una classe di utilità, rendendo possibile un unico punto di controllo, di gestione
degli errori e di eventuale modifica della funzionalità.
Indice
L’apertura di un file in scrittura o in lettura deve essere considerato un evento da gestire con
molta cura per i seguenti motivi:
L’utilizzo del package java.io è vietato all’interno del container da parte delle specifiche J2EE.
Come per la classe System e per i thread, il suo utilizzo non dà luogo ad errori ma può
compromettere il corretto funzionamento e le performance dell’application server;
Il meccanismo di switch messo a punto dal Facility Management (che prevede lo spostamento
del pacchetto in cui è eseguito weblogic su un’altra macchina per motivi di manutenzione, carico
o problemi) potrebbe essere messo in crisi da un componente che abbia un lock su un file.
Evitare l’accesso diretto ai file se non per casi indispensabili, avendo comunque cura di
chiudere sempre il file dopo il suo utilizzo tramite un blocco finally [JBP].
Uno dei casi in cui è indispensabile accedere in lettura ad un file si verifica quando è necessario
leggere delle impostazioni contenute in un file di properties. Secondo le indicazioni del Facility
Management i file di configurazione devono trovarsi nella cartella che viene indicata
nell’ambiente di esecuzione dalla variabile d’ambiente configfile.path.
Indice
8. Serializzazione degli oggetti
Tutti gli oggetti che sono referenziati nell’HttpSession o che possono essere membri,
parametri o valori di ritorno negli EJB devono implementare l’interfaccia
java.io.Serializable.
Nel caso in cui questi oggetti non implementassero l’interfaccia Serializable, oltre a
contravvenire alle specifiche J2EE, si verificherebbero errori e problemi nelle seguenti
casistiche:
• Si effettua la chiamata di un EJB remoto, con conseguente serializzazione di tutti i
parametri e degli oggetti restituiti come risultato;
• L’application server viene configurato per archiviare l’HttpSession su file system o su
una base dati per gestire un livello di servizio migliore in termini di disponibilità (scenari
di high availability e clustering);
• L’application server viene configurato per serializzare la sessione e trasmetterla ad
un’altra istanza in caso di necessità (scenari di high availability e clustering);
• L’application server viene configurato con politiche di archiviazione o trasmissione per
gli EJB di tipo Stateful (scenari di high availability e clustering);
• L’application server, nell’ambito del normale ciclo di vita degli EJB, effettua la
“passivazione” o l’”attivazione” degli stessi, serializzando gli oggetti referenziati come
membri di classe.
Se in uno dei casi descritti un oggetto non può essere serializzato o se una delle sue
variabili non può esserlo (ad esempio una connessione al DB o un Context JNDI) allora la
dichiarazione dell’oggetto non serializzabile deve essere preceduta dalla parola chiave
transient.
Essa indica alla Java Virtual Machine di non tentare la serializzazione dell’oggetto in questione,
evitando errori durante l’esecuzione dei metodi.
Indice
Nel caso si debbano affrontare scelte applicative che facciano uso di soluzioni custom di
prodotti, è consigliabile fare riferimento all’Area di Architettura per la valutazione
dell’impatto architetturale della soluzione ipotizzata.
Indice
Per classi che posseggono unicamente metodi static, verificare la possibilità di creare dei
Singleton. Questa strategia non si applica per classi Abstract, poiché le loro sottoclassi
potrebbero dovere includere metodi non statici.
Indice
Esempio:
Indice
Esempio:
Indice
Tutti gli statement switch case debbono includere una opzione di default per gestire valori non
specificati.
Esempio:
Indice
Evitare la creazione di costrutti if annidati a causa della difficoltà nella lettura del codice e della
manutenibilità.
Esempi:
Indice
Se un campo di tipo final viene assegnato ad una costante a compile time, può essere dichiarato
anche static, evitando overhead in ogni oggetto a runtime.
Esempio:
Indice
Assicurarsi che le risorse come Connection, Statement, ResultSet, vengano sempre chiuse al
termine del loro utilizzo. Spesso si possono verifcare lock su tabelle a causa di eccezioni non
gestite nelle quali non viene effettuata la rollback e chiuse le risorse.
Esempio:
Esempio:
Indice
//AllocationExpression
/ClassOrInterfaceType[@Image='Vector' or @Image='java.util.Vector']
Esempio:
Indice
I nuovi oggetti create in loops devono essere controllati per vedere se possono essere create al di
fuori dei loops e riutilizzati.
Esempio:
public class Something {
public static void main( String as[] ) {
for (int i = 0; i < 10; i++) {
Foo f = new Foo(); // Avoid this whenever you can it's really expensive
}
}
}
Indice
L’uso dell’operatore '+=' per concatenare stringhe comporta che la JVM crei ed usi una
StringBuffer interna. Se un non-trivial number di queste concatenazioni sono usate un uso
esplicito di uno StringBuilder o uno stringBuffer vthreadsafe threadsafe è consigliato per evitare
ciò.
Esempio:
Indice
Invece di copiare manualmente i dati tra 2 array usare l’efficiente metodo System.arraycopy
Esempio:
Indice
Esempio:
boolean checkIt(String x) {
return x.startsWith("a"); // suboptimal
}
boolean fasterCheckIt(String x) {
return x.charAt(0) == 'a'; // faster approach
}
}
Indice
Usando '==' o '!=' per confrontare stringhe funziona solamente se intern version sono usate su
emtrambi i lato. Usare al suo posto il metodo equals().
Esempio:
Esempio:
Indice
Evitare di chiamare toString() su oggetti che già si conosce essere istanze di stringa; non è
necessario.
Esempio:
Indice
Evitare di istanziare String objects; questo è di solito non necessario poiché sono immutable e
possono essere sharati in sicurezza.
Esempio:
Indice
Esempio:
Indice
Non c’è necessità di chiamare String.valueOf per concatenare ad una stringa; basta usare
valueOf() come argomento direttamente.
Esempio:
Indice
//FieldDeclaration/Type/ReferenceType/ClassOrInterfaceType[@Image = 'StringBuffer'
or @Image = 'StringBuilder']
Indice
Esempio:
String x = "foo";
if (x == null) { // preferred
doSomething();
}
Indice
Evitare di istanziare oggetti utilizzando getClass() sulla classe. Preferibile l’utilizzo del metodo
pubblico .class.
Esempio:
// replace this
Class c = new String().getClass();
// with this:
Class c = String.class;
Indice
Assicurarsi di identificare il Locale quando si crea un’istanza della classe SimpleDateFormat per
assicurarsi che sia utilizzata la formattazione opportuna per il Locale desiderato.
Esempio:
Indice
33. Attributi immutabili
Identificare i campi private il cui valore non cambia una volta inizializzati nel costruttore.
Questo aiuta a convertire i campi in final e renderli immutabili.
Esempio:
Indice
La sincronizzazione a livello di metodo può causare problemi se viene aggiunto codice nel
metodo. La sincronizzazione su un blocco aiuta ad assicurare che solo il codice che necessita
sincronizzazione la abbia.
Esempio:
Indice
Gli statement switch senza statement di break o return per ogni opzione case possono generare
comportamenti problematici.
Esempio:
Indice
Non vi è necessità di controllare il null prima di eseguire una instanceOf; se passi un argomento
null, l’istanza restituisce false
Esempio:
class Foo {
void bar(Object x) {
if (x != null && x instanceof Bar) {
// just drop the "x != null" check
}
}
}
Indice
Nelle comparazioni inserire come primo operatore campi litteral, se il secondo argomento è null,
viene evitata la NullPointerException.
Esempio:
class Foo {
boolean bar(String x) {
return x.equals("2"); // should be "2".equals(x)
}
}
Indice
Lanciare una nuova eccezione da un blocco catch senza passare l’eccezione orignale nella nuova
eccezione, causa la perdita dello stack trace originario, rendendo difficile un eventuale debug.
Esempio:
Indice
Il metodo isEmpty() della classe collection viene realizzato per determinare se una collezione ha
degli elementi.
Esempio:
Indice
Esempio:
Indice
Esempio:
Indice
Esempio:
class Foo{
Logger log = Logger.getLogger(Foo.class.getName());
public void testA () {
System.out.println("Entering test");
// Better use this
log.fine("Entering test");
}
}
Indice
Utilizzare l’istanza di Logger, ma non richiamare la printStacktrace che logga sullo standard
output
Esempio:
class Foo {
void bar() {
try {
// do something {
} catch (Exception e) {
e.printStackTrace();
}
}
}
Indice
Esempio:
Indice
Indice
Esempio:
Indice
Gestire eccezioni di tipo Throwable non è raccomandato poichè lo scope dell’errore è molto
vasto e va da errori runtime out of memory
Esempio:
Indice
Blocchi catch vuoti implicano che una eccezione venga gestita ma senza che nessuna azione
venga presa causando possibili problemi nell’esecuzione del codice.
Esempio:
Indice
Esempio:
Indice
La complessità, che influisce direttamente sui costi di manutenzione,è determinate dal numero di
decision points in un metodo. I decision points includono costrutti if, while, for e case.
Esempio:
Indice
Indice
Questa classe definisce un metodo equals che restituisce sempre true. Questo ha molto senso. In
più significa che il metodo equals non sia simmetrico.
Indice
Questo metodo invoca il equals(Object o) per comparare due array, ma di tipi incompatibili
(i.e. String[] e StringBuffer[], o String[] e int[])
Non saranno mai uguali. Inoltre quando equals (...) è usato per comparare array controlla
soltanto se sono lo stesso array ed ignora il contenuto degli array.
Indice
Indice
Questo cast solleverà sempre una ClassCastException. L'analisi crede di conoscere il tipo
preciso del valore di cui fa cast e tenta di farne downcast su un subtype; il downcoast fallirà
sempre sollevando una ClassCastException.
Indice
Un valore possibilmente null è passato ad una call site dove tutti i metodi target conosciuti
richiedono che il parametro sia non null. O il parametro è annotato come un parametro che
dovrebbe essere sempre non null, o l' analisi deve avere dimostrato che sarà sempre
dereferenziato.
Indice
Questo method call passa un valore nullo per un parametro del metodo non nullo. O il parametro
è annotato come un parametro che dovrebbe essere sempre non nullo, o l' analisi deve avere
dimostrato che sarà sempre dereferenziato.
Indice
Questo metodo o campo è o usa una MAPPA o SET di URL. Siccome entrambi gli equals ed
hashCode URL method effettuano domain name resolution, questo può produrre un probelma di
perfomance.
Indice
Entrambi gli equals ed hashCode URL method effettuano domain name resolution; questo può
produrre un problema di perfomance.
Indice
Il codice accede ad un database con una password in chiaro. Chiunque acceda al sorgente o al
compilato può acquisire la password.
Indice
62. String non costanti passate a metodi execute all'interno di statement SQL
Il metodo invoca il metodo execute all'interno di un SQL statement con una String che sembra
dinamicamente generata. Si consiglia di usare al posto un prepared statement. E' più efficiente e
meno vulnerabile agli attacchi di tipo SQL injection.
Indice
Presentation
Una web application è costituita da un insieme di risorse che contribuiscono a formare lo strato
di interazione tra gli utenti e il backend.
Esiste una distinzione tra le risorse che possono essere gestite da un web server tradizionale,
senza nessuna necessità di elaborazioni ulteriori e che sono definite statiche, rispetto alle risorse
che devono essere gestite da un web container, perché necessitano di elaborazioni, e che sono
definite dinamiche.
Sebbene un web container come quelli, ad oggi, in uso (Tomcat e Weblogic) possa servire il
contenuto statico senza problemi funzionali, le sue performance e il suo tuning non sono così
ottimizzati per questo tipo di contenuto come possono esserlo invece per un web server (ad oggi
il web server di riferimento è Apache, che sta terminando la sostituzione di iPlanet nei diversi
ambienti).
Indice
Viene considerato una best practise l’utilizzo di url “relativi” all’interno delle web application
Java, sia per referenziare immagini che per indicare link o altre risorse.
Questo tuttavia significa che un url relativo generato da una jsp che si trovi nella web
application di esempio "myweb" avrà una forma del tipo:
http://webServer:port/myweb/myResource
Questo url non è compatibile con l’architettura tecnologica per due motivi:
• le risorse statiche accedute dalle JSP non si trovano sull’application server ma sul web
Server in una directory particolare;
• le risorse dinamiche vengono reindirizzate dal web server all’application server solo se
precedute da una stringa particolare.
E’ necessario anteporre a tutti i riferimenti presenti nelle pagine generate dall’application
server il corretto prefisso, sia nel caso in cui si tratti di risorse statiche che nel caso in cui si
tratti di risorse dinamiche.
Per permettere alla propria applicazione di poter essere eseguita senza problemi sia sulla
piattaforma di sviluppo (che non prevede un web server anteposto all’application server ) sia
negli ambienti di application test, system test e produzione, è opportuno che il prefisso da
anteporre agli url sia costruito partendo da un file di configurazione.
Indice
Esistono molte soluzioni che aiutano nell’implementazione di questo paradigma ma, senza voler
entrare nello specifico, valgono alcune raccomandazioni.
Evitare di utilizzare le servlet per la generazione della view, dando luogo a lunghe
sequenze di println, che rendono ingestibile la presentation da chi abbia skill di web
design.
Evitare di utilizzare le jsp per la gestione del flusso di navigazione, per la gestione dei dati
o per la logica applicativa.
Le jsp devono essere del tutto prive di scriptlet java e utilizzare, per la logica di
presentazione, le Tag Libraries.
Localizzare la Business Logic in classi che non abbiano nessun riferimento alle API J2EE
in modo che siano testabili e riusabili al di fuori del contesto specifico.
Indice
Le specifiche J2EE mettono a disposizione dei progettisti e degli sviluppatori quattro contenitori
che possono essere usati per archiviare (per intervalli di tempo più o meno lunghi) gli oggetti
che compongono ad esempio: lo stato conversazionale con il client, le preferenze scelte
dall’utente, i valori di configurazione, ecc…
Le quattro classi che possono essere usate per questa funzione in una web application sono:
• javax.servlet.jsp.PageContext: questa classe viene tenuta in memoria per la durata
dell’esecuzione di una singola JSP;
• javax.servlet.http.HttpServletRequest: questa classe rappresenta una request, e come
tale il suo ciclo di vita è legato all’elaborazione di una singola richiesta del client, anche
se questa dovesse attraversare più servlet o jsp con il meccanismo del redirect o del
forward;
• javax.servlet.http.HttpSession: questa classe rappresenta una sessione. Viene creata al
primo utilizzo che se ne fa e viene mantenuta in memoria fino a quando viene
espressamente distrutta (ad esempio a seguito di un logout) oppure per timeout a seguito
di inattività;
• javax.servlet.ServletContext: questa classe viene mantenuta in memoria per tutta la
durata di un’applicazione, e quindi ogni oggetto da essere referenziato non viene mai
deallocato.
Mentre PageContext e HttpServletRequest hanno una vita molto breve e quindi non danno
problemi nell’allocazione e nella gestione della memoria, occorre porre molta attenzione agli
oggetti referenziati nei contenitori di vita più lunga (HttpSession e ServletContext) in quanto
fino a che continueranno ad essere referenziati il Garbage Collector (GC) non potrà liberare la
memoria da essi utilizzata, anche se tali oggetti non servissero più a nulla (ad esempio perché
l’utente è uscito da una certa sezione della web application oppure perché si è disconnesso).
In particolare può essere pericoloso referenziare collections (come List o Map) che vengono poi
utilizzati nelle pagine o nelle classi di logica per referenziare altri oggetti, con il rischio che tali
oggetti non possano più essere liberati dalla memoria.
Nel progetto web, si consiglia di offrire all’utente il caso d’uso di log-out esplicito
dall’applicazione. L’implementazione associata si occuperà, fra l’altro, di liberare le
risorse allocate e in particolare l’HttpSession.
Casi d’uso che prevedono l’implementazione di una sessione con determinate caratteristiche di
persistenza, consigliano un approccio diverso, rispetto al supporto di sessione con HttpSession.
In situazioni così articolate è il caso di coinvolgere l’Area di Architettura perché sia studiato un
approccio di progetto più strutturato.
Indice
Nella gestione delle request effettuata tramite l’estensione della classe HttpServlet, occorre
gestire in modo specifico e diverso le chiamate di tipo GET e di tipo POST.
La casistica è la seguente:
• Se l’applicazione prevede solamente richieste di uno dei due tipi, implementare
normalmente il metodo corretto (doGet o doPost rispettivamente). Il metodo non
utilizzato dovrebbe gestire le richieste non previste reindirizzandole ad una pagina di
avviso;
• Se l’applicazione prevede richieste di entrambe i tipi occorre gestirle correttamente con
le specificità di ognuna.
Indice
Esiste una limitazione storica nella lunghezza degli URI gestiti dai web server pari a 256
caratteri, anche se attualmente molte implementazioni superano questo limite portandolo a 4000.
Per mantenere la portabilità, un’applicazione deve evitare di superare il limite dei 256
caratteri negli URI generati e utilizzare richieste di tipo POST nel caso in cui questi non
siano sufficienti per contenere l’indirizzo dell’applicazione più i parametri.
Si tenga presente che l’URI di un’invocazione GET viene visualizzato per intero, con tutte le
informazioni passate, nella barra di navigazione del browser.
Indice
E’ buona pratica estrarre dai componenti che si occupano della view tutte le stringhe che
costituiscono messaggi per l’utente, etichette, ecc…
Queste stringhe devono essere raccolte in opportuni file di properties per permettere una facile
modifica e/o internazionalizzazione, tramite il meccanismo i18n di Java.
In questo caso la pagina jsp dovrebbe usare il nome dell‘immagine leggendolo da un file di
properties simile a quello usato per i messaggi di testo, utilizzando il meccanismo i18n di Java
per ricavare il corretto nome dell’immagine a seconda del linguaggio utente
Indice
Il frontend deve confinare in classi ben specifiche le chiamate al layer di business logic, allo
scopo di proteggersi dal cambiamento della tecnologica e dell’interfaccia del backend.
Indice
Evitare l’utilizzo di script fatti direttamente sulle pagine. Implementare lo script all’interno di
una tag library.
Esempio: :
<HTML>
<BODY>
<!--Java Script-->
< SCRIPT language="JavaScript" type="text/javascript">
<!--
function calcDays() {
var date1 = document.getElementById('d1').lastChild.data;
var date2 = document.getElementById('d2').lastChild.data;
date1 = date1.split("-");
date2 = date2.split("-");
var sDate = new Date(date1[0]+"/"+date1[1]+"/"+date1[2]);
var eDate = new Date(date2[0]+"/"+date2[1]+"/"+date2[2]);
var daysApart = Math.abs(Math.round((sDate-eDate)/86400000));
document.getElementById('diffDays').lastChild.data = daysApart;
}
onload=calcDays;
//-->
</SCRIPT>
</BODY>
</HTML>
Indice
Evitare l’utilizzo degli scriptlet direttamente sulle pagina JSP. Preferibile inserire all’interno di
una tag library il codice java.
Esempio: :
<HTML>
<HEAD>
<%
response.setHeader("Pragma", "No-cache");
%>
</HEAD>
<BODY>
<jsp:scriptlet>String title = "Hello world!"; </jsp:scriptlet>
</BODY >
</HTML >
Indice
Le informazioni sulle regole di stile da applicare alla pagina jsp, debbono essere inserite
all’interno del foglio di stile. Evitare l’utilizzo delle dichiarazioni di stile all’interno delle pagine
(ex <B >, <FONT >, align=center)
Esempio: :
<HTML> <BODY> <p align='center' > <b >text </b > </p > </BODY ></HTML >
Indice
12. Evitare l’utilizzo del forward all’interno di una JSP
Esempio: :
Indice
I tag iframe che non contengono l’attributo src, possono causare sul browser IE l’attivazione di
popup di sicurezza se si accede alla pagina in SSL.
Esempio: :
Indice
In produzione i commenti all’interno del codice HTML aumentano il payload trasmesso tra il
web server ed Il client. Preferibile utilizzare commenti JSP
Esempio: :
Indice
15. Evitare duplicazione di tag import
Esempio: :
Indice
Inserire all’interno della pagina JSP la dichiarazione dell’encoding con il quale interpretare il
linguaggio.
Esempio: :
Indice
Evitare lo script all’interno del codice HTML. Esternalizzare dove possibile utilizzando
l’attributo src dela tag <SCRIPT > .
Script esternalizzati possono essere ri-utilizzati tra pagine diverse ed il browser può cachare lo
script riducendo il payload trasmesso.
Indice
Application
In un contest java enterprise il metodo getClassLoader() potrebbe non funzionare come atteso,
spesso il suo comportamento viene dettato dalla implementazione fatta dal vendor
dell’application server.
Utilizzare il costrutto Thread.currentThread().getContextClassLoader().
Esempio:
Indice
Le specifiche EJB affermano che ogni Message Driven Bean o Session Bean, debba avere il
suffisso Bean
Esempio:
Indice
Esempio:
Indice
L’interfaccia remota di un SessionBean di un EJB non dovrebbe avere suffissi come session o
ejb.
Esempio:
Indice
Indice
Esempio:
// Neither this,
public class OtherThread implements Runnable {
Indice
Indice
Java mette a disposizione l’utilizzo della keywork deprecated che, aggiunta davanti al metodo
di un’interfaccia, comunica in modo puntuale e chiaro agli utilizzatori di tale metodo che questo
sta per venire dimesso e occorre prevedere l’utilizzo di nuove modalità.
[.................................]
/**
* @deprecated dalla versione XXXXX, sostituito da
* {@link #myNewMethod() }
*/
public void myMethod() {
[………………………………………]
}
/**
* Questo metodo sostituisce il precedente {@link #myMethod() }
*/
public void myNewMethod() {
[………………………………………]
}
[.................................]
Indice
I vantaggi di questo approccio consistono nel poter avere una serie di funzionalità implementate
in modo trasparente rispetto al container o ai protocolli con cui vengono utilizzate, con vantaggi
di riusabilità e di semplicità di sviluppo e test.
Indice
10. Non frammentare l’interfaccia della logica applicativa
E’ bene valutare la granularità delle funzionalità esposte dalla logica applicativa, soprattutto in
relazione alla possibilità di riuso del software.
Un ottima guida nella gestione della granularità dei servizi deriva dal pattern noto come
Session Facade [BLU] che sebbene sia nato per risolvere questo problema in ambito EJB si
presta ad essere declinato in diversi contesti tecnologici.
Indice
Indice
Data
2. Accedere alle connessioni in modo da poter testare le classi al di fuori del container
3. ORM o SQL
L’accesso ai dati deve avvenire in modo più trasparente possibile rispetto al prodotto
utilizzato e in un layer specifico e configurabile.
Questo approccio è noto con il termine di Data Access Object, o DAO, e la sua applicabilità si
estende anche ad altri contesti, dall’utilizzo del Message And Queuing all’accesso di qualunque
informazione con qualunque tecnologia.
Un vantaggio implicito di questa soluzione è che tutto il codice “accessorio” all’accesso ai dati
(gestione delle connessioni, delle transazioni, degli statement) è naturalmente concentrato in
poche classi, dando ulteriori vantaggi di manutenibilità del software.
Indice
2. Accedere alle connessioni in modo da poter testare le classi al di fuori del container
La gestione delle connessioni deve essere implementata in modo tale che, a seconda del
contesto di esecuzione, siano acquisite connessioni utilizzando le facility a disposizione, e
quindi avvalendosi del Datasource in un contesto enterprise o creando direttamente
connessioni dal driver JDBC in un contesto stand alone.
Indice
3. ORM o SQL
L’utilizzo diretto dell’SQL può essere considerato la scelta migliore nei casi in cui un progetto
sia di dimensioni tali da non giustificare i tempi di apprendimento e di progettazione di un layer
ORM, di fronte ad un guadagno in termini di produttività nello sviluppo e manutenzione del
codice tanto minore quanto più piccolo è il progetto.
E’ evidente che la determinazione dei costi di apprendimento e utilizzo delle soluzioni ORM
dipende dal grado di esperienza e confidenza nello strumento da parte del team (dall’analista
tecnico agli sviluppatori).
Nei casi in cui i costi di apprendimento siano bassi o nulli, queste soluzioni possono venire
validamente impiegate anche per progetti di piccole dimensioni.
Nel caso di soluzioni che prevedono l’uso di ORM o particolari soluzioni non affrontate tra
queste regole è d’obbligo sottoporre all’Area di Architetture la soluzione ipotizzata, perché
possa essere certificata e inserita nel corretto contesto architetturale.
Indice
Nel caso in cui si utilizzi direttamente l’SQL in un progetto, è bene evitare di disseminare
le istruzioni SQL in molte classi.
A titolo di esempio si indicano tre strategie che permettono un buon controllo sull’SQL:
1. inserire le istruzioni SQL su file di testo esterni alle classi Java. In questo caso il
vantaggio consiste nel poter cambiare queste istruzioni (ad esempio a seguito dell’attività
di tuning in una select) senza ricompilare l’applicazione;
2. concentrare le istruzioni SQL definendole come costanti in un gruppo di classi ben
definito. Si potrebbero ad esempio utilizzare tre classi, una che contiene tutte le istruzioni
di update, una le istruzioni di insert e un’altra le select;
3. definire come costanti anche tutti i nomi di colonne e di tabelle e utilizzare tali costanti
nella definizione delle istruzioni SQL. In questo modo di fronte al cambiamento del
nome di una colonna o di una tabella si potrà intervenire in un unico punto aggiornando
automaticamente tutto il codice.
Indice
Le istruzioni SQL devono indicare sempre i nomi delle colonne a cui si riferiscono nelle
select, insert o update. Evitare dunque i riferimenti impliciti basati sull’ordine dei campi.
Questo modo di lavorare protegge l’applicazione dall’evoluzione della base dati in cui, a seguito
di istruzioni di modifica, l’ordine delle colonne potrebbe cambiare.
Indice
L’invio ad un DB server di una istruzione SQL può essere effettuato con due modalità.
Si può semplicemente usare uno statement a fronte del quale il DB Server dovrà compilare
l’istruzione ed eseguirla oppure si può utilizzare un PreparedStatement a fronte del quale il DB
Server:
• verificherà se tra le istruzioni già compilate e presenti in cache esiste quella richiesta;
• in caso positivo riuserà l’istruzione in cache;
• in caso negativo compilerà l’istruzione e la metterà in cache prima di eseguirla.
E’ evidente che tanto più spesso viene riusata un’istruzione tanto maggiori saranno i
guadagni in termini di performance dovuti al risparmio delle ricompilazioni delle
istruzioni. Per questo motivo l’utilizzo dei PreparedStatement viene considerato preferibile
all’utilizzo dei normali statement in tutti i casi in cui si preveda che un’istruzione venga
eseguita con una certa frequenza.
Indice