Representar las reglas de negocio con excepciones.

16

Sé que es costoso pero (OMI) creo que es una muy buena práctica. Estoy hablando de reglas como, por ejemplo, no puede guardar una factura si no es un vendedor ... así que, en ese caso, lanzar una excepción que diga 'no está autorizado' o tal ...

Otro enfoque sería tener objetos con un estado o algo así

¿Hay algún otro enfoque? ¿Cómo te sientes al respecto?

sebagomez
fuente

Respuestas:

15

Si te refieres a representar verificaciones de reglas de negocios individuales con excepciones, entonces no creo que sea una muy buena idea. Muchas veces tiene que informar más de una condición fallida y no detenerse en la primera.

Por otro lado, creo que verificar todas las reglas y luego lanzar una excepción con el resumen es una buena práctica.

matiash
fuente
1
Así es exactamente como lo manejo en mis aplicaciones. Usar FluentValidation para hacerme la vida más fácil, y el método ValidateAndThrow me salva el día.
Matteo Mosca
En una aplicación de interfaz de usuario, estoy completamente de acuerdo, pero en una aplicación de nivel de servicio generaría una excepción si se me pasara un objeto que no cumple con las reglas comerciales. Si está utilizando los dos en combinación, a veces agrega una función de validación o un error complejo como matiasha describe en la última oración.
Proyecto de ley
8
Lanza una excepción específica de dominio . Esto le permite separarse entre los nuestros y los no superiores.
@ Thorbjørn Ravn Andersen +1 gran adición "específica de dominio"
Justin Ohms
1
@JamesPoulson puede ser suficiente crear JamesPoulsonExceptioncomo una subclase de RuntimeExceptiony luego proporcionar la excepción original como cause. Entonces puedes simplemente decir if (exception instanceof JamesPoulsonException)... para diferenciar. Use el getCause()método para alcanzar la excepción original.
9

En el ejemplo que nos ha dado, creo que plantear una excepción es una mala idea. Si sabe que el usuario no está autorizado antes de que comience a trabajar y aún así le permite realizar alguna función y luego lo golpea con un mensaje DESPUÉS de que ya ha completado la tarea, es un mal diseño.

Usar excepciones para hacer cumplir las reglas comerciales no es un buen diseño.

Walter
fuente
Lo que entiendo de lo que dijiste es que no estás de acuerdo con la interfaz de usuario. Estoy bien con eso. Estoy de acuerdo con usted en que una interfaz de usuario mucho más amigable no le permitiría intentar actualizar algo que no está permitido. Pero eso no significa que la validación y la verificación de excepciones en el núcleo comercial sean innecesarias. Por el contrario, creo que son imprescindibles. Los necesita para asegurarse de que una IU mal programada no permita un mal uso de BL.
Fede
8
@Fede: es una cuestión de separación de preocupaciones. La interfaz de usuario es responsable de recopilar las intenciones del usuario e informar los comentarios de la capa empresarial. El trabajo de la capa empresarial es analizar la información recopilada por la IU, analizarla e informar a la IU y / o pedirle a la capa de datos que conserve algunos datos. Solo debe haber un acoplamiento flojo entre estas capas. Las excepciones son un enfoque pobre, deficiente para el acoplamiento suelto. No solo significa compartir clases reales entre las capas, sino que también invoca un mecanismo destinado a manejar fallas inesperadas.
Adam Crossland
@ Adam - Bien dicho y exactamente en el punto.
Walter
1
@ Adam - No te sigo con los problemas de separación de preocupaciones. No espero que nadie en la interfaz de usuario maneje una CustomerNameInLowercaseException (¡por favor, también espero que esa excepción ni siquiera exista!). Solo puede manejar una ValidationException genérica. Además, estoy 100% con usted en que la interfaz de usuario solo debe recopilar información y toda esa tontería. Lo que dije antes es que no importa lo que hagas en la interfaz de usuario, el BL no debería asumir que cada entrada está bien. Es solo una programación defensiva.
Fede
@Fede: es el trabajo de Business Layer asegurar que cada entrada esté bien. Si la interfaz de usuario lo está haciendo, entonces está implementando la lógica empresarial. Ahora, si es el caso de que un campo de entrada esté restringido a dígitos y el BL vea caracteres alfabéticos, de todos modos arroje una excepción . Cada vez que un componente recibe entradas no válidas de otro componente, lanzar una excepción es lógico y correcto. La interfaz se ha roto y el sistema está roto. Sin embargo, la validación de entradas es muy diferente a la ejecución de la lógica empresarial. Dos cosas muy diferentes.
Adam Crossland
5

No veo qué valor tiene arrojar una excepción al crear una buena lógica de negocios. Hay docenas de enfoques para manejar la lógica empresarial que no implican el uso de un sistema destinado a abordar condiciones inesperadas en la operación de un sistema.

Se espera que, en la lógica empresarial, no se cumplan las condiciones; esa es la razón para tenerlo en primer lugar, y no desea aprovechar el mismo mecanismo que maneja fallas de E / S inesperadas, errores de falta de memoria y referencias nulas. Esas son fallas del sistema, pero detectar condiciones comerciales no satisfechas es la operación exitosa del sistema.

Además, es un sistema que está listo para consecuencias no deseadas. Debido a que se debe detectar una excepción en algún momento, corre el riesgo de que una nueva excepción de la regla de negocios se vea atrapada en algún lugar que no está destinada o puede tener el código que busca reglas de negocios que capturen excepciones que en realidad no están destinadas para ello. Sí, estas condiciones pueden explicarse con buenas prácticas de codificación, pero en cualquier sistema no trivial en el que trabaje más de un desarrollador, ocurrirán errores, y solo tiene que esperar que no sean errores costosos.

Adam Crossland
fuente
1
Estoy de acuerdo, las excepciones se llaman excepciones porque no se espera que sucedan. Por otro lado, hacer cumplir las reglas comerciales en su nivel de servicio con una excepción no es necesariamente incorrecto. No espera que se use, espera que el cliente solo invoque operaciones y solo envíe datos que cumplan condiciones válidas; pero desea incorporar una capa de protección porque sabe que también pueden ocurrir errores en la codificación del cliente. Algo así como el uso de restricciones de clave externa en una base de datos: espera que las personas inserten y actualicen los datos correctamente, pero saben que podrían fallar debido a un error de programación.
Jeremy
2

expresar reglas comerciales es una cosa, implementarlas es otra

pensar en la experiencia del usuario; si el usuario no es un vendedor, por eso les dará un botón que dice 'Crear factura' en absoluto ?

Steven A. Lowe
fuente
1
Solo porque no le des un botón, eso no significa que no te enviarán el mensaje para hacer algo de todos modos. Piense cómo serían las normas de seguridad fáciles si eso era todo lo que tomó ..
jmoreno
Si el usuario no tiene permitido hacer X, no le dé un botón que diga "Do X". La mejor seguridad es la ignorancia: no le digas al usuario cosas que no puede hacer;)
Steven A. Lowe
1

Eso depende completamente de lo que se esté haciendo.

Primero, ¿cuál es el comportamiento real que quieres? Si alguien está ingresando su propia información, entonces un rechazo y un cuadro de diálogo que dice, esencialmente, "No puedes hacer eso" probablemente sea correcto. Si se trata de una persona que ingresa datos, trabajando desde una pila de formularios, un cuadro de diálogo probablemente también sea bueno, y la persona que ingresa los datos puede colocar los formularios no válidos en una pila especial. Si está realizando un procesamiento por lotes, no desea detener las cosas, sino marcarlo y pasar al siguiente.

Una vez que tenga el comportamiento, debe decidir cómo lo va a implementar. Probablemente sea una buena idea tener un verificador de reglas de negocio que arroje una excepción. Devolver un código de retorno y hacerlo pasar es otra cosa que puede salir mal, y ciertamente no desea que las entradas erróneas vayan más allá.

No se preocupe por los gastos de rendimiento. En el caso de que una persona ingrese datos, es trivial en comparación con las otras veces involucradas. Típicamente, el humano tomará más tiempo en ese sistema. En el caso de un trabajo por lotes, si las excepciones son un problema de rendimiento, está ingresando demasiados registros incorrectos y, en realidad, manejar y volver a ingresar todos esos será un problema mayor que las excepciones.

David Thornley
fuente
0

Tener una API de excepción robusta y bien diseñada que sea consistente es muy apropiado. Usar esto para hacer cumplir las reglas comerciales también puede ser apropiado. De hecho, en mi experiencia, cuanto más complicada es la regla de negocios, más probable es que termine siendo manejada de esta manera. A menudo es tan fácil, si no más fácil, escribir un sistema donde se esperan excepciones que escribir una lógica de ramificación autorizada.

Esto quiere decir que las reglas simples que se pueden describir en una sola oración generalmente deben implementarse de manera preventiva o autorizada, según cuál sea. Sin embargo, si tiene una regla que es multidimensional y requiere más de tres o cuatro factores (especialmente si la selección de estos factores se basa en uno o más de los otros factores), entonces la codificación de excepción puede ser más fácil de mantener. A menudo, en estos casos, la ruta lógica tendrá muchas excepciones precursoras que deben lanzarse (verifica por qué no se puede realizar la acción) y luego (o viceversa) hay una caída en la seguridad (para verificar que la acción esté autorizada ), a veces habrá alguna lógica de acumulación autorizada que debe verificarse (disponibilidad descendiente / ancestro, estados precursores en los que se deben colocar los objetos, etc.

Un beneficio que se deriva de este tipo de lanzamiento de excepciones es que le permite separar y reutilizar las excepciones precursoras en múltiples áreas de su proyecto. (Esta es la esencia de la Programación Orientada a Aspectos). Al hacer esto, está encapsulando un aspecto particular de sus reglas comerciales generales en un componente autónomo y mantenible. En general, estos componentes corresponderán 1-1 con los mensajes de error lanzados. (Aunque a veces tendrá un componente que arroja varias excepciones diferentes, casi nunca debería tener la misma excepción lanzada desde múltiples componentes).

En mi opinión, es más difícil diseñar sistemas que se basen en excepciones y el tiempo de desarrollo inicial es más largo ya que tiene que construir el proceso de excepción en todos los N niveles. Sin embargo, estos sistemas generalmente terminan siendo mucho más estables. Si bien nunca es posible diseñar un sistema que 'no fallará', el beneficio del diseño basado en excepciones es que siempre está anticipando la falla. Para la mayoría de las personas, el proceso puede ser contra intuitivo. Es como pedir indicaciones y que alguien te diga todas las calles que no debes encender.

Justin Ohms
fuente