64 votes

Dont le design est plus préférable : test-créer, essayez-créer, créer des prises accessoires ?

Imaginons qu'il y est une opération qui crée un utilisateur. Cette opération peut échouer si spécifié e-mail ou nom d'utilisateur existe. Si elle a échoué, il est nécessaire de savoir exactement pourquoi. Il existe trois approches de le faire comme je le vois et je me demande s'il est un gagnant clair.

Donc, voici une classe utilisateur:

class User
{
    public string Email { get; set; }
    public string UserName { get; set; }
}

Et il y a 3 façons d'accomplir l'opération de création:

Test-Créer

if (UserExists(user)) act on user exists error;
if (UsernameExists(user)) act on username exists error;
CreateUser(user);

UserExists et UsernameExists faire la demande au serveur de base de données pour faire une validation. Ces appels sont de nouveau répété dans CreateUser pour s'assurer de l'API est utilisé correctement. En cas de validation a échoué, je jette ArgumentOutOfRangeException dans les deux cas. Il y a donc un gain de performance.

Essayez-Créer

enum CreateUserResultCode
{
    Success,
    UserAlreadyExists,
    UsernameAlreadyExists
}

if (!TryCreate(user, out resultCode))
{
    switch(resultCode)
    {
        case UserAlreadyExists: act on user exists error;
        case UsernameAlreadyExists: act on username exists error;
    }
}

Ce modèle effectue la validation qu'une seule fois, mais nous avons recours à l'utilisation de la dite codes d'erreur qui n'est pas considéré comme une bonne pratique.

Créer Des Captures

try
{
    CreateUser(user);
}
catch(UserExistsException)
{
    act on user exists error;
}
catch(UsernameExistsException)
{
    act on username exists error;
}

Je n'utilise pas de codes d'erreur ici, mais maintenant, je dois créer une classe d'exception pour tous les cas. C'est plus ou moins comment les exceptions sont censé être utilisé, mais je me demande si la création d'une autre exception au lieu d'enum entrée en vaut la peine.

Donc, nous avons un gagnant clair ou c'est plus une question de goût?

80voto

Reed Copsey Points 315315

Donc, nous avons un gagnant clair ou c'est plus une question de goût?

La première option a un défaut fondamental - il ne va jamais être thread-safe ou le coffre si CreateUser s'appuie sur des ressources externes, et d'autres implémentations peuvent créer entre vos tests. En général, j'ai tendance à éviter ce "modèle" à cause de cela.

Comme pour les deux autres options - il s'agit vraiment de savoir si l'échec est prévu de se produire. Si CreateUser serait attendu à échouer sur un peu normal de base, l'Essayer* le modèle est ma préférence, à l'aide d'exceptions devient essentiellement l'utilisation d'exceptions pour le contrôle de flux.

Si la panne serait vraiment un cas exceptionnel, alors exceptions serait plus compréhensible.

37voto

Mehrdad Points 70493

Test-créer peut causer des conditions de course, ce n’est pas une bonne idée. Il fonctionne probablement aussi extra.

Try-créer est bon si vous pensez que les erreurs de faire partie du flux de code normal (par exemple dans le cas de l’entrée d’utilisateur).

Créer-hic, c’est bon si des erreurs sont vraiment exceptionnels (si vous n’êtes pas inquiet de la performance).

9voto

recursive Points 34729

C'est un peu subjectif, mais il y a quelques béton les avantages et les inconvénients qui mérite d'être souligné.

Un inconvénient de l'essai-créer approche est la condition de la course. Si deux clients à tenter de créer le même utilisateur à environ le même temps, il peut être possible pour eux à la fois à passer les tests, et ensuite tenter de créer le même utilisateur.

Entre Essayer de Créer et de Créer des Captures, je préfère Créer des Captures, mais c'est le goût personnel. On pourrait dire que Créer des Captures utilise des exceptions pour le contrôle de flux, ce qui est généralement mal vu. D'autre part, Essayer de Créer nécessite un peu maladroit output paramètre, qui pourrait être plus facilement négligés.

Donc, je préfère Créer des Captures, mais il y a certainement une place pour le débat ici.

4voto

Nick Vaccaro Points 3476

Vous avez spécifié que et les deux appels de DB. Je vais supposer que `` fait également une base de données appeler.

Pourquoi ne pas laisser la base de données gérer vos problèmes de traitement multithread ? En supposant que davantage qu’il y a des contraintes appropriés mis en place sur vos tables, vous pouvez laisser il err-out dans un appel de procédure stockée.

Donc, je vais voté pour Créer-Catch.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X