Al momento abbiamo una discussione delicata in azienda che tocca un paio di vecchie discussioni basate sull'opinione pubblica. Tuttavia, vorrei discutere il caso in questo forum per stabilire alcune linee guida ragionevoli sul codice. Supponiamo di avere le seguenti due classi di classi legacy non modificabili:
public class SomeValue {
private String value;
public SomeValue(final String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
public class SomeCondition {
private SomeValue a;
private SomeValue b;
public SomeCondition(final SomeValue a, final SomeValue b) {
this.a = a;
this.b = b;
}
public boolean isA() {
return a != null;
}
public boolean isB() {
return b != null;
}
public String getAOrBValue() {
if (isA()) {
return a.getValue();
}
if (isB()) {
return b.getValue();
}
return null;
}
}
Ora, in discussione è lo stile migliore per un metodo che controlla se qualcuno di aob è impostato e restituisce il suo valore (prioritizzando a). Le due versioni in offerta sono quelle:
Versione 1:
protected String getValue(final List<SomeCondition> conditions) {
if (isNotEmpty(conditions)) {
for (SomeConditions conditions : condition) {
if (condition.isA())) {
return a.getValue();
}
if (condition.isB()) {
return b.getValue();
}
}
}
return "default";
}
I critici di questa versione dicono che i ritorni all'interno di più istruzioni if contenute in un ciclo for non solo nascondono istruzioni else ma anche un'istruzione break. Se si tentasse di ottenere un ritorno alla fine del metodo, si vedrebbe tutta questa complessità nascosta che sicuramente costringerebbe uno al refactoring. Se si dovesse risolvere il problema con questo metodo, si sarebbe in guai seri.
Versione 2:
protected String getValue(final List<SomeCondition> conditions) {
return conditions
.stream()
.map(this::getAOrBValue)
.filter(match -> match != null)
.findFirst()
.orElse("default");
}
I critici di questa versione dicono che questo codice è difficile da leggere poiché utilizza in modo errato l'API di java streaming per gestire qualcosa che di solito sarebbe coperto da semplici istruzioni for e if. Inoltre, l'algoritmo di filtraggio è più difficile da capire poiché è distribuito su due classi.
Sono consapevole che parte di questa discussione è basata sull'opinione pubblica. Tuttavia, ritengo che esistano alcune convenzioni di programmazione ben consolidate che potrebbero aiutarci, decidere quale dei due stili vogliamo rendere ufficiali nelle nostre linee guida sul codice. Qualcuno può far luce sull'argomento?