J'ai entendu dire qu'il est recommandé de valider les arguments des méthodes publiques:
- Doit-on vérifier null s'il n'attend pas null?
- Une méthode doit-elle valider ses paramètres?
- MSDN - CA1062: Validez les arguments des méthodes publiques (j'ai un arrière-plan .NET mais la question n'est pas spécifique à C #)
La motivation est compréhensible. Si un module est utilisé de manière incorrecte, nous voulons lever immédiatement une exception au lieu de tout comportement imprévisible.
Ce qui me dérange, c'est que les mauvais arguments ne sont pas la seule erreur qui peut être faite lors de l'utilisation d'un module. Voici quelques scénarios d'erreur dans lesquels nous devons ajouter une logique de vérification si nous suivons les recommandations et ne voulons pas d'escalade d'erreur:
- Appel entrant - arguments inattendus
- Appel entrant - le module est dans un mauvais état
- Appel externe - résultats inattendus renvoyés
- Appel externe - effets secondaires inattendus (double entrée vers un module appelant, rupture d'autres états de dépendances)
J'ai essayé de prendre en compte toutes ces conditions et d'écrire un module simple avec une méthode (désolé, les gars non-C #):
public sealed class Room
{
private readonly IDoorFactory _doorFactory;
private bool _entered;
private IDoor _door;
public Room(IDoorFactory doorFactory)
{
if (doorFactory == null)
throw new ArgumentNullException("doorFactory");
_doorFactory = doorFactory;
}
public void Open()
{
if (_door != null)
throw new InvalidOperationException("Room is already opened");
if (_entered)
throw new InvalidOperationException("Double entry is not allowed");
_entered = true;
_door = _doorFactory.Create();
if (_door == null)
throw new IncompatibleDependencyException("doorFactory");
_door.Open();
_entered = false;
}
}
Maintenant c'est sûr =)
C'est assez flippant. Mais imaginez à quel point il peut être effrayant dans un vrai module avec des dizaines de méthodes, un état complexe et beaucoup d'appels externes (salut, amateurs d'injection de dépendances!). Notez que si vous appelez un module dont le comportement peut être remplacé (classe non scellée en C #), vous effectuez un appel externe et les conséquences ne sont pas prévisibles au niveau de la portée de l'appelant.
En résumé, quelle est la bonne façon et pourquoi? Si vous pouvez choisir parmi les options ci-dessous, répondez aux questions supplémentaires, s'il vous plaît.
Vérifiez l'utilisation complète du module. Avons-nous besoin de tests unitaires? Existe-t-il des exemples d'un tel code? L'injection de dépendances doit-elle être limitée dans son utilisation (car elle entraînera davantage de logique de vérification)? N'est-il pas pratique de déplacer ces vérifications au moment du débogage (ne pas inclure dans la version)?
Vérifiez uniquement les arguments. D'après mon expérience, la vérification des arguments - en particulier la vérification des valeurs nulles - est la vérification la moins efficace, car l'erreur d'argument conduit rarement à des erreurs complexes et à des escalades d'erreurs. La plupart du temps, vous obtenez un NullReferenceException
à la ligne suivante. Alors pourquoi les vérifications d'arguments sont-elles si spéciales?
Ne vérifiez pas l'utilisation du module. C'est une opinion assez impopulaire, pouvez-vous expliquer pourquoi?