it-swarm-es.com

¿Cómo prevenir hendiduras profundas?

¿Qué pasos y medidas puedo tomar para evitar hendiduras profundas en mi código?

17
Tamara Wijsman

La sangría profunda es generalmente no es un problema si cada función/método en su programa hace una y solo una cosa. Ocasionalmente, podría ser necesario anidar condicionales a unos pocos niveles de profundidad, pero honestamente puedo decir que solo he escrito código con sangría profunda un puñado de veces en más de 12 años de codificación.

14
Chinmay Kanchi

Lo mejor que puedes hacer es extraer métodos:

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);
    }

    // ....
}
26
ChaosPandion

¿Quizás podría considerar cláusulas de protección ?

en vez de

public void DoSomething(int value){
    if (someCondition){
           if(someOtherCondition){
                if(yetAnotherCondition){
                       //Finally execute some code
                }
           }
    }
} 

Hacer

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
}

Si alguna vez tienes la oportunidad, te recomiendo que leas Code Complete de Steve McConnell. Tiene muchos buenos consejos sobre estos temas.

http://www.Amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=pd_sim_b_6

Para obtener más información sobre las "cláusulas de protección", consulte: https://sourcemaking.com/refactoring/replace-nested-conditional-with-guard-clauses

16
Jason Turan

Invierta sus ifs.

En vez de:

if (foo != null)
{
    something;
    something;
    if (x)
    {        
       something;
    }
    something;
}
else
{
    boohoo;
}

Yo escribiría:

if (foo == null)
{
    boohoo;
    return;
}
something;
something;
if (x)
{        
   something;
}
something;

Lo mismo se aplica a los bloques if-else. Si else es más corto/menos anidado, revertirlos.

Verifique los valores de los parámetros en un lugar

Verifique todos los parámetros de valores ilegales tan pronto como ingrese su método, luego continúe sabiendo que está seguro. Crea un código más legible, pero también le ahorra acumular bloques condicionales más adelante y distribuir estas comprobaciones por toda la subrutina.

8
Konrad Morawski

Por lo general, he visto que el código con sangría profunda suele ser un código problemático. Si se enfrenta a este problema, retroceda y evalúe si su función está haciendo demasiadas cosas.

Al mismo tiempo, para responder a su pregunta, si existe la necesidad de una sangría tan profunda, sugeriría que la deje allí. Por la sencilla razón de que en dicho código, la sangría ayudará, ya que es probable que sea un código muy largo.

4
Vaibhav

Divida los componentes anidados (especialmente los repetidos) en funciones separadas (esto es más fácil si su idioma admite cierres) o reemplace una serie de bucles anidados con una recursividad.

Además, sangra dos espacios en lugar de cuatro.

2
Hoa Long Tam

Yo no lo creía, pero de acuerdo con Code Complete, este es un lugar apropiado para usar break (si su equipo está a bordo). Sin embargo, me imagino que esto es más aceptable con los programadores de C++, donde break se usa en las declaraciones switch que con los programadores de Delphi donde break solo se usa cuando no tiene ganas de escribir un bucle while.

1
Peter Turner

No veo las hendiduras profundas como un problema categórico a eliminar (ni veo la refactorización como la verdadera respuesta para todo).

Por lo general, en lugar de ifs anidados, me gusta escribir declaraciones lógicas:

if (foo && bar && baz) 

más bien que

if foo 
 if bar
   if baz
1
Paul Nathan

La sangría es realmente un pensamiento para luchar, de hecho. Lo que aprendí a hacer es dividir el método en partes primero, luego usar un truco extraño para omitir cada una de las siguientes piezas si una pieza falla. Aquí hay un ejemplo :

En vez de :

 {if (networkCardIsOn() == true)
     {if (PingToServer() == true)
        {if (AccesLogin(login,pass) == true)
             {if (nextCondition == true)
                ...
         }
     }
 }

Actualmente escribo:

 {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();
       } 
 }
 ...

Al principio, esto me parece extraño, pero desde que lo uso, el costo de mantenimiento se ha dividido a la mitad, y mi cerebro está más fresco al final del día.

De hecho, la ganancia introducida por esta "técnica" es que la complejidad del código está realmente dividida porque el código es menos denso.

Mientras lee el código, no tiene que recordar nada acerca de las condiciones pasadas: si está en ese punto X en el código, los pasos anteriores se pasan y han tenido éxito.

Otra ganancia es que se simplifica la "ruta de escape y la condición" de todos los "if-else" anidados.

0
Pierre Watelet