[Java] L'histoire d'une déclaration de commutation vraiment effrayante
introduction
Il y a longtemps, j'ai résumé l'histoire lorsque j'ai raté la déclaration de commutation.
C'est une histoire très embarrassante, mais j'ai rédigé un article pour éviter que des accidents similaires ne se reproduisent.
1. État initial
- Comme TestServlet.java ci-dessous, l'instruction switch a été utilisée dans le but d'allouer le traitement en fonction de la valeur du paramètre de requête.
- En fait, le nombre de branches conditionnelles était proche de 10, j'ai donc adopté l'instruction switch au lieu de l'instruction if.
TestServlet.java
@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Paramètre de demande"id"Obtenez la valeur de.
int id = Integer.parseInt(request.getParameter("id"));
// "id"Les processus sont distribués en fonction de la valeur de.
switch(id) {
case 1:
//Processus 1-A
break;
case 2:
//Processus 2-A
break;
case 3:
//Processus 3-A
break;
default:
//Traitement par défaut
break;
}
...
}
}
2. Rénovation grâce à des fonctions supplémentaires
- Étant donné que le traitement dans l'instruction switch a augmenté avec l'ajout de fonctions, l'instruction switch est devenue gonflée dans son ensemble, comme indiqué ci-dessous.
- À ce stade, en écrivant et en effaçant le code à plusieurs reprises, il semble que ** j'ai accidentellement effacé une pause **.
- Je n'ai pas remarqué que j'avais supprimé la pause parce que l'instruction switch était gonflée ...
- ** Au fait, la suppression de break ne provoque pas d'erreur de compilation! ** **
TestServlet.java
@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Paramètre de demande"id"Obtenez la valeur de.
int id = Integer.parseInt(request.getParameter("id"));
// "id"Les processus sont distribués en fonction de la valeur de.
switch(id) {
case 1:
//Processus 1-A
//Processus 1-B
//Processus 1-C
break;
case 2:
//Processus 2-A
//Processus 2-B
//Processus 3-C (★ J'ai effacé la pause immédiatement après cela...)
case 3:
//Processus 3-A
//Processus 3-B
//Processus 3-C
break;
default:
//Traitement par défaut
break;
}
...
}
}
3. L'accident s'est produit
- Quelques temps après avoir publié le code avec des fonctions supplémentaires, un utilisateur a demandé que "le système se comporte étrangement".
- J'aurais dû passer tous les tests du test unitaire au test du système, mais quand je l'ai examiné en détail, j'ai trouvé que le résultat du traitement était étrange.
Valeur de l'identifiant du paramètre |
Résultat de traitement attendu |
Résultat réel du traitement |
1 |
X |
X |
2 |
Y |
Pas Y |
3 |
Z |
Z |
Autre |
α |
α |
4. Raison de l'accident
- Au moment où break a disparu de l'instruction switch, une ** "fallthrough" ** totalement involontaire s'est produite.
- Comme mentionné ci-dessus, la disparition du break ne provoque pas d'erreur de compilation, donc si vous ne lisez pas attentivement le code, vous le manquerez ...
- La raison pour laquelle il a réussi le test est que "le test ne couvrait pas le branchement conditionnel".
- Cependant, créer un test qui couvre toutes les branches conditionnelles peut être une tâche ardue ...
5. Que faire après l'accident
- Je ne pense pas que ce soit la meilleure réponse, mais j'ai dit "n'utilisez pas l'instruction switch inutilement".
- Puisque la cause de cet accident est "une instruction switch qui est devenue gonflée et qui a une mauvaise visibilité", j'ai établi ma règle selon laquelle "lors de l'utilisation d'une instruction switch, on suppose que toute l'instruction switch est mince et que la visibilité est bonne".
- En premier lieu, le "code avec une mauvaise visibilité" lui-même est un problème, mais pour éviter les "chutes involontaires", j'ai pensé qu'il était plus sûr de ne pas utiliser l'instruction switch avec négligence. (Peut-être "allergie de déclaration de commutation" ...)
- J'ai essayé de réfléchir plus que jamais avant de faire un test unitaire.
- Même avec des modifications mineures, nous en sommes venus à concevoir des moyens d'éliminer les modèles de test manquants, comme l'utilisation de la table de décision pour identifier les modèles de test. (Il semble que vous ayez une conscience trop basse ...)
- A cette époque, nous avons commencé à utiliser des indicateurs objectifs tels que la vérification du taux de couverture au niveau des agences avec Cobertura.
URL de référence