c# - versiones - visual studio 2017 full
¿Qué diseño es más preferible: test-create, try-create, create-catch? (4)
Supongamos que hay una operación que crea un usuario. Esta operación puede fallar si existe un correo electrónico o nombre de usuario especificados. Si ha fallado, se requiere saber exactamente por qué. Hay tres enfoques para hacer esto tal como lo veo y me pregunto si hay un claro ganador.
Entonces, aquí hay un usuario de clase:
class User
{
public string Email { get; set; }
public string UserName { get; set; }
}
Y hay 3 formas de lograr crear operación:
Prueba-Crear
if (UserExists(user)) act on user exists error;
if (UsernameExists(user)) act on username exists error;
CreateUser(user);
UserExists y UsernameExists realizan una solicitud al servidor de db para realizar una validación. Estas llamadas nuevamente se repiten en CreateUser para asegurar que API se use correctamente. En caso de que la validación haya fallado, tiro ArgumentOutOfRangeException en ambos casos. Entonces hay un golpe de rendimiento.
Try-Create
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;
}
}
Este patrón realiza la validación solo una vez, pero recurrimos al uso de los denominados códigos de error, que no se consideran una buena práctica.
Crear-Atrapar
try
{
CreateUser(user);
}
catch(UserExistsException)
{
act on user exists error;
}
catch(UsernameExistsException)
{
act on username exists error;
}
No utilizo códigos de error aquí, pero ahora tengo que crear una clase de excepción separada para cada caso. Es más o menos como se supone que se usan las excepciones, pero me pregunto si vale la pena crear una excepción por separado en lugar de la entrada enum.
Entonces, ¿tenemos un ganador claro o es más una cuestión de gusto?
Entonces, ¿tenemos un ganador claro o es más una cuestión de gusto?
La primera opción tiene un defecto fundamental: nunca será seguro ni seguro para hilos si CreateUser
confía en recursos externos y otras implementaciones pueden crearse entre sus pruebas. En general, tiendo a evitar este "patrón" debido a esto.
En cuanto a las otras dos opciones, realmente se trata de si se espera que ocurra la falla. Si se espera que CreateUser
falle de manera algo normal, el patrón Try * es mi preferencia, ya que el uso de excepciones se convierte esencialmente en excepciones para el flujo de control.
Si el fracaso realmente fuera un caso excepcional, entonces las excepciones serían más comprensibles.
Esto es algo subjetivo, pero hay algunos pros y contras concretos que vale la pena señalar.
Una desventaja del enfoque de creación de prueba es la condición de carrera. Si dos clientes intentan crear el mismo usuario aproximadamente al mismo tiempo, es posible que pasen las pruebas y luego intenten crear el mismo usuario.
Entre Try-Create y Create-Catch, prefiero Create-Catch, pero ese es el gusto personal. Se podría argumentar que Create-Catch utiliza excepciones para el control de flujo, que generalmente es desaprobado. Por otro lado, Try-Create requiere un parámetro de output
un tanto incómodo, que podría pasarse por alto con mayor facilidad.
Por lo tanto, prefiero Create-Catch, pero definitivamente hay lugar para el debate aquí.
Has especificado que UserExists
y UsernameExists
hacen llamadas a DB. CreateUser
que CreateUser
también realiza una llamada a la base de datos.
¿Por qué no dejar que la base de datos maneje sus problemas de enhebrado? Asumiendo además que existen restricciones adecuadas establecidas en su (s) mesa (s), puede dejar que se extravíen dentro de una llamada de proceso almacenada.
Por lo tanto, emitiré mi voto para Create-Catch .
Test-Create puede causar condiciones de carrera, por lo que no es una gran idea. También es probable que haga un trabajo extra.
Try-Create es bueno si espera que los errores sean parte del flujo de código normal (como en el caso de la entrada del usuario).
Create-Catch es bueno si los errores son realmente excepcionales (por lo que no le preocupa el rendimiento).