Comment éviter les indentations profondes? [fermé]


17

Quelles mesures et mesures puis-je prendre pour empêcher des indentations profondes dans mon code?


2
Beaucoup de gens parleront de refactoring ici. C'est peut-être trop demander, mais si vous avez publié du code (pas trop long) profondément indenté, et les gens pourraient vous montrer comment ils le remanieraient. Bien sûr, cela rend probablement la langue de la question spécifique alors ...
Paddyslacker

3
Utilisez une largeur d'onglet plus petite.
mipadi

6
Anti-motif de pointe de flèche . Google it, plein de conseils
NimChimpsky

2
Arrêtez d'utiliser python: D
back2dos

Il est temps de regarder votre logique de contrôle et de boucle. Votre code est probablement plus compliqué qu'il ne devrait l'être, et une re-conceptualisation du problème conduira à un code beaucoup plus court. Étudiez le bon code et apprenez les techniques.
Macneil

Réponses:


14

L'indentation profonde n'est généralement pas un problème si chaque fonction / méthode de votre programme fait une et une seule chose. Parfois, il peut être nécessaire d'imbriquer des conditions à quelques niveaux, mais je peux honnêtement dire que je n'ai écrit du code profondément en retrait qu'une poignée de fois en 12 ans et plus de codage.


26

La meilleure chose que vous puissiez faire est d'extraire des méthodes:

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

    // ....
}

2
Cela fonctionne également pour les ifconditions complexes . Poussé à l'extrême, vous vous retrouverez avec un pseudocode exécutable.
Alan Plum

Une autre meilleure chose que nous pouvons faire est de supprimer probablement les elseblocs inutiles .
sepehr

16

Vous pourriez peut-être envisager des clauses de garde ?

au lieu de

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

Faire

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 jamais vous en avez l'occasion, je vous recommanderais de lire Code Complete de Steve McConnell. Il a beaucoup de bons conseils sur ces sujets.

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

Pour plus d'informations sur les «clauses de garde», voir: https://sourcemaking.com/refactoring/replace-nested-conditional-with-guard-clauses


8

Inversez votre ifs.

Au lieu de:

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

J'écrirais:

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

De même pour if- elseblocs. Si elseest plus court / moins imbriqué, inversez-les.

Vérifier les valeurs des paramètres en un seul endroit

Vérifiez tous les paramètres pour les valeurs illégales dès que vous entrez dans votre méthode, puis poursuivez en sachant que vous êtes en sécurité. Cela rend le code plus lisible, mais cela vous évite également d'empiler des blocs conditionnels plus tard et de répartir ces contrôles dans tout le sous-programme.


1
Ce style a-t-il un nom spécifique?
Thomas Lauria

@ThomasLauria pas que je sache. Il sort juste tôt. IfLes s au début du code qui arrêtent le flux d'exécution en raison d'une condition non remplie sont également appelées clauses de sauvegarde , comme l'a souligné @JasonTuran. Et cela semble être aussi proche que possible d'avoir un nom distinct.
Konrad Morawski

Il y a quelques années, mon superviseur m'a dit que ce style était appelé "programmation linéaire", mais je pense que c'était un fantasme de lui;)
Thomas Lauria

4

En règle générale, j'ai vu que le code profondément indenté est généralement un code problématique. Si vous êtes confronté à ce problème, reculez et évaluez si votre fonction fait trop de choses.

En même temps, pour répondre à votre question, s'il y a un besoin d'indentation aussi profond, je vous suggère de le laisser là. Pour la simple raison que dans un tel code, l'indentation sera utile car il est susceptible d'être un très long morceau de code.


2

Décomposez les composants imbriqués (en particulier ceux qui sont répétés) en fonctions distinctes (c'est plus facile si votre langage prend en charge les fermetures) ou remplacez une série de boucles imbriquées par une récursivité.

Indiquez également deux espaces au lieu de quatre.


5
Une fois que vous êtes passé à l'étape de modification de la largeur de votre onglet, vous avez de
gros

Les onglets à deux espaces sont les choses difficiles ....
David Thornley

6
Changer le retrait n'est qu'un moyen de cacher le problème et non une solution
Murph

1

Je ne considère pas les retraits profonds comme un problème catégorique à supprimer (et je ne vois pas non plus la refactorisation comme la vraie réponse à tout).

En règle générale, au lieu des if imbriqués, j'aime écrire des instructions logiques:

if (foo && bar && baz) 

plutôt que

if foo 
 if bar
   if baz

Le problème est qu'il existe également des boucles for et while qui ne relèvent pas de cette règle.
Tamara Wijsman du

@ TomWij: Je n'essaie pas d'induire un impératif catégorique sur le style.
Paul Nathan

1
??? `` `` ``
Tamara Wijsman

1

Je ne le croyais pas moi-même, mais selon Code Complete, c'est un endroit approprié à utiliser break(si votre équipe est à bord). J'imagine que cela est plus acceptable avec les programmeurs C ++, où ils sont breakutilisés dans les switchinstructions qu'avec les programmeurs Delphi où ils breakne sont utilisés que lorsque vous n'avez pas envie d'écrire une whileboucle.


0

L'indentation est vraiment une idée à combattre, en effet. Ce que j'ai appris à faire, c'est de diviser la méthode en morceaux d'abord, puis d'utiliser une astuce étrange pour sauter tous les morceaux suivants si un morceau échoue. Voici un exemple :

Au lieu de :

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

J'écris actuellement:

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

Cela m'a paru étrange au début, mais depuis que j'utilise cela, le coût de la maintenance a été divisé par deux, et mon cerveau est plus frais à la fin de la journée.

En fait, le gain introduit par cette "technique" est que la complexité du code est vraiment divisée car le code est moins dense.

En lisant le code, vous n'avez rien à vous rappeler des conditions passées: si vous êtes à ce point X dans le code, les étapes précédentes sont passées et ont réussi.

Un autre avantage est que "la voie et la condition d'échappement" de tous ces "if-else" imbriqués sont simplifiées.


Pouvez-vous expliquer «le coût de la maintenance a été divisé par deux»? Comment sauriez-vous vraiment si, en cas d'arrêt de l'exécution?
Chris

J'ai fait quelques retouches. J'espère que je répondrai à vos questions ...
Pierre Watelet

2
Si vous voulez aller même simplement, vous avez une ligne goto error_handling.
Paul Nathan

C'est pas gentil. Désolé, mais ce n'est pas le cas. Là encore, je suis bizarre
Murph

3
au lieu d'émuler un essai, pourquoi ne pas en utiliser un directement?
Newtopian
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.