Quali misure e misure posso adottare per evitare profonde indentazioni nel mio codice?
Quali misure e misure posso adottare per evitare profonde indentazioni nel mio codice?
Il rientro profondo è di solito non un problema se ogni funzione / metodo nel tuo programma fa una sola cosa. Occasionalmente, potrebbe essere necessario per nidificare condizionali di qualche livello, ma posso onestamente dire che ho scritto solo codice profondamente rientrato una manciata di volte in 12+ anni di programmazione.
La cosa migliore che puoi fare è estrarre i metodi:
int Step1(int state)
{
if (state == 100)
{
return Step2(state);
}
else
{
return Step3(state);
}
}
int Step2(int state)
{
if (state != 100)
{
throw new InvalidStateException(2, state);
}
// ....
}
Forse potresti prendere in considerazione clausole di protezione ?
invece di
public void DoSomething(int value){
if (someCondition){
if(someOtherCondition){
if(yetAnotherCondition){
//Finally execute some code
}
}
}
}
Do
public void DoSomething(int value){
if(!(someCondition && someOtherCondition && yetAnotherCondition)){
return;
//Maybe throw exception if all preconditions must be true
}
//All preconditions are safe execute code
}
Se mai ne hai la possibilità ti consiglio di leggere Code Complete di Steve McConnell. Ha molti ottimi consigli su questi argomenti.
Per ulteriori informazioni sulle "clausole di guardia" vedi: link
Inverti il tuo if
s.
Invece di:
if (foo != null)
{
something;
something;
if (x)
{
something;
}
something;
}
else
{
boohoo;
}
Scriverò:
if (foo == null)
{
boohoo;
return;
}
something;
something;
if (x)
{
something;
}
something;
Lo stesso vale per if
- else
blocchi. Se else
è più breve / meno nidificato, quindi ripristinali.
Controlla i valori dei parametri in un unico punto
Controlla tutti i parametri per i valori non validi non appena inserisci il tuo metodo, quindi procedi sapendo che sei al sicuro. Rende il codice più leggibile, ma ti consente anche di accumulare blocchi condizionali in un secondo momento e di diffondere questi controlli su tutta la subroutine.
In genere, ho visto che il codice profondamente rientrato è in genere un codice problematico. Se stai affrontando questo problema, fai un passo indietro e valuta se la tua funzione sta facendo troppe cose.
Allo stesso tempo, per rispondere alla tua domanda, se c'è un bisogno di indentazione così profonda, ti suggerirei di lasciarlo lì. Per la semplice ragione che in tale codice, l'indentazione aiuterà poiché è probabile che sia un pezzo di codice molto lungo.
Rompi i componenti nidificati (specialmente quelli ripetuti) in funzioni separate (questo è più facile se la tua lingua supporta le chiusure) o sostituisci una serie di cicli annidati con una ricorsione.
Inoltre, induisci due spazi anziché quattro.
Non vedo rientri profondi come un problema categoriale da rimuovere (né vedo refactoring come la vera risposta per tutto).
Tipicamente invece di if annidati, mi piace scrivere affermazioni logiche:
if (foo && bar && baz)
anziché
if foo
if bar
if baz
Non ci credevo, ma secondo Code Complete questo è un posto appropriato per usare break
(se la tua squadra è a bordo). Immagino che questo sia più accettabile con i programmatori C ++, dove break
è usato in switch
statement rispetto ai programmatori Delphi in cui break
è usato solo quando non hai voglia di scrivere un ciclo while
.
L'indentazione è davvero un modo per combattere, anzi. Quello che ho imparato a fare è dividere prima il metodo in pezzi, poi usare un trucco strano per saltare ogni pezzo successivo se un pezzo fallisce. Ecco un esempio:
Invece di:
{if (networkCardIsOn() == true)
{if (PingToServer() == true)
{if (AccesLogin(login,pass) == true)
{if (nextCondition == true)
...
}
}
}
Attualmente scrivo:
{vbContinue = true;
if (vbContinue) {
vbContinue = networkCardIsOn();
if (vbContinue == false) {
code to Handle This Error();
}
}
if (vbContinue) {
vbContinue = PingToServer();
if (vbContinue == false) {
code to HandleThisError2();
}
}
if (vbContinue) {
vbContinue = AccesLogin(login,pass);
if (vbContinue == false) {
HandleThisErrorToo();
}
}
...
Questo mi è sembrato strano all'inizio, ma dal momento che lo uso, i costi di manutenzione sono stati divisi per metà e il mio cervello è più fresco alla fine della giornata.
In effetti, il guadagno introdotto da questa "tecnica" è che la complessità del codice è realmente divisa perché il codice è meno denso.
Durante la lettura del codice, non devi ricordare nulla delle condizioni passate: se sei a quel punto X nel codice, i passaggi precedenti vengono passati e sono riusciti.
Un altro vantaggio è che "percorso e condizione di fuga" da tutti quelli annidati "if-else" è semplificato.
Leggi altre domande sui tag code-quality indentation