ti-enxame.com

Como evitar recuos profundos?

Que etapas e medidas posso tomar para evitar recuos profundos no meu código?

17
Tamara Wijsman

O recuo profundo é geralmente não é um problema se todas as funções/métodos do seu programa fizerem uma e apenas uma coisa. Ocasionalmente, pode é necessário aninhar condicionais com alguns níveis de profundidade, mas posso dizer honestamente que só escrevi código recuado profundamente algumas vezes em mais de 12 anos de codificação.

14
Chinmay Kanchi

A melhor coisa que você pode fazer é extrair 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

Talvez você possa considerar cláusulas de guarda ?

ao invés de

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

Faz

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 você tiver uma chance, eu recomendo que você leia Code Complete, de Steve McConnell. Ele tem muitos conselhos excelentes sobre esses tópicos.

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

Para obter mais informações sobre "cláusulas de guarda", consulte: https://sourcemaking.com/refactoring/replace-nested-conditional-with-guard-clauses

16
Jason Turan

Inverta seus ifs.

Ao invés de:

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

Eu escreveria:

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

O mesmo se aplica aos blocos if-else. Se else for mais curto/menos aninhado, então reverta-os.

Verifique os valores dos parâmetros em um só lugar

Verifique todos os parâmetros em busca de valores ilegais assim que você inserir seu método e continue sabendo que está seguro. Isso cria um código mais legível, mas também evita que você empilhe blocos condicionais posteriormente e espalhe essas verificações por toda a sub-rotina.

8
Konrad Morawski

Normalmente, vi que o código profundamente recuado é geralmente um código problemático. Se você estiver enfrentando esse problema, dê um passo atrás e avalie se sua função está fazendo muitas coisas.

Ao mesmo tempo, para responder à sua pergunta, se houver uma necessidade de indentação tão profunda, sugiro que você a deixe lá. Pela simples razão de que, em tal código, o recuo ajudará, pois é provável que seja um pedaço de código muito longo.

4
Vaibhav

Divida os componentes aninhados (especialmente os repetidos) em funções separadas (isso é mais fácil se o seu idioma suportar fechamentos) ou substitua uma série de loops aninhados por uma recursão.

Recue também dois espaços em vez de quatro.

2
Hoa Long Tam

Eu não acreditei, mas de acordo com o Code Complete, este é um local apropriado para usar break (se sua equipe estiver a bordo). Eu imagino que isso seja mais aceitável com os programadores de C++, onde break usado nas instruções switch do que com os programadores Delphi onde break é usado apenas quando você não sinta vontade de escrever um loop while.

1
Peter Turner

Não vejo indentações profundas como um problema categórico a ser removido (nem vejo a refatoração como a verdadeira resposta para tudo).

Normalmente, em vez de ifs aninhados, gosto de escrever instruções lógicas:

if (foo && bar && baz) 

ao invés de

if foo 
 if bar
   if baz
1
Paul Nathan

Recuo é realmente um pensamento para lutar, de fato. O que eu aprendi a fazer é dividir o método em partes primeiro e depois usar um truque estranho para pular todas as partes seguintes, se uma delas falhar. Aqui está um exemplo :

Ao invés de :

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

Atualmente, escrevo:

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

Isso me pareceu estranho no começo, mas desde que eu uso isso, o custo de manutenção foi dividido pela metade e meu cérebro fica mais frio no final do dia.

De fato, o ganho introduzido por essa "técnica" é que a complexidade do código é realmente dividida porque o código é menos denso.

Ao ler o código, você não precisa se lembrar de nada sobre as condições passadas: se você estiver nesse ponto X do código, as etapas anteriores são aprovadas e foram bem-sucedidas.

Outro ganho é que o "caminho e condição de escape" de todos os aninhados "if-else" é simplificado.

0
Pierre Watelet