2010-12-14 11 views
10

Tengo una conversación con un colega sobre cuándo lanzar fallas y cuándo no arrojar fallas en un servicio WCF.Fallo o no falla

Una opinión es que solo lanzamos fallas cuando la operación del servicio no pudo hacer su trabajo debido a algún error; y algo puede estar en un estado inválido por eso. Así, algunos ejemplos:

  • ValidateMember (nombre de la cadena, cadena contraseña, país cadena) -> lanzaría un fallo si no se pasan los parámetros obligatorios, ya que la validación en sí no podía ser ejecutado; -> echaría la culpa si ocurrió algún error interno, al igual que la base de datos se redujo -> devolvería un contrato estado en todos los demás casos, que especifica el resultado de la validación (MemberValidated, WrongPassword, MemberNotKnown, ...)

  • GetMember (int memberId) -> haría sino echar la culpa si algo se ha reducido, en todos los demás casos, sería volver al miembro o nula si no se encuentra

la otra opinión es que también hay que tirar faltas cuando GetMember no encuentra el miembro o, en el caso de ValidateMember, la contraseña es incorrecta.

¿Qué opinas?

+0

Por cierto, si invitas a personas que brindan respuestas útiles en ocasiones, entonces quizás consigas que más personas respondan tus preguntas –

+0

no puede hacer eso, ¡upvote requiere 15 reputación! –

+0

Ahora puedes :-) – VdesmedT

Respuesta

12

Mi opinión sobre esto ...

Hay tres causas del fracaso:

  1. El código de servicio inició una excepción, por ejemplo, error de base de datos, error de lógica en su código. Esto es tu culpa.
  2. El código del cliente no pudo usar su servicio correctamente según su documentación, p. no estableció un valor de bandera requerido, no pudo pasar una ID. Esta es la falla del desarrollador del software cliente.
  3. El usuario final escribió algo tonto en la pantalla, p. fecha de nacimiento faltante, salario negativo. Este es el error del usuario final.

Depende de usted cómo elija asignar los contratos de falla reales a cada causa de falla. Por ejemplo, hacemos esto:

  • Para las causas 1 y 2, todo lo que el código del cliente necesita saber es que el servicio falló. Definimos un contrato de falla de "error fatal" muy simple que contiene solo un ID de error único. Los detalles completos del error se registran en el servidor.
  • Para la causa 3, el usuario final necesita saber exactamente lo que hizo mal. Definimos un contrato de falla de "errores de validación" que contiene una colección de mensajes de error amistosos para que el código del cliente se muestre en la pantalla.

Hemos prestado el Microsoft EntLib class de la causa 3, y el uso exception shielding para manejar las causas 1 y 2 de forma declarativa. Hace un código muy simple.

para aclarar:

Manejamos las tres causas como esta dentro del servicio:

  1. una excepción inesperada se lanza en el código de servicio. Lo atrapamos en el nivel superior (en realidad, el blindaje de excepción lo atrapa, pero el principio es el mismo). Registre todos los detalles, luego arroje FaultException<ServiceFault> al cliente que solo contenga el ID del error.
  2. Validamos los datos de entrada y lanzamos deliberadamente una excepción.Normalmente es ArgumentException, pero cualquier tipo apropiado sería suficiente. Una vez arrojado, se trata exactamente de la misma manera que (1) porque queremos que parezca igual para el cliente.
  3. Validamos los datos de entrada y lanzamos deliberadamente una excepción. Esta vez, es un FaultException<ValidationFault>. Configuramos el blindaje de excepción para pasar este a través de no envuelto, por lo que aparece en el cliente como FaultException<ValidationFault> no FaultException<ServiceFault>.

Resultado final:

  • No hay bloques de captura en absoluto dentro del servicio (agradable código limpio).
  • El cliente solo tiene que atrapar FaultException<ValidationFault> si desea mostrar mensajes al usuario. El controlador global de errores del cliente trata todos los demás tipos de excepción, incluidos FaultException<ServiceFault>, como errores fatales, ya que un error fatal en el servicio generalmente también implica un error fatal en el cliente.
+0

bien, entonces todos estos casos se refieren a datos de entrada no válidos, en ese caso también lanzamos fallas. ¿Pero qué harías en los otros casos? –

+0

He agregado más detalles. Eso responde tu pregunta? –

+0

Veo cómo manejas las excepciones y fallas, gracias.¿Lanzaría una falla en el caso de GetCustomer cuando se pasa una identificación de cliente pero no se encuentra cuando el repositorio trata de encontrarla, o no? –

3

Es una falla rutinaria común, luego arrojar una falla es un error. El software debe escribirse para manejar elementos de rutina, como ingresar la contraseña incorrecta. El procesamiento de fallas es por fallas excepcionales que no se consideran parte del diseño normal del programa.

Por ejemplo, si su programa fue escrito con la idea de que siempre tiene acceso a una base de datos y la base de datos no es accesible, ese es un problema donde la "corrección" está fuera de los límites de su software. Se debe arrojar una falla.

El procesamiento de fallas utiliza diferentes flujos lógicos a través de la estructura del lenguaje de programación, y al usarlo solo cuando "dejó" el procesamiento normal del problema de programación, hará que su solución aproveche la función del lenguaje de programación de una manera que parece más natural.

2

Creo que es una buena práctica separar el manejo de errores y el manejo de errores. Cualquier caso de error debe ser tratado por su programa; el manejo de fallas está reservado para condiciones excepcionales. Como una guía para la separación de los dos, me pareció útil al considerar tales casos, recordar que solo hay tres tipos de error (cuando se manejan datos y mensajes) y solo un tipo de falla. Los tipos de error están relacionados con diferentes tipos de validación:

  1. Validación de mensajes - se puede determinar a partir de los contenidos de los mensajes que los datos son válidos o no válidos.

    Ejemplo: contenido destinado a ser una fecha de nacimiento: a partir de los datos puede decir si es válido o no.

  2. Validación de contexto: solo puede determinar que el contenido no es válido por referencia al mensaje combinado con el estado del sistema.

    Ejemplo: una fecha válida para unirse a una empresa es anterior a la fecha de nacimiento de esa persona.

  3. Mentiras en el sistema: solo puede determinar que un mensaje fue erróneo cuando un mensaje posterior arroja una anomalía.

    Ejemplo: fecha de nacimiento válida almacenada e inspección del certificado de nacimiento de la persona muestra que esto es incorrecto. La corrección de mentiras al sistema generalmente requiere una acción fuera del sistema, por ejemplo, la invocación de recursos legales o disciplinarios.

Su sistema DEBE lidiar con todas las clases de errores, aunque en el caso tres esto puede estar limitado a la emisión de una alerta.

Las fallas (excepciones) por el contrario solo tienen una causa: corrupción de datos (que incluye el truncamiento de datos). Ejemplo: los parámetros de validación no se pasan.

Aquí el mecanismo adecuado es el manejo de fallas o excepciones, básicamente pasando el problema a alguna otra parte del sistema que sea capaz de manejarlo (razón por la cual debería haber un destino final para fallas no controladas).

1

Mi opinión es que deben producirse excepciones/fallas cuando no se puede lograr lo que el método debe hacer. Por lo tanto, la lógica de validación nunca debe generar excepciones, excepto si la validación no puede realizarse (es decir, por razones técnicas) pero nunca solo porque los datos no son válidos (en ese caso devolverá códigos/mensajes de validación o cualquier cosa que ayude a la persona que llama a corregir datos).

Ahora el caso GetMember es interesante porque se trata de semántica. El nombre del método sugiere que un miembro puede recuperarse al pasar una identificación (en comparación, por ejemplo, con el método TryGetMember). Por supuesto, el método no debería arrojar la misma excepción si el ID no se encuentra o si la base de datos no responde, pero una identificación incorrecta pasada a este método es probablemente la señal de que algo va mal en algún lugar antes de esa llamada. Excepto si el usuario puede ingresar directamente un ID de miembro desde la interfaz en cuyo caso se debe realizar una validación antes de llamar al método.

Escuché mucho sobre el problema de rendimiento. Acabo de hacer una prueba simple usando C# y trow/catch 1000 excepciones. El tiempo que tomó fue de 23 ms para las excepciones de 1 K. Eso es 23μ por excepción. Creo que el rendimiento ya no es el primer argumento aquí, excepto si planea recaudar más de 2000 excepciones por segundo, en cuyo caso tendrá un rendimiento del 5%, lo que puedo empezar a considerar.

mi humilde opinión ...

2

En los viejos tiempos que solíamos tener una regla que las excepciones eran sólo para cosas excepcionales e inesperadas. Una de las razones por las que no quería usarlos demasiado era que "costaban" mucho poder de cómputo.

Pero si usa excepciones, puede reducir la cantidad de código, sin necesidad de muchas otras afirmaciones, simplemente deje que la excepción salte.

Depende de su proyecto. Lo más importante es que hay un estándar de proyecto y todos lo hacen de la misma manera.

Cuestiones relacionadas