¿Es una violación del Principio Abierto-Cerrado actualizar una constante que representa un valor del mundo real?

10

Tengo una clase que calcula el ingreso neto anual de los trabajadores. Tiene una constante que representa un porcentaje de impuestos. Pero un día la tasa de impuestos ha cambiado, así que necesito arreglar el código.

¿El acto de arreglar esta constante indica una violación del Principio Abierto-Cerrado , ya que postula que una clase debería estar cerrada a modificaciones?

Análisis Paradisys
fuente
10
El software cambia porque el mundo real cambia. Por otro lado, hacer que un porcentaje de impuestos sea una constante no es tanto una violación del Principio Abierto-Cerrado, sino simplemente una cosa ignorante. El porcentaje de impuestos es un elemento cambiante obvio que debe vincularse en tiempo de ejecución.
Richard Chambers
44
Estoy completamente de acuerdo con Richard. Si tiene que cambiar el código para corregir esta "constante", OCP es el menor de sus problemas.
Robert Harvey
3
Lo que constituye una violación de OCP es altamente subjetivo y todo el asunto es algo obsoleto de todos modos (dado que la herencia de implementación ya no es la mejor práctica). Esta es una pregunta típica en la que tienes que adivinar qué piensa la persona que hace la pregunta.
Robert Bräutigam
2
@DocBrown: ¿qué constituye un "nuevo requisito"? Si me muestra un código, puedo señalar nuevos requisitos que definitivamente requerirán un cambio de código, independientemente de cómo se ajuste OCP. Volvamos a la pregunta: si el desarrollador le preguntó al experto en negocios al respecto, y no se esperaba que la tasa impositiva cambiara más de una vez cada dos años, no tiene sentido hacerlo configurable o inyectable. Simplemente manténgalo simple y prepárese para lo que sabe . Y para esas cosas, claro, que sea externo a la clase. Entonces eso depende .
Robert Bräutigam
1
@ RobertBräutigam: mi punto es que, en mi humilde opinión, no existe tal cosa como "conformidad con OCP", solo hay "conformidad con OCP en el contexto de ciertas categorías de requisitos". Seguramente puede haber cierta subjetividad a las categorías que un componente debe ser "conforme a OCP". Pero en el caso descrito en esta pregunta, según tengo entendido, ya se identificó un requisito cambiante, de modo que esta "clase de cálculo de ingresos" claramente no obedece al OCP en el contexto de este requisito específico.
Doc Brown

Respuestas:

14

El OCP se puede entender mejor cuando se piensa en clases o componentes proporcionados por un proveedor A en algún tipo de biblioteca de recuadro negro, para uso de los usuarios B, C y D (tenga en cuenta que este es solo un modelo mental que estoy usando para mayor claridad, no importa si en realidad el único usuario de la clase es el mismo A).

Si B, C y D pueden usar o reutilizar las clases proporcionadas para diferentes casos de uso, sin la necesidad de modificar el código fuente de la biblioteca, entonces el componente cumple con el OCP ( con respecto a una categoría de casos de uso ). Hay diferentes medios para lograr esto, como

  • hacer que la clase sea heredable (generalmente junto con el patrón de método de plantilla o el patrón de estrategia)

  • al proporcionar "puntos de inyección" para la inyección de dependencia

  • proporcionando parámetros de configuración para la clase o componente (por ejemplo, teniendo un parámetro de constructor "porcentaje de impuestos", como en su caso, o utilizando algún otro mecanismo de configuración)

  • quizás otros medios, dependiendo del lenguaje de programación o del ecosistema

Los ejemplos típicos que se encuentran en los libros de texto son a menudo del primer o segundo tipo (supongo que, a los ojos de los autores de esos libros, el tercer tipo es demasiado trivial para que valga la pena mencionarlo).

Como puede ver, esto no tiene nada que ver con prohibir cualquier cambio en el código fuente por parte del proveedor A (como la corrección de errores, la optimización o la adición de nuevas funciones de una manera compatible con versiones anteriores), que no está relacionado con el OCP. El OCP se trata de cómo A diseña la interfaz y la granularidad de los componentes en la biblioteca, de modo que los diferentes escenarios de reutilización (como el rescate con diferentes tasas impositivas) no inducen automáticamente requisitos para el cambio.

Entonces, a pesar de lo que otros le dicen aquí, la respuesta es claramente "sí" , sería una violación del OCP.

EDITAR: parece que alguien escribió una publicación de blog detallada sobre este tema. Aunque algunas partes podrían haber sido mejor redactadas (como señaló Derek Elkins), parece que el autor generalmente comparte mi punto de vista de que "cumplir el OCP" no es una propiedad absoluta, sino algo que solo puede evaluarse en el contexto de ciertas categorías de cambios de requisitos.

Doc Brown
fuente
OK, entonces OCP se trata de proporcionar un comportamiento extensible para diferentes casos de uso con uno de los tres medios que ha enumerado, ¿verdad? Pero, ¿qué pasaría si el ejemplo de un OP implicara que algo fundamental está a punto de cambiar? No sé de qué país es OP, pero en mi país la tasa impositiva es algo que no cambia muy a menudo. Fue un mal ejemplo, pero tal vez se extrajo intencionalmente en una constante, para enfatizar el punto. Estoy bastante seguro de que no estaba destinado a ser configurable o ampliable. Entonces, tal vez la pregunta era sobre "esto no tiene nada que ver con prohibir cualquier cambio del código fuente por parte del vendedor A".
Vadim Samokhin
Al menos lo entendí así. El pobre tipo que borró su respuesta aceptada lo hizo, supongo. Lo has visto desde un ángulo un poco diferente: entiendo tu punto y estoy de acuerdo con él. Pero parece que el comentario más sabio fue dado por @Robert Bräutigam. Hasta ahora no me había dado cuenta de que OCP es TAN subjetivo.
Vadim Samokhin
1
Supongo que si alguna vez me hacen la misma pregunta, hay una pregunta que debería hacer en respuesta: "¿se supone que ese comportamiento debe extenderse o configurarse de alguna manera?". En caso afirmativo, la modificación directa de una clase en sí misma es una violación de OCP. Si no, entonces OCP simplemente no es aplicable en esa situación.
Vadim Samokhin
1
@Zapadlo: Creo que si un componente cumple con el OCP para una clase de requisitos no es muy subjetivo; en la mayoría de los casos, es bastante claro si un nuevo requisito necesita una modificación del código fuente de un componente, o si el componente admite este requisito ". Los posibles enfoques para implementarlo no se limitan a los primeros 3 medios que enumeré, vea mi edición. Su noción de subjetividad podría ser causada porque el OCP solo tiene un nombre engañoso y está bastante mal explicado en muchos libros de texto.
Doc Brown
Mi noción de subjetividad fue causada por el hecho de que no entendí completamente lo que dijiste, pero supongo que ahora sí. Muchas gracias por los comentarios perspicaces y su respuesta.
Vadim Samokhin
4

Como otros dicen, idealmente la clase de ingresos del trabajador permitiría la parametrización de la constante, haciendo que esta clase sea independiente de ese valor.

En última instancia, la aplicación de llamada también podría permitir la parametrización en términos de configuración externa (por ejemplo, un archivo). Una vez que tengamos la configuración externa, podemos cambiar la tasa de impuestos, aunque tenga en cuenta que si el archivo de configuración se lee solo una vez al inicio, entonces la aplicación tendrá que reiniciarse para que los porcentajes de impuestos actualizados surtan efecto, por lo que es algo a tener en cuenta mente. Podríamos proporcionar una función de aplicación para releer la configuración cuando se nos indique, o podríamos proporcionar un mecanismo más complicado que se da cuenta cuando cambia el archivo de configuración ...

A largo plazo, es posible que los problemas impositivos requieran más que solo un porcentaje; por ejemplo, que un día las leyes impositivas son más complejas y requieren varios porcentajes y algunas constantes (por ejemplo, la cantidad por debajo de $ 10k gravada con X%, mientras que el resto gravado al Y%).

Básicamente, esto sugiere utilizar un patrón de estrategia, donde la clase principal en cuestión aquí acepta un objeto de estrategia para calcular el impuesto.

Las diversas estrategias (y las constantes de% y $) deben poder elegirse desde el archivo de configuración, y ahora, agregar una nueva estrategia requiere agregar algún código nuevo, pero no necesariamente actualizaciones del código existente.

Cada estrategia puede saber cómo analizar / interpretar sus propios argumentos de configuración externa, junto con cómo calcular el impuesto real.

Dinámicamente, el impuesto puede depender aún más de la configuración regional que rige, por lo que puede tener una configuración regional asociada con las ganancias o con los empleados (o ambos). En la configuración externa, podríamos asociar la configuración regional con la estrategia fiscal.


También vea inyección de dependencia , donde gestionamos estas cosas explícitamente.

Erik Eidt
fuente
1
La pregunta no era si es una mala idea enterrar algo como un porcentaje de impuestos en el código, estoy seguro de que es obvio para la mayoría de nosotros aquí (incluido el OP). La pregunta era: "¿esto viola el OCP?" Entonces no veo cómo su respuesta se refiere a esta pregunta.
Doc Brown
1

Si necesita modificar la clase para cambiar el valor del impuesto, entonces su diseño de hecho está violando el OCP. El diseño apropiado, para lo que ha descrito hasta ahora, es que la clase calculadora tome el valor del impuesto como parámetro.

Si su clase está instanciada (lo que significa que no es una clase estática), al hacer la propiedad de clase de la variable de impuestos, cuyo valor se inyecta a través del constructor, también mejoraría la cohesión de la clase.

En resumen, su diseño actual hace que su clase dependa de un valor constante que no es realmente una constante (definiendo constante como un valor que nunca cambiaría sin importar qué, como el valor de PI). Viola OCP. Cambie el diseño para recibir el valor fiscal como argumento del constructor.

Christopher Francisco
fuente
0

Totalmente de acuerdo con @Becuzz, y solo quiero resumir esto: OCP se trata de encontrar abstracciones reutilizadas (por lo tanto, útiles) que se inyectan en una clase. Por lo tanto, el comportamiento de la clase se modifica no cambiando su código, sino proporcionándole diferentes implementaciones. Esto se aclara en el libro de Robert Martin " Desarrollo, principios, patrones y prácticas de software ágil ", consulte el capítulo correspondiente "El principio abierto-cerrado", el subcapítulo "La abstracción es la clave". Aclara otro concepto erróneo de que el comportamiento solo puede modificarse con la herencia. Fue Bertrand Meyer quien propuso eso en 1988 en su libro " Construcción de software orientado a objetos ", no Robert Martin.

Vadim Samokhin
fuente
-2

A mi modo de ver, no es una violación del principio abierto cerrado. Sin embargo, el hecho de que algo que está destinado a cambiar en el tiempo (como el porcentaje de impuestos) es una constante es una falla de diseño: no debe cambiar el valor de la constante sino cómo maneja el porcentaje de impuestos. Esto debería ser algún tipo de configuración que podría modificarse sin volver a compilar todo.

Zalomon
fuente
El "defecto de diseño" es que está violando el principio de abrir y cerrar, ya que necesita volver a compilar el código para cambiar la constante.
Erdrik Ironrose