Quelle est la meilleure pratique pour vérifier plusieurs conditions, sans ordre particulier?
L'exemple en question doit vérifier quatre conditions distinctes, dans n'importe quel ordre, et ne pas afficher le message d'erreur correct.
Les exemples ci-dessous utilisent une syntaxe de type C.
Cette méthode n'est pas préférée car les raisons pour lesquelles la condition a échoué ne sont pas faciles à discerner.
if (A && B && C && D) {
// continue here...
} else {
return "A, B, C, or D failed";
}
Dans le passé, j'utilisais des instructions conditionnelles imbriquées, comme ça. Cela peut devenir vraiment déroutant.
if (A) {
if (B) {
if (C) {
if (D) {
// continue here...
} else {
return "D failed"
}
} else {
return "C failed";
}
} else {
return "B failed";
}
} else {
return "A failed";
}
C'est la méthode actuelle que j'utilise, que j'aime appeler fail-early. Dès qu'une "mauvaise" condition est rencontrée, elle revient.
if (!A) {
return "A failed";
}
if (!B) {
return "B failed";
}
if (!B) {
return "C failed";
}
if (!D) {
return "D failed";
}
// continue here...
Une dernière approche à laquelle je peux penser est une sorte de collection d'erreurs. Si les conditions à tester sont complètement distinctes, on peut vouloir utiliser cette approche.
String errors = "";
if (!A) {
errors += "A failed\n";
}
if (!B) {
errors += "B failed\n";
}
if (!C) {
errors += "C failed\n";
}
if (!D) {
errors += "D failed\n";
}
if (errors.isEmpty()) {
// continue here...
} else {
return errors;
}
Quelles sont les meilleures pratiques pour vérifier plusieurs conditions? En termes d'attentes, il se comporte idéalement comme l'exemple 4, où les détails de tous les échecs sont retournés.
La réponse est ... cela dépend.
Est-ce que l'un des A, B, C ou D l'empêche de fonctionner? La vérification de A et l'échec rendent-il la vérification de B, C ou D impossible ou redondante? Est-il utile de signaler la collection d'erreurs signalées ou simplement la première détectée?
Chacune des options présentées a son utilité dans la situation appropriée. Il n'y a pas d'approche unique de gestion des erreurs pour les gouverner tous.
Cela dépend vraiment du type d'informations que vous souhaitez récupérer de la fonction. Décomposons ce que chaque option vous offre:
Vous ne vous souciez pas de la condition qui échoue, vous voulez seulement savoir si elles réussissent ou non.
Clairement dégagé. Formatage et lisibilité très mauvais en raison de l'imbrication du code. Fait la même chose que # 3 mais plus laid.
Vous apprenez à connaître la première condition qui a échoué.
Vous apprenez à connaître chaque condition qui a échoué.
Maintenant, c'est à vous de juger quelle option est la meilleure, selon le contexte et les informations dont vous avez vraiment besoin.
La réponse dépend énormément de la langue que vous utilisez et de ce que vous allez faire à la suite des erreurs.
Par exemple, dans Scala, et en supposant que je veux signaler toutes les erreurs afin qu'elles puissent toutes être corrigées en même temps, je ferais probablement quelque chose comme
val (yes, no) = List(
(A, "A failed"),
(B, "B failed"),
(C, "C failed"),
(D, "D failed")
).partition(_._1)
if (!no.isEmpty) Some(no.map(_._2)) else None
où je regroupe d'abord mes conditions et mes messages d'erreur, puis les trie en deux groupes - les succès et les échecs - et renvoie ces messages d'erreur s'il y avait quelque chose, et sinon renvoie une valeur sentinelle disant - dans ce cas - que tout va bien.
Mais cela repose de manière critique sur la capacité de Scala à regrouper, cartographier et manipuler rapidement les collections et les conteneurs. En Java, j'écrirais exactement le même code dans le plus détaillé (et moins pratique à vérifier, car je dois maintenant interroger errors.size()
pour savoir si j'ai échoué):
ArrayList<String> errors = new ArrayList<String>();
if (!A) errors.add("A failed");
if (!B) errors.add("B failed");
if (!C) errors.add("C failed");
if (!D) errors.add("D failed");
return errors;
Si nous n'avons besoin que de la première erreur, en Java je ferais un échec rapide en Scala je pourrais
List(A,B,C,D).zipWithIndex.find(!_._1).foreach{ x => return x._2 }
en supposant que j'étais d'accord avec le numéro de l'article qui a mal tourné en tant que code de retour.
Donc, la réponse est vraiment: vous avez les différents styles importants, mais comment les implémenter le plus efficacement/le moins douloureusement dépendra beaucoup de vos outils.