Aclarar el principio abierto / cerrado

25

Como ya he explicado, el principio abierto / cerrado establece que una vez que el código escrito no debe modificarse (aparte de las correcciones de errores). Pero si cambian las reglas de mi negocio, ¿no debería modificar el código que implementa esos cambios? Sospecho que no estoy entendiendo algo sobre cómo funciona el principio porque no tiene sentido para mí.

Winston Ewert
fuente

Respuestas:

22

Este es probablemente el más sólido de los principios sólidos para explicar. Déjame intentarlo. Imagina que escribiste una clase de Factura que funciona perfectamente y no tiene errores. Hace un PDF de una factura.

Entonces alguien dice que quiere una factura HTML con enlaces. No cambia ningún código en Factura para satisfacer esta solicitud. En cambio, crea otra clase, HTMLInvoice, que hace lo que ahora quieren. Aprovecha la herencia para no tener que escribir mucho código duplicado en HTMLInvoice.

El código antiguo que usaba la antigua factura no está roto ni afectado de ninguna manera. El nuevo código puede usar HTMLInvoice. (Si también realiza la sustituibilidad de Liskov , la L de sólido, puede dar instancias HTMLInvoice al código existente que espera instancias de factura.) Todos viven felices para siempre.

La factura está cerrada a modificación, abierta a extensión. Y tiene que escribir la factura correctamente de antemano para que esto funcione, por cierto.

Kate Gregory
fuente
1
Si las reglas de negocio cambian, ¿no se supone que funciona perfectamente sin errores, por lo que no se aplica el principio de apertura / cierre?
JeffO
Luché con esta regla yo misma y lo que Kate sugiere es básicamente lo que he llegado a la conclusión. En los negocios, intentas programar clases más pequeñas y más flexibles para que puedas reutilizarlas bien. Si logra que funcionen correctamente, no desea modificarlos. Pero rara vez están completamente "hechos", por lo que es inevitable alguna modificación. Tenga en cuenta que el texto dice "módulo" sin embargo, no objeto. A menudo aplico con éxito el OCP a nivel de función, con funciones ajustadas que hacen una cosa perfectamente y nunca necesitan ser cambiadas.
CodexArcanum
1
@Jeff OI distingue entre corregir un error (donde el código no cumplió con el requisito original y nadie lo quiere como está) y cambiar los requisitos. Si requiero archivos PDF y el código hace que los archivos PDF, no hay fallo, a pesar de que ahora quiero HTML (y por lo general la gente quiere HTML, así, no en lugar de.)
Kate Gregory
2
@ Winston: esto es lo que quise decir cuando dije que tenía que escribir la factura correctamente. Idealmente, ya había una factura bastante abstracta y heredó PDFInvoice esperando esto. Si no, tienes que romper la regla una vez para prepararte para no romperla en el futuro. De cualquier manera, predecir cambios futuros es una gran parte de todo esto, y esa es la parte de la receta "atrapar y cortar un elefante".
Kate Gregory
1
Tu última declaración es la más importante. Abierto / cerrado es un diseño ideal, y debe obtener el diseño por adelantado para lograrlo. No todo necesita satisfacer abierto / cerrado tampoco, pero es una herramienta poderosa si puedes llegar allí.
Alex Feinman
13

¿Has leído el artículo El principio abierto-cerrado de los amigos del tío Bob en ObjectMentor? Creo que es una de las mejores explicaciones por ahí.

Hay muchas heurísticas asociadas con el diseño orientado a objetos. Por ejemplo, "todas las variables miembro deben ser privadas", o "las variables globales deben evitarse", o "usar la identificación de tipo de tiempo de ejecución (RTTI) es peligroso". ¿Cuál es la fuente de estas heurísticas? ¿Qué los hace verdaderos? ¿Son siempre ciertas? Esta columna investiga el principio de diseño que subyace a estas heurísticas: el principio abierto-cerrado.

Como dijo Ivar Jacobson: “Todos los sistemas cambian durante sus ciclos de vida. Esto debe tenerse en cuenta al desarrollar sistemas que se espera que duren más que la primera versión ”. ¿Cómo podemos crear diseños que sean estables ante el cambio y que duren más que la primera versión? Bertrand Meyer nos dio orientación en 1988, cuando acuñó el ahora famoso principio abierto-cerrado. Parafraseándolo:

LAS ENTIDADES DE SOFTWARE (CLASES, MÓDULOS, FUNCIONES, ETC.) DEBEN ABRIRSE PARA SU EXTENSIÓN, PERO CERRARSE PARA MODIFICARSE.

Cuando un solo cambio en un programa resulta en una cascada de cambios en módulos dependientes, ese programa exhibe los atributos indeseables que hemos llegado a asociar con un diseño "malo". El programa se vuelve frágil, rígido, impredecible e irreutilizable. El principio abierto-cerrado ataca esto de una manera muy directa. Dice que debe diseñar módulos que nunca cambien . Cuando los requisitos cambian, amplía el comportamiento de dichos módulos agregando código nuevo, no cambiando el código antiguo que ya funciona.

Descripción

Los módulos que se ajustan al principio abierto-cerrado tienen dos atributos principales.

  1. Están "abiertos para la extensión".
    Esto significa que el comportamiento del módulo puede extenderse. Que podemos hacer que el módulo se comporte de formas nuevas y diferentes a medida que cambian los requisitos de la aplicación, o para satisfacer las necesidades de las nuevas aplicaciones.
  2. Están "cerrados por modificación".
    El código fuente de dicho módulo es inviolable. Nadie puede hacer cambios en el código fuente.

Parece que estos dos atributos están en desacuerdo entre sí. La forma normal de extender el comportamiento de un módulo es realizar cambios en ese módulo. Normalmente se cree que un módulo que no se puede cambiar tiene un comportamiento fijo. ¿Cómo se pueden resolver estos dos atributos opuestos?

La abstracción es la clave ...

Martijn Verburg
fuente
3
Este es un buen artículo que explica la abstracción. Sin embargo, hay un punto fundamental a tener en cuenta, y ese es un buen diseño abstracto presentado en primer lugar. Muchas tiendas tienen mucho código heredado y la única forma de cambiarlo es "modificarlo", no "extenderlo". Si este es el caso, probablemente uno debería trabajar para cambiar eso, pero hasta que lo haga, está atascado modificando el código.
Michael K
@ Chris, genial - También recomiendo el libro "Código limpio" del tío Bob si te gusta este tipo de cosas.
Martijn Verburg
@Michael - Totalmente de acuerdo, es casi como tener que refactorizar el código para que sea ideal.
Martijn Verburg
El artículo demuestra muy bien la importancia de la abstracción. Pero no estoy captando la conexión entre las abstracciones e intentando nunca modificar los módulos después de escribirlos. La abstracción significa que puedo modificar el módulo X sin tener que hacer modificaciones al módulo Y. ¿Pero no es el punto de hacerlo para poder modificar el módulo X o el módulo Y si es necesario?
Winston Ewert
1
Guau. El código es inviolable? Nunca he sido un gran admirador del tío Bob. Este director es pedante, extremadamente no pragmático y tiene una conexión limitada con la realidad.
user949300
12

La respuesta de Kate Gregory es muy buena, pero considere una situación diferente en la que un nuevo requisito puede satisfacerse con un cambio relativamente pequeño en la Invoiceclase existente . Por ejemplo, supongamos que se debe agregar un nuevo campo al PDF de la factura. Según OCP, aún deberíamos crear una nueva subclase, incluso si el nuevo campo pudiera agregarse en la implementación existente cambiando algunas líneas de código.

En mi opinión, OCP refleja la realidad de los años 80 y principios de los 90, donde los proyectos a menudo ni siquiera usaban el control de versiones, y mucho menos tenían pruebas de regresión automatizadas o el beneficio de sofisticadas herramientas de refactorización. OCP fue un intento de evitar el riesgo de romper el código que había sido probado manualmente y puesto en producción. Hoy, tenemos mejores formas de gestionar el riesgo de romper el software de trabajo (a saber, sistemas de control de versiones, TDD y pruebas automatizadas, y herramientas de refactorización).

Rogério
fuente
2
Sí, porque en la práctica, no es posible crear una clase que se pueda extender para adaptarse a todos los futuros posibles, a menos que proteja todos los métodos (lo que apesta y también viola el principio YAGNI, que es mucho más importante que el O / C dito).
Martin Wickman
"Según OCP, aún deberíamos crear una nueva subclase, incluso si el nuevo campo pudiera agregarse en la implementación existente cambiando algunas líneas de código". ¿Por qué no agregar nuevos campos o nuevos métodos? El punto importante es que solo está agregando (extendiendo) y no cambiando lo que ya está allí.
Giorgio
Creo que el principio tiene sentido cuando se trata de bibliotecas / marcos estándar. No desea abrir y modificar piezas de código bien establecidas. De lo contrario, se trata de una refactorización constante y prueba, prueba, prueba.
mastaBlasta
@Giorgio Claro, la adición de nuevos campos o métodos es lo que yo recomendaría, en la mayoría de los casos. Pero eso no es extensión , es "modificación"; el punto principal de OCP es que el código debe "cerrarse para modificación" (es decir, sin cambios en el archivo fuente preexistente) mientras está "abierto para extensión"; y la extensión en OCP se logra a través de la herencia de implementación.
Rogério
@ Rogério: ¿Por qué define el límite entre extensión y modificación a nivel de clase? ¿Hay alguna razón en particular para esto? Prefiero configurarlo a nivel de método: cambiar un método cambia el comportamiento de su aplicación, agregar un método (público) extiende su interfaz.
Giorgio
6

Personalmente, creo que este principio debe tomarse con una pizca de sal. El código es orgánico, las empresas cambian y el código cambia según las necesidades de una empresa a medida que pasa el tiempo.

Me resulta muy difícil entender el hecho de que la abstracción es clave. ¿Qué pasa si la abstracción estaba originalmente equivocada? ¿Qué pasa si la función comercial ha cambiado significativamente?

Este principio esencialmente garantiza que las intenciones y el comportamiento ORIGINALES de un diseño nunca deben cambiar. Eso probablemente funcione para aquellos que tienen API públicas y sus clientes tienen problemas para mantenerse al día con las nuevas versiones y algunos otros casos extremos. Sin embargo, si una empresa posee TODO el código, entonces cuestiono este principio.

Tener una buena cobertura de prueba de su código debería facilitar la refactorización de su base de código. Significa que está bien equivocarse: sus pruebas ayudarán a guiarlo hacia un mejor diseño.

Dicho esto, si no hay pruebas, entonces este principio es sólido.

usuario126776
fuente