Il 0% ha trovato utile questo documento (0 voti)
12 visualizzazioni43 pagine

Regole Di Buona Programmazione Java

Regole basi di una buona programmazione in JAVA

Caricato da

cciccio
Copyright
© © All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Il 0% ha trovato utile questo documento (0 voti)
12 visualizzazioni43 pagine

Regole Di Buona Programmazione Java

Regole basi di una buona programmazione in JAVA

Caricato da

cciccio
Copyright
© © All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Sei sulla pagina 1/ 43

Regole di buona Programmazione Java

Regole generali

1. Divieto di creazione di nuovi thread

2. Divieto di utilizzo della classe runtime

3. Divieto di utilizzo della classe system

4. Divieto di scrittura o lettura per gli stream out, err o in

5. Divieto di utilizzo diretto del garbage collector (controllo attivo)

6. Utilizzo delle proprietà di sistema

7. Gestione dei file

8. Serializzazione degli oggetti

9. Non referenziare classi proprietarie di prodotti

10. Privilegiare utilizzo di classi singleton

11. Privilegiare la semplificazione del return su controlli booleani

12. Semplificare le espressioni booleane

13. Nel costrutto switch case prevedere sempre un default (controllo attivo)

14. Evitare costrutti if annidati

15. Prevedere per campi final assegnazioni static

16. Prevedere sempre la chiusura delle risorse

17. Ottimizzare le chiamate to array (controllo attivo)

18. Use array list instead of vector

19. Avoid instantiating objects in loops

20. Use string buffer for string appends (controllo attivo)

21. Avoid array loops

22. Simplify starts with


23. Use equals to compare strings

24. Use index of char

25. String to string

26. String instantiation

27. Avoid duplicate literals

28. Use less string value of

29. Avoid string buffer field

30. Test null (controllo attivo)

31. Evitare istanze con getclass

32. Utilizzo della classe simpledateformat necessita di specificare il locale

33. Attributi immutabili

34. Evitare utilizzo di syncronized a livello di metodo

35. Inserire lo statement di break nel costrutto switch case (controllo attivo)

36. Semplificare le espressioni condizionali (controllo attivo)

37. In una comparazione inserire come primo operatore costanti

38. Preservare lo stack trace della eccezione originale

39. Utilizzare il metodo delle collection isempty() per testare la size

40. Utilizzare un solo logger per classe

41. Logger static final

42. Evitare utilizzo di system.out.println / err

43. Evitare utilizzo di printstacktrace

44. Istanza Boolean

45. Evitare di utilizzare ip hardcoded (controllo attivo)

46. Controllare il risultato del resultset


47. Exception: evitare di gestire eccezioni throwable (controllo attivo)

48. Evitare import non utilizzati

49. Evitare blocchi catch vuoti (controllo attivo)

50. Evitare statement if vuoti (controllo attivo)

51. Indice di complessità ciclomatica

52. Il metodo equals restituisce sempre false (controllo attivo)

53. Il metodo equals restituisce sempre true (controllo attivo)

54. Il metodo equals usato per comparare array incompatbili (controllo attivo)

55. Impossibile cast (controllo attivo)

56. Impossibile downcast (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)

61. Password del DB costante codificata nel codice (controllo attivo)

62. String non costanti passate a metodi execute all'interno di statement SQL (controllo attivo)

1. Divieto di creazione di nuovi thread

La creazione di nuovi thread in un’applicazione J2EE, ha l’effetto di rendere impossibile


all’application server la gestione ottimizzata dei thread proprietari, con conseguente possibile
degrado delle prestazioni ed impossibilità da parte del gruppo di Facility Management di gestire
il comportamento del Server e dell’applicazione.

Indice

2. Divieto di utilizzo della classe runtime


Ogni applicazione Java ha accesso alla classe Runtime che permette di interfacciarsi
all’ambiente di esecuzione. L’utilizzo dei metodi di questa classe può interferire con il buon
funzionamento dell’application server dando luogo a situazioni impreviste e non gestibili dal
Facility Management.

Indice

3. Divieto di utilizzo della classe System

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

4. Divieto di scrittura o lettura per gli stream out, err o in

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.

La corretta politica di gestione di tutti i messaggi di log e di errore è quella di utilizzare


log4j che è una libreria di log specializzata. Applicare comunque l’accortezza di non
referenziare direttamente log4j nei propri oggetti ma soltanto attraverso una propria
classe di utilità.

Indice

5. Divieto di utilizzo diretto del garbage collector

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

6. Utilizzo delle proprietà di sistema

E’ vietato l’utilizzo dei metodi di accesso in lettura e scrittura alle proprietà di sistema, ad
esempio con i metodi:

String property = System.getProperty(“key”);


System.setProperty(“key”, “new value”);

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

7. Gestione dei file

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

9. Non referenziare classi proprietarie di prodotti

Qualora un’applicazione utilizzasse classi proprietarie di un qualsiasi prodotto (dall’application


server al DB Server a librerie di terze parti) o facesse affidamento su funzionalità non standard
degli stessi, sarebbe compromessa la sua portabilità rendendo difficile la sostituzione del
prodotto referenziato.

A seconda del caso, le pratiche da seguire sono le seguenti:


• attenersi rigorosamente allo standard J2EE evitando di inserire nel codice richiami
ad API specifiche dell’application server in uso;
• attenersi rigorosamente alle API JDBC ed evitare riferimenti espliciti al driver del
DB Server in uso;
• ogni qual volta risulti necessario utilizzare nella propria applicazione prodotti o
librerie di terze parti, concentrare in una o più classi tutta la logica di gestione della
componente esterna, richiamando nel codice applicativo soltanto la o le classi
appositamente create.

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

10. Privilegiare utilizzo di classi Singleton

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

11. Privilegiare la semplificazione del return su controlli booleani

Evitare costrutti if-then-else non necessari all’atto del return di un booleano.

Esempio:

public boolean isBarEqualTo(int x) {

if (bar == x) { // this bit of code...


return true;
} else {
return false;
}
}

public boolean isBarEqualTo(int x) {

return bar == x; // can be replaced with this


}

Indice

12. Semplificare le espressioni booleane


Evitare comparazioni non necessarie in espressioni booleane, impattano sulla manutenibilità e
leggibilità della applicazione

Esempio:

public class Bar {


// can be simplified to
// bar = isFoo();
private boolean bar = (isFoo() == true);

public isFoo() { return false;}


}

Indice

13. Nel costrutto switch case prevedere sempre un default

Tutti gli statement switch case debbono includere una opzione di default per gestire valori non
specificati.

Esempio:

public void bar() {


int x = 2;
switch (x) {
case 1: int j = 6;
case 2: int j = 8;
// missing default: here
}
}

Indice

14. Evitare costrutti if annidati

Evitare la creazione di costrutti if annidati a causa della difficoltà nella lettura del codice e della
manutenibilità.
Esempi:

public class Foo {


public void bar(int x, int y, int z) {
if (x>y) {
if (y>z) {
if (z==x) {
// !! too deep
}
}
}
}
}

Indice

15. Prevedere per campi final assegnazioni static

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:

public class Foo {


public final int BAR = 42; // this could be static and save some space
}

Indice

16. Prevedere sempre la chiusura delle risorse

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:

public class Bar {


public void foo() {
Connection c = pool.getConnection();
try {
// do stuff
} catch (SQLException ex) {
// handle exception
} finally {
// oops, should close the connection using 'close'!
//c.close();
}
}
}
Indice

17. Ottimizzare le chiamate toArray

Le chiamate al metodo di collection toArray() dovrebbero specificare la dimensione del vettore


target.

Esempio:

List foos = getFoos();

// inefficient, the array will be discarded


Foo[] fooArray = foos.toArray(new Foo[0]);

// much better; this one sizes the destination array,


// avoiding of a new one via reflection
Foo[] fooArray = foos.toArray(new Foo[foos.size()]);

Indice

18. Use array list instead of vector

ArrayList è un’implementazione Collection molto migliore del Vettore se un’operazione thread-


safe non è richiesta.

//AllocationExpression
/ClassOrInterfaceType[@Image='Vector' or @Image='java.util.Vector']

Esempio:

public class SimpleTest extends TestCase {


public void testX() {
Collection c1 = new Vector();
Collection c2 = new ArrayList(); // achieves the same with much better performance
}
}

Indice

19. Avoid instantiating objects in loops

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

20. Use string buffer for string appends

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:

public class Foo {


void bar() {
String a;
a = "foo";
a += " bar";
// better would be:
// StringBuilder a = new StringBuilder("foo");
// a.append(" bar);
}
}

Indice

21. Avoid array loops

Invece di copiare manualmente i dati tra 2 array usare l’efficiente metodo System.arraycopy

Esempio:

public class Test {


public void bar() {
int[] a = new int[10];
int[] b = new int[10];
for (int i=0;i<10;i++) {
b[i]=a[i];
}
}
}
// this will trigger the rule
for (int i=0;i<10;i++) {
b[i]=a[i];
}
}
}

Indice

22. Simplify starts with

Quando passano su un literal di lunghezza 1, le calls a (string).startsWith possono essere riscritte


usando (string).charAt(0) guadagnando leggibilità.

Esempio:

public class Foo {

boolean checkIt(String x) {
return x.startsWith("a"); // suboptimal
}

boolean fasterCheckIt(String x) {
return x.charAt(0) == 'a'; // faster approach
}
}

Indice

23. Use equals to compare strings

Usando '==' o '!=' per confrontare stringhe funziona solamente se intern version sono usate su
emtrambi i lato. Usare al suo posto il metodo equals().

Esempio:

public boolean test(String s) {


if (s == "one") return true; // unreliable
if ("two".equals(s)) return true; // better
return false;
}
Indice

24. Use index of char

Usare String.indexOf(char) quando si controlla l’indice di un singolo carattere; è eseguito più


velocemente.

Esempio:

String s = "hello world";


// avoid this
if (s.indexOf("d") {}
//instead do this
if (s.indexOf('d') {}

Indice

25. String to string

Evitare di chiamare toString() su oggetti che già si conosce essere istanze di stringa; non è
necessario.

Esempio:

private String baz() {


String bar = "howdy";
return bar.toString();
}

Indice

26. String instantiation

Evitare di istanziare String objects; questo è di solito non necessario poiché sono immutable e
possono essere sharati in sicurezza.

Esempio:

private String bar = new String("bar"); // just do a String bar = "bar";

Indice

27. Avoid duplicate literals


Il codice contenente duplicate String literals può solitamente essere migliorato dichiarando la
Stringa come campo costante.

Esempio:

private void bar() {


buz("Howdy");
buz("Howdy");
buz("Howdy");
buz("Howdy");
}
private void buz(String x) {}

Indice

28. Use less string value of

Non c’è necessità di chiamare String.valueOf per concatenare ad una stringa; basta usare
valueOf() come argomento direttamente.

Esempio:

public String convert(int i) {


String s;
s = "a" + String.valueOf(i); // not required
s = "a" + i; // preferred approach
returns;
}

Indice

29. Avoid string buffer field

Le StringBuffers/StringBuilders possono crescere considerevolmente, e così può diventare una


fonte di memory leaks se contenuta in oggetti con tempo di vita elevato.

//FieldDeclaration/Type/ReferenceType/ClassOrInterfaceType[@Image = 'StringBuffer'
or @Image = 'StringBuilder']

Indice

30. Test null


Non utilizzare il metodo equals() per testare se un oggetto è null, utilizzare l’operatore ‘==’.

Esempio:

String x = "foo";

if (x.equals(null)) { // bad form


doSomething();
}

if (x == null) { // preferred
doSomething();
}

Indice

31. Evitare istanze con getClass

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

32. L’utilizzo della classe SimpleDateFormat necessita di specificare il locale

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:

public class Foo {


// Should specify Locale.US (or whatever)
private SimpleDateFormat sdf = new SimpleDateFormat("pattern");
}

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:

public class Foo {


private int x; // could be final
public Foo() {
x = 7;
}
public void foo() {
int a = x + 2;
}
}

Indice

34. Evitare utilizzo di syncronized a livello di metodo

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:

public class Foo {


// Try to avoid this
synchronized void foo() {
}
// Prefer this:
void bar()
synchronized(this) {
}
}
}

Indice

35. Inserire lo statement di break nel costrutto switch case

Gli statement switch senza statement di break o return per ogni opzione case possono generare
comportamenti problematici.
Esempio:

public void bar(int status) {


switch(status) {
case CANCELLED:
doCancelled();
// break; hm, should this be commented out?
case NEW:
doNew();
case REMOVED:
doRemoved ();
}
}

Indice

36. Semplificare le espressioni condizionali

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

37. In una comparazione inserire come primo operatore costanti

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

38. Preservare lo stack trace della eccezione originale

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:

public class Foo {


void good() {
try{
Integer.parseInt("a");
} catch(Exception e) {
throw new Exception(e);
}
}
void bad() {
try{
Integer.parseInt("a");
} catch(Exception e) {
throw new Exception(e.getMessage());
}
}
}

Indice

39. Utilizzare il metodo delle collection isEmpty() per testare la size

Il metodo isEmpty() della classe collection viene realizzato per determinare se una collezione ha
degli elementi.

Esempio:

public class Foo {


void good() {
List foo = getList();
if (foo.isEmpty()) {
// blah
}
}
void bad() {
List foo = getList();
if (foo.size() == 0) {
// blah
}
}
}

Indice

40. Utilizzare un solo Logger per classe

Usare un solo Logger

Esempio:

public class Foo {


Logger log = Logger.getLogger(Foo.class.getName());
// It is very rare to see two loggers on a class, normally
// log information is multiplexed by levels
Logger log2= Logger.getLogger(Foo.class.getName());
}

Indice

41. Logger static final

In molte circostanze la reference al Logger può essere static final.

Esempio:

public class Foo {


Logger log = Logger.getLogger(Foo.class.getName()); // not recommended

static final Logger log = Logger.getLogger(Foo.class.getName()); // preferred approach


}

Indice

42. Evitare utilizzo di System.out.println / err

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

43. Evitare utilizzo di printStackTrace

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

44. Istanza Boolean

Evitare di istanziare la classe Boolean, è possibile referenziare Boolean.TRUE, Boolean.


FALSE.

Esempio:

Boolean bar = new Boolean("true"); // unnecessary creation, just reference Boolean.TRUE;


Boolean buz = Boolean.valueOf(false); // ...., just reference Boolean.FALSE;

Indice

45. Evitare di utilizzare IP HardCoded


Esempio:

public class Foo {


private String ip = "127.0.0.1"; // not recommended
}

Indice

46. Controllare il risultato del ResultSet

Controllare sempre il valore del ResultSet.

Esempio:

Statement stat = conn.createStatement();


ResultSet rst = stat.executeQuery("SELECT name FROM person");
rst.next(); // what if it returns false? bad form
String firstName = rst.getString(1);

Statement stat = conn.createStatement();


ResultSet rst = stat.executeQuery("SELECT name FROM person");
if (rst.next()) { // result is properly examined and used
String firstName = rst.getString(1);
} else {
// handle missing data }

Indice

47. Exception: Evitare di gestire eccezioni Throwable

Gestire eccezioni di tipo Throwable non è raccomandato poichè lo scope dell’errore è molto
vasto e va da errori runtime out of memory

Esempio:

public void bar() {


try {
// do something {
} catch (Throwable th) { // should not catch Throwable
th.printStackTrace();
}
}
Indice

48. Evitare import non utilizzati

Evitare import non utilizzati

Indice

49. Evitare blocchi catch vuoti

Blocchi catch vuoti implicano che una eccezione venga gestita ma senza che nessuna azione
venga presa causando possibili problemi nell’esecuzione del codice.

Esempio:

public void doSomething() {


try {
FileInputStream fis = new FileInputStream("/tmp/bugger");
} catch (IOException ioe) {
// not good
}
}

Indice

50. Evitare statement if vuoti

Evitare blocchi vuoti.

Esempio:

public class Foo {


void bar(int x) {
if (x == 0) {
// empty!
}
}
}

Indice

51. Indice di Complessità Ciclomatica

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:

public class Foo { // This has a Cyclomatic Complexity = 12

public void example() {


if (a == b) {
if (a1 == b1)
fiddle();
} else if a2 == b2) {
fiddle();
} else {
fiddle();
}
else if (c == d) {
while (c == d) {
fiddle();
}
} else if (e == f) {
for (int n = 0; n < h; n++) {
fiddle();
}
} else {
switch (z) {
case 1:
fiddle();
break;
case 2:
fiddle();
break;
case 3:
fiddle();
break;
default:
fiddle();
break;
}
}
}
}

Indice

52. Il metodo equals restituisce sempre false


La classe in oggetto definisce un equals method che restituisce sempre falso. Questo significa
che un oggetto non è uguale a sé stesso e non è possibile creare MAP o Set utili di questa classe.
Più importante, ciò significa che il metodo equals non è riflessivo ed è uno dei requisisti
fondamentali di tale metodo. La semantica del metodo è che l'oggetto sia identico a sé stesso.
Questo è il comportamento ereditato da dalla classe Object. Se si ha necessità di sovrascrivere
un equals ereditato da una differente superclass, si può usare:

public boolean equals(Object o) { return this == o; }.

Indice

53. Il metodo equals restituisce sempre true

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

54. Il metodo equals usato per comparare array incompatbili

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

55. Impossibile cast

Questo cast solleverà sempre una ClassCastException

Indice

56. Impossibile downcast

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

57. Il method call passa parametri nulli al posto di non nulli


(ALL_TARGETS_DANGEROUS)

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

58. Il method call passa parametri nulli al posto di non nulli

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

59. Mappe e set di URL che comportano problemi di performance

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

60. Equals and HasCode che comportano problemi di performance

Entrambi gli equals ed hashCode URL method effettuano domain name resolution; questo può
produrre un problema di perfomance.

Indice

61. Password del DB costante codificata nel codice

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

1. Separazione tra il contenuto statico e dinamico

2. Gestione degli URL generati all’interno delle pagine dinamiche

3. Separazione tra la logica di presentazione e di controllo

4. Gestione rigorosa degli oggetti allocati dal frontend

5. Evitare di gestire il POST e il GET con un unico metodo

6. Tenere conto della limitazione del GET a 256 char

7. Internazionalizzazione dei testi e delle immagini

8. Disaccoppiare il frontend dalla implementazione della business logic

9. Evitare l’utilizzo di script javascript troppo lunghi

10. Evitare l’utilizzo di scriptlet direttamente sulle pagine JSP

11. Evitare l’utilizzo di richiamare regole di stile in line

12. Evitare l’utilizzo del forward all’interno di una JSP

13. Evitare di utilizzare il tag iframe senza l’attributo src

14. Evitare l’utilizzo di commenti nel html

15. Evitare duplicazione di tag import

16. Encoding delle pagine JSP

17. Evitare la scrittura di codice js nel tag script

1. Separazione tra il contenuto statico e dinamico

Una web application è costituita da un insieme di risorse che contribuiscono a formare lo strato
di interazione tra gli utenti e il backend.

Questo insieme di risorse è ad esempio formato da:


• Immagini;
• Pagine html statiche;
• Fogli di stile;
• Pagine jsp dinamiche;
• Servlet;
• Classi java;
• File di configurazione e librerie di appoggio;
• Applet.

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).

Da questa considerazione deriva che lo standard in essere prevede di pubblicare tutto il


contenuto statico di una web application sul web server e limitare alla web application
vera e propria soltanto le parti dinamiche.

Indice

2. Gestione degli URL generati all’interno delle pagine dinamiche

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:

Questo insieme di risorse è ad esempio formato da:

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.

Sarebbe possibile ricavare il prefisso delle risorse dinamiche dall’header dell’HttpRequest, in


quanto il plug-in che mette in comunicazione il web server con Weblogic inserisce nell’header
la stringa del suffisso utilizzata per il mapping delle risorse dell’application server. Tuttavia
questa gestione comporterebbe una diversità tra il modo di configurare le risorse statiche (che
non può usufruire di questa informazione) e il modo di gestire quelle dinamiche. Viene pertanto
sconsigliata

Indice

3. Separazione tra la logica di presentazione e di controllo

E’ ricorrente in letteratura il richiamo al pattern chiamato: Model View Control. Anche


nell’ambiente Intesa Sanpaolo vale l’indicazione di questo pattern, che prevede una netta
separazione tra i componenti che si occupano di:
• Gestire i dati e lo stato dell’applicazione (Model);
• Visualizzare i dati (View);
• Gestire la navigazione, la scelta della view corretta e della logica applicativa (Control).

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.

E’ consigliabile creare le pagine jsp secondo un layout strutturato e componibile attraverso


operazioni di “include”.

Indice

4. Gestione rigorosa degli oggetti allocati dal frontend

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).

Una buona pratica è quella di dereferenziare gli oggetti dall’HttpSession e dal


ServletContext non appena la loro utilità viene meno, per evitare costosi sovraccarichi
della memoria utilizzata dai server.

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

5. Evitare di gestire il POST e il GET con un unico metodo

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

6. Tenere conto della limitazione del GET a 256 char

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

7. Internazionalizzazione dei testi e delle immagini

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.

La stessa regola vale anche per le immagini contenenti messaggi di testo.

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

L’utilizzo dell’internazionalizzazione di Java è lineare nella sua implementazione, ma la sua


integrazione in un’applicazione distribuita deve tenere conto di una serie di complessità
aggiuntive.

Indice

8. Disaccoppiare il frontend dalla implementazione della business logic

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.

Infatti in questo modo se l’implementazione di un metodo di business logic passasse da una


classe Java (POJO) ad un EJB e poi ad un Web Services, il client non avrebbe impatti se non in
una modifica isolata nella classe che gestisce la chiamata in oggetto.

Indice

9. Evitare l’utilizzo di script javascript troppo lunghi

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

10. Evitare l’utilizzo di scriptlet direttamente sulle pagine JSP

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

11. Evitare l’utilizzo di richiamare regole di stile in line

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

Evitare l’utilizzo del forward all’interno di una pagina JSP

Esempio: :

<jsp:forward page='myPage.jsp'/ >

Indice

13. Evitare di utilizzare il tag iframe senza l’attributo

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: :

<HTML><title>bad example> <BODY>


<iframe> </iframe>
</BODY> </HTML>

<HTML> <title> good example> <BODY>


<iframe src="foo"> </iframe>
</BODY> </HTML>

Indice

14. Evitare l’utilizzo di commenti nel html

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: :

<HTML> <title>bad example <BODY>


<!-- HTML comment -->
</BODY> </HTML>

<HTML> <title> good example <BODY>


< %-- JSP comment --%>
< /BODY> </HTML>

Indice
15. Evitare duplicazione di tag import

Evitare la duplicazione di tag import all’interno della medesima pagina JSP

Esempio: :

<%@ page import=\"com.foo.MyClass,com.foo.MyClass\"%> <html> <body> <b > <img


src=\"<%=Some.get()%>/foo\" >xx </img>text </b > </body> </html>

Indice

16. Encoding delle pagine JSP

Inserire all’interno della pagina JSP la dichiarazione dell’encoding con il quale interpretare il
linguaggio.

Esempio: :

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

Indice

17. Evitare la scrittura di codice js nel tag script

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

1. Porre attenzione all’utilizzo del class loader corretto

2. Utilizzare nomenclatura corretta per attribuire nomi a MDB e SessionBean

3. Utilizzare la nomenclatura corretta per gli oggetti Local Home

4. Utilizzare la nomenclatura corretta per gli oggetti Remote

5. Evitare di richiamare il metodo System.exit

6. Non utilizzare threads

7. Esporre la logica con interfacce

8. Utilizzare “deprecated” per gestire l’evoluzione delle interfacce

9. Disaccoppiare la logica applicativa dalla tecnologia

10. Non frammentare l’interfaccia della logica applicativa

11. Utilizzare lo strumento corretto per il compito specifico

1. Porre attenzione all’utilizzo del class loader corretto

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:

public class Foo {


ClassLoader cl = Bar.class.getClassLoader();
}

Indice

2. Utilizzare nomenclatura corretta per attribuire nomi a MDB e SessionBean

Le specifiche EJB affermano che ogni Message Driven Bean o Session Bean, debba avere il
suffisso Bean
Esempio:

public class SomeBean implements SessionBean{} // proper name

public class MissingTheProperSuffix implements SessionBean {} // non-standard name

Indice

3. Utilizzare la nomenclatura corretta per gli oggetti Local Home

L’interfaccia locale di un SessionBean EJB, dovrebbe avere un suffisso LocalHome.

Esempio:

public interface MyBeautifulLocalHome extends javax.ejb.EJBLocalHome {} // proper name

public interface MissingProperSuffix extends javax.ejb.EJBLocalHome {} // non-standard name

Indice

4. Utilizzare la nomenclatura corretta per gli oggetti Remote

L’interfaccia remota di un SessionBean di un EJB non dovrebbe avere suffissi come session o
ejb.

Esempio:

/* Poor Session suffix */


public interface BadSuffixSession extends javax.ejb.EJBObject {}

/* Poor EJB suffix */


public interface BadSuffixEJB extends javax.ejb.EJBObject {}

/* Poor Bean suffix */


public interface BadSuffixBean extends javax.ejb.EJBObject {}

Indice

5. Evitare di richiamare il metodo System.exit

Le applicazioni WEB non debbono richiamare il metodo System.exit() o


Runtime.getRuntime().exit(), poiché solo il web container o l’application server deve poter
stoppare la JVM.
Esempio:

public void bar() {


System.exit(0); // never call this when running in an application server!
}

public void foo() {


Runtime.getRuntime().exit(0); // never stop the JVM manually, the container will do this.
}

Indice

6. Non utilizzare threads

Le specifiche Java J2EE esplicitamente proibiscono utilizzo dei thread

Esempio:

// This is not allowed


public class UsingThread extends Thread {

// Neither this,
public class OtherThread implements Runnable {

// Nor this ...


public void methode() {
Runnable thread = new Thread(); thread.run();
}
}

Indice

7. Esporre la logica con interfacce

Le funzionalità di un’applicazione devono essere formalizzate tramite interfacce che


rappresentano il contratto del servizio. L’implementazione può avvenire con i componenti
più adatti al tipo di problema ed avvalersi delle tecnologie più adatte a supportare i
requisiti non funzionali richiesti (sicurezza, remoting, scalabilità, ecc…).

Questa formalizzazione ha i seguenti vantaggi:


• Evitare la dispersione della logica nei layer (ad esempio il frontend) in cui sarebbe
difficilmente riusabile, manutenibile o testabile;
• Esporre la business logic in modo semplice e indipendente dall’implementazione
tecnologica.

Indice

8. Utilizzare “deprecated” per gestire l’evoluzione delle interfacce

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

9. Disaccoppiare la logica applicativa dalla tecnologia

I componenti EJB non devono contenere logica di business. In generale la logica


applicativa deve sempre essere gestita in classi Java normali.

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.

Occorre tenere presenti le seguenti considerazioni:


• Optare per una granularità più fine delle funzionalità esposte aumenta le possibilità di
riuso in altri contesti;
• Al crescere della finezza della granularità peggiorano però la scalabilità e la performance
dei servizi (soprattutto nel caso in cui la logica applicativa possa venir richiamata da
remoto)

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.

Questo paradigma prevede di individuare:


• un contratto a granularità più ampia che esponga una serie di servizi verso l’esterno (e
richiamabili dal front-end o da altre applicazioni locali e/o remote). Questo contratto
costituisce il session facade (il nome deriva dall’implementazione di questo componente
che storicamente era realizzato con un EJB di tipo Session);
• altri contratti a grana più fine, orientati al massimo riuso, ma senza problemi di
scalabilità perché esposti e richiamabili soltanto dall’implementazione del Session
Facade.

Indice

11. Utilizzare lo strumento corretto per il compito specifico

La piattaforma Java e la sua estensione enterprise mettono a disposizione degli analisti e


degli sviluppatori una serie di strumenti il cui uso deve essere attentamente considerato,
perché se da un lato possono rispondere in modo semplice e produttivo ad esigenze
specifiche, dall’altro possono diventare di difficile manutenzione se usati a sproposito.

Indice
Data

1. Inserire la logica di accesso ai dati in un layer specifico e configurabile

2. Accedere alle connessioni in modo da poter testare le classi al di fuori del container

3. ORM o SQL

4. Non disseminare l’sql nelle classi java

5. Indicare sempre i nomi delle colonne nelle insert e nelle select

6. Utilizzare PreparedStatement invece di Statement dinamici

1. Inserire la logica di accesso ai dati in un layer specifico e configurabile

E’ opinione diffusa che il dominio applicativo, la sua analisi e l’implementazione della


soluzione dovrebbero essere trasparenti rispetto allo strumento di persistenza dei dati, sia esso
un DB relazionale o altro.

L’accesso ai dati deve avvenire in modo più trasparente possibile rispetto al prodotto
utilizzato e in un layer specifico e configurabile.

I vantaggi ottenuti sono i seguenti:


• minori impatti nel cambiamento del prodotto DB Server o di una sua release;
• facilità di manutenzione ed evoluzione del codice;
• facilità di tuning della logica di accesso ai dati, che si trova ad essere isolata e circoscritta
e quindi facilmente modificabile;

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

In generale, le soluzioni ORM possono rendere più rapido lo sviluppo e la manutenzione di


un’applicazione che accede al DB, ma il loro uso va attentamente valutato rispetto alla
complessità nella progettazione e nel tuning. Vanno considerati anche eventuali costi in
termini di curva di apprendimento degli sviluppatori.

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

4. Non disseminare l’SQL nelle classi java

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

5. Indicare sempre i nomi delle colonne nelle insert e nelle select

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

6. Utilizzare PreparedStatement invece di Statement dinamici

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

Potrebbero piacerti anche