Quelles mesures et mesures puis-je prendre pour empêcher des indentations profondes dans mon code?
Quelles mesures et mesures puis-je prendre pour empêcher des indentations profondes dans mon code?
Réponses:
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.
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);
}
// ....
}
if
conditions complexes . Poussé à l'extrême, vous vous retrouverez avec un pseudocode exécutable.
else
blocs inutiles .
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
Inversez votre if
s.
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
- else
blocs. Si else
est 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.
If
Les 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.
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.
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.
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
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 break
utilisés dans les switch
instructions qu'avec les programmeurs Delphi où ils break
ne sont utilisés que lorsque vous n'avez pas envie d'écrire une while
boucle.
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.