Uploaded by Alessandro Zamboni

Refactoring checkRegole face di upload

advertisement
REFACTORING CHECKREGOLE FASE DI
UPLOAD
Code refactoring: cos’è e perché va fatto
Il code refactoring è un processo di ristrutturazione del codice il quale principale scopo è quello di migliorare la
leggibilità, prestazioni e manutenibilità nel tempo.
Programmazione funzionale
Paradigma di programmazione in cui il flusso di esecuzione del programma assume la forma di una serie di valutazioni
di funzioni matematiche. (Wikipedia)
Pone maggior accento sulle funzioni rispetto ai paradigmi procedurali e imperativi.
Esempio:
Approccio imperativo
List<Persona> femmine = new ArrayList<>();
for (Persona persona: persone) {
if (FEMMINA.equals(persona.getGenere())) {
femmine.add(persona);
}
}
for (Persona femmina : femmine) {
System.out.prinln(femmina);
}
Approccio dichiarativo
persone.stream().
.filter(persona -> FEMMINA.equals(persona.getGenere()))
.collect.(Collectors.toList())
.forEach(System.out::println);
La programmazione funzionale è una sorta di sottoinsieme della programmazione dichiarativa.
Espressione Lambda
Un’espressione lambda è una funzione anonima. I parametri in ingresso sono a sinistra del segno freccia, e il corpo
della funzione è a destra, è simile ad un metodo.
Esempi:
s -> System.out.println("Ciao "+ s);
(x, y) -> x + y;
Cosa è stato fatto in questo caso
Prima del refactoring avevamo questa situazione:
REFACTORING CHECKREGOLE FASE DI UPLOAD
1
protected EsitoUpload checkRegole(CeStagingUpload ceStagingUpload) {
LOG.info("START Check regole - proess CeStagingUpload con idStagingUpload {} ", ceStagingUpload.getIdStagingUpload());
EsitoUpload esitoUpload = new EsitoUpload();
esitoUpload.setEsito(ESITO_OK);
esitoUpload.setNotaEsito("");
LOG.info("esitoUpload {} ", esitoUpload.toString());
esitoUpload = checkCodPortafoglio(ceStagingUpload, esitoUpload);
LOG.info("esitoUpload checkCodPortafoglio {} ", esitoUpload.toString());
if (ESITO_KO.equalsIgnoreCase(esitoUpload.getEsito())) {
return esitoUpload;
}
esitoUpload = checkCambioIfrs(ceStagingUpload, esitoUpload);
LOG.info("esitoUpload checkCambioIfrs{} ", esitoUpload.toString());
if (ESITO_KO.equalsIgnoreCase(esitoUpload.getEsito())) {
return esitoUpload;
}
esitoUpload = checkRapportoFittizio(ceStagingUpload, esitoUpload);
LOG.info("esitoUpload checkRapportoFittizio{} ", esitoUpload.toString());
if (ESITO_KO.equalsIgnoreCase(esitoUpload.getEsito())) {
return esitoUpload;
}
... per altre 15 regole da applicare al nostro oggetto "esitoUpload"
}
Siamo quindi passati da un approccio imperativo ad un approccio funzionale nel seguente modo:
Ho dichiarato come attributi di classe le regole e l’esito dell’upload
private EsitoUpload esitoUpload = new EsitoUpload();
private Supplier<Stream<Function>> regole = () -> Stream.of(
ceStagingUpload -> this.checkCodPortafoglio((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkCambioIfrs((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkRapportoFittizio((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkFase((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkSingleName((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkMotivazione((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkAbi((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkIfrs5Chiuso((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkIfrs5ApertoIfrs9((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.getCeHermioneAgg((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkFilialeRapporto((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkNsgWithoutFiliale((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.getPortafogliAttiviWithFilialeRapporto((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.getPortafogliAttiviWithNsg((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkRapportoNotExists((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkFlagForzatura((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkProgRichiesta1((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkProgRichiesta2((CeStagingUpload) ceStagingUpload),
ceStagingUpload -> this.checkFilialeRapportoIfrs9((CeStagingUpload) ceStagingUpload)
);
}
Analizziamo le classi utilizzate:
Stream: rappresenta una sequenza di elementi sui cui eseguire operazioni intermedie o terminali. Le terminali
generano un risultato di un determinato tipo mentre le intermedie un nuovo Stream su cui invocare altre operazioni
dando vita ad una catena di chiamate a metodi.
Supplier: rappresenta un fornitore di risultati. Espone un solo metodo (essendo un’interfaccia funzionale) “get()”
che produce un risultato senza accettare input. Il suo funzionamento in questo caso ci torna utile in fase di test
perché riutilizzando più di una volta lo stream dichiarato sopra ci lancia una IllegalStateException: “stream has
already been operated upon or closed”. Questo avviene perché lo stream in Java 8 alla fine dell’ultima operazione
REFACTORING CHECKREGOLE FASE DI UPLOAD
2
viene chiuso e quindi non riutilizzabile. La classe Supplier ci risolve il problema perché utilizzando il metodo get()
ogni volta restituirà un nuovo stream.
Function: rappresenta una funzione che prende in input un solo argomento e produce un risultato. Il suo metodo
funzionale è apply(T input) applica la funzione all’argomento dato in input.
Corpo del metodo dopo il refactoring:
protected EsitoUpload checkRegole(CeStagingUpload ceStagingUpload) {
LOG.info("START Check regole - proess CeStagingUpload con idStagingUpload {} ", ceStagingUpload.getIdStagingUpload());
this.esitoUpload.setEsito(ESITO_OK);
this.esitoUpload.setNotaEsito("");
LOG.info("esitoUpload {} ", this.esitoUpload.toString());
this.regole.get().anyMatch(regola -> {
regola.apply(ceStagingUpload);
return ESITO_KO.equals(this.esitoUpload.getEsito());
});
return this.esitoUpload;
}
Analizziamo alcuni metodi utilizzato:
get(), metodo dell’interfaccia funzionale Supplier, spiegato nell’analisi precedente.
anyMatch(Predicate predicate), metodo della classe Stream che ritorna true se qualche elemento dello stream
corrisponde al predicato fornito.
apply(T input), analizzato prima, esegue la Function dello Stream dichiarato prima come attributo della classe,
utilizza come input l’oggetto preso come parametro dal metodo checkRegole.
Conclusione:
Abbiamo visto come un approccio funzionale-dichiarativo può semplificare notevolmente la struttura del codice,
rendendolo decisamente più leggibile, più manutenibile, più efficiente e
facilmente scalabile.
REFACTORING CHECKREGOLE FASE DI UPLOAD
3
Download