Quizás la mayor promesa de usar el paradigma orientado a objetos es la reutilización del código. Algunos discuten que esto se logró. ¿Por qué se logró (no)?
¿El código se reutiliza como lo define OOP y hace que los proyectos sean más productivos?
¿O más manejable? ¿O más fácil de mantener? ¿O con más calidad?
Probablemente todos estamos de acuerdo en que la reutilización de código es algo bueno, pero hay varias formas de lograr este objetivo. La pregunta es sobre el método de reutilización de código ofrecido por OOP. ¿Fue algo bueno? ¿Existen mejores métodos para lograr la reutilización del código que la orientación a objetos, subclases, polimorfismo, etc.? ¿Qué formas son mejores? ¿Por qué ?
Cuéntenos su experiencia con la reutilización de OOP u otra reutilización de paradigmas.
fuente
Respuestas:
La reutilización de código es una muy buena idea. No es genial .
Tengo una perspectiva extraída de unos 30 años de ingeniería de software, tratando de "reutilizar".
Comencé a investigar la "reutilización de código" como tema de investigación en los años 80, después de descubrir que había reutilizado el diseño de un sistema operativo que construí a principios de los 70, para otro sistema operativo que construí a fines de los 70.
La buena parte de la reutilización del código es la capacidad de reutilizar a veces el código preexistente honesto a dios. Pero el mundo está lleno de código; como puedes encontrar lo que buscas Esto es lo que llamo la maldición de reutilización :
Soy Santa Claus (ok Código abierto), y tengo una bolsa de mil millones de componentes de software. Puedes tener cualquiera de ellos.
Buena suerte eligiendo.
Para resolver bien el problema de reutilización:
En su mayoría, lo que se ha descubierto a lo largo de los años es que para que el código sea reutilizable, debe diseñarse para ese propósito, o contiene demasiados supuestos implícitos. Las bibliotecas de reutilización de código más exitosas en realidad han sido bastante pequeñas. Podría decirse que las bibliotecas y los marcos son código "reutilizable" y son extremadamente exitosos; Java y C # tienen éxito no porque sean muy buenos lenguajes de computadora, sino porque tienen enormes bibliotecas bien diseñadas, implementadas y documentadas disponibles. Pero la gente no mira el código fuente en las bibliotecas; simplemente llaman una API bien documentada (diseñada para ser generalmente utilizable).
Lo que la reutilización de código no ha hecho (OOP tampoco) es proporcionar una mejora de órdenes de magnitud en nuestra capacidad de codificar sistemas.
Creo que la falla clave es que cualquier tipo de reutilización de código es fundamentalmente limitada porque el código tiene demasiados supuestos incorporados . Si hace que el código sea pequeño, minimiza las suposiciones, pero el costo de construir desde cero no es muy grande y las ganancias de reutilización no son efectivas. Si haces que los fragmentos de código sean enormes, son prácticamente inútiles en un nuevo contexto. Al igual que Gulliver, están atados a la playa por un millón de cuerdas pequeñas, y simplemente no puedes permitirte cortarlas todas.
En lo que deberíamos estar trabajando es en la reutilización del conocimiento para construir código . Si podemos hacer esto, entonces podemos aplicar ese conocimiento para construir el código que necesitamos, manejando el conjunto actual de suposiciones.
Para hacer esto, todavía se necesita la misma capacidad de especificación para caracterizar los componentes de software (¡todavía tiene que decir lo que quiere!). Pero luego aplica este conocimiento de "construcción" a las especificaciones para generar el código que desea.
Como comunidad, todavía no somos muy buenos en esto. Pero la gente lo hace todo el tiempo; ¿Por qué no podemos automatizarlo? Hay mucha investigación, y esto demuestra que se puede hacer en muchas circunstancias.
Una pieza clave de la maquinaria necesaria para esto son las herramientas mecánicas para aceptar "descripciones de componentes" (estos son solo documentos formales y se pueden analizar como lenguajes de programación) y aplicarles transformaciones de programa .
Los compiladores ya hacen esto: -} Y son realmente buenos en la clase de problema que abordan.
Los modelos UML con generación de código son un intento de hacer esto. No es un muy buen intento; más o menos lo que uno dice en la mayoría de los modelos UML es "Tengo datos que se ven así". Es bastante difícil generar un programa real si se deja de lado la funcionalidad.
Estoy tratando de construir sistemas prácticos de transformación de programas, una herramienta llamada DMS . Me ha distraído bastante aplicar las transformaciones del programa no tanto a las especificaciones abstractas para generar código, sino al código heredado para limpiarlo. (¡Son el mismo problema en abstracto!). (Construir tales herramientas lleva mucho tiempo; he estado haciendo esto durante 15 años y mientras tanto tienes que comer).
Pero el DMS tiene las dos propiedades clave que describí anteriormente: la capacidad de procesar especificaciones formales arbitrarias y la capacidad de capturar "conocimiento de generación de código" como transformaciones, y aplicarlas bajo demanda. Y notablemente, generamos en algunos casos especiales, algún código bastante interesante de las especificaciones; DMS se construye en gran medida utilizándose para generar su implementación. Eso nos ha permitido al menos parte de la promesa de reutilización (conocimiento): ganancias de productividad extremadamente significativas. Tengo un equipo de aproximadamente 7 personas técnicas; probablemente hemos escrito 1-2 MSLOC de "especificaciones" para DMS, pero tenemos unos 10MSLOC de código generado.
Resumen: la reutilización del conocimiento de generación es la victoria, no la reutilización del código .
fuente
Mostly what has been discovered over the years is that for code to be reusable, it sort of has to be designed for that purpose, or it contains too many implicit assumptions.
Llegué a una conclusión similar, pero no pude expresarlo de manera tan sucinta.La reutilización del código se logra en OOP pero también se logra en la programación funcional. Cada vez que toma un bloque de código y lo hace invocable por el resto de su código para que pueda usar esta funcionalidad en otro lugar, es la reutilización del código.
Este tipo de reutilización de código también hace que el código sea más manejable porque cambiar este bloque invocable cambia todos los lugares a los que se llama. Yo diría que este resultado también aumentó la calidad y la legibilidad.
No estoy seguro de que OOP simplemente esté allí para proporcionar la reutilización del código. Miro a OOP como una forma más de interactuar con objetos y abstraer los detalles de la estructura de datos.
De Wikpedia:
fuente
double sqrt (double x)
? Las funciones puras son el arquetipo de la reutilización.double sqrt(double x)
,float sqrt(float x)
,int sqrt(int x)
es posible definir un montón de ellos, mientras que con un lenguaje de programación genérica que tendríaNumber sqrt(Number x)
y hacer con ella.Si y no
La reutilización de código es un término general para muchas actividades diferentes.
fuente
Publicaría una respuesta larga pero ¿por qué? Udi Dahan lo explica mucho mejor que yo.
http://www.udidahan.com/2009/06/07/the-fallacy-of-reuse/
Aquí está el comienzo de la publicación:
fuente
Estoy de acuerdo con Chris, la programación funcional es una buena manera de reutilizar el código.
Muchos programas tienen estructuras de código que son recurrentes. Para esto , se utilizan algunos patrones de diseño en el mundo OOP, pero esto se puede lograr mediante funciones recursivas y coincidencia de patrones en lenguajes de programación funcionales. Para obtener más información al respecto, consulte el primer capítulo de Programación funcional del mundo real .
Creo que la herencia profunda en OOP puede ser engañosa en muchos casos. Tiene una clase y muchos de los métodos estrechamente relacionados se implementan en diferentes archivos. Como Joe Armstrong dijo sobre OOP:
Las funciones de alto orden también son muy útiles cuando se trata de la reutilización de código, por ejemplo,
map
yfoldr
esa es la base de MapReduce de Google .El paso de mensajes asincrónicos también es una buena manera de organizar un software complejo, y algunos científicos informáticos afirman que se suponía que los objetos se comunicaban entre sí de manera asincrónica como en el principio Tell, no pregunte a OOP. Vea más sobre esto en Programación Orientada a Objetos: ¿El camino equivocado? donde se cita a Joe Armstrong :
La transmisión de mensajes asincrónicos como en sistemas controlados por eventos y en Erlang también es una muy buena manera de desacoplar sistemas y el acoplamiento flexible es importante en sistemas complejos. Con un sistema suficientemente desacoplado, puede evolucionar el sistema mientras se está ejecutando, tal vez en diferentes nodos. Unibet hizo una gran presentación sobre esto: Arquitectura dirigida por eventos de dominio
Sin embargo, creo que la mayor parte de la reutilización del código se realiza mediante bibliotecas y marcos.
fuente
La humilde tubería de Unix ha hecho más por la reutilización de código que cualquier otra cosa que haya aparecido y desaparecido. Los objetos resultaron ser una forma intuitiva de estructurar el código cuando aparecieron y luego la gente comenzó a agregarle cualquier cosa y todo. En general, los objetos son para encapsulación y no para reutilización de código, la reutilización de código requiere algo más y la jerarquía de herencia de clase es un sustituto pobre de lo que realmente debería ser un mecanismo de reutilización de código.
fuente
OOP no es especial; puede hacer código reutilizable con o sin OOP. Las funciones puras son particularmente reutilizables : por ejemplo,
java.lang.math.sqrt(double)
toma un número y da un número. Sin POO, pero definitivamente más reutilizable que la mayoría de los códigos existentes.fuente
Desde una vista de programación funcional, OOP se trata principalmente de administrar el estado.
En la programación funcional, puede tener fácilmente cientos de funciones útiles para las listas: http://haskell.org/ghc/docs/6.12.1/html/libraries/base-4.2.0.0/Data-List.html .
¿Tendría cientos de métodos en una clase de lista? Los métodos públicos se consideran una interfaz con el estado interno que desea mantener pequeño.
Lamentablemente, en lugar de (re) usar muchas funciones pequeñas, algunas personas duplican la funcionalidad. Para mí eso se debe a que OOP no fomenta la reutilización del código tanto como lo hace la programación funcional.
fuente
Para mí, sí, pero no todo el tiempo, y podría haberse hecho de otras maneras.
La mayoría de las veces creando una clase base abstracta y creando implementaciones concretas de esa clase.
También muchos marcos hacen uso de la herencia para proporcionar la reutilización del código (Delphi, Java, .Net son solo algunos que se me ocurren al instante).
Eso no quiere decir que muchas bibliotecas de utilidades y fragmentos de código no podrían haber hecho el trabajo también, pero hay algo agradable en una jerarquía de objetos bien diseñada.
fuente
En mi experiencia, he tenido más éxito aprovechando el código "reutilizable" a través de recursos de programación genéricos (como plantillas de C ++) que el que he tenido usando principios de OOP como jerarquías de herencia.
fuente
OOP está demasiado abierto para una reutilización efectiva.
Hay demasiadas formas de reutilizar. Cada clase pública pregunta: "¡crea una nueva instancia de mí!" , cada método público dice: "¡llámame!" , cada método protegido produce: "¡anularme!" - y todas estas formas de reutilización son diferentes , tienen diferentes parámetros, aparecen en diferentes contextos, todos tienen sus diferentes reglas, cómo llamarlo / extenderlo / anularlo.
La API es mejor, es un subconjunto estricto de puntos OOP (o no-oop), pero en la vida real, las API están sobrevaloradas y crecen para siempre, todavía hay demasiados puntos de conexión. Además, una buena API puede facilitar la vida, es la mejor manera de proporcionar una interfaz para OOP.
El paradigma Datadlow proporciona una interfaz estricta para los componentes, tienen puertos de los siguientes tipos:
Dependiendo del dominio, hay algunos tipos de paquetes, por lo que los consumidores y productores pueden conectarse si tienen los mismos puertos (o compatibles). La parte más hermosa de esto, que puede hacerse visualmente, porque no hay parámetros ni ajustes adicionales en las conexiones, realmente solo conectan a un consumidor y un productor.
No estaba claro, puede echar un vistazo a la etiqueta "flujo de datos" en StackOverflow , o "programación de flujo de datos" de Wikipedia o "programación basada en flujo" de Wikipedia .
(Además, he escrito un sistema de flujo de datos, en C ++. Entonces, OOP y DF no son enemigos, DF es una forma de organización de nivel superior).
fuente
En CommonLisp hay muchos medios para lograr la reutilización:
escritura dinámica, haciendo que su código sea genérico por defecto
abstracciones imperativas, es decir, subrutinas
orientación a objetos, con herencia múltiple y despacho múltiple
abstracción de sintaxis, la capacidad de definir nuevas construcciones sintácticas o abreviar código de placa de caldera
abstracciones funcionales, cierres y funciones de alto orden
Si intenta comparar la experiencia de CommonLisp con otros lenguajes, verá que la característica principal que facilita la reutilización del código es la presencia de abstracciones tanto orientadas a objetos como funcionales. Son más complementarios que alternativos: sin uno de ellos, se ve obligado a volver a implementar las características que faltan de una manera torpe. Vea, por ejemplo, las clases de functor utilizadas como cierres y coincidencia de patrones para obtener el envío de métodos no extensibles.
fuente
- Kevlin Henney
fuente
Voy a arriesgarme a ridiculizar y confesar, solo he estado usando OOP muy recientemente. No viene a mí automáticamente. La mayor parte de mi experiencia involucra bases de datos relacionales, así que pienso en tablas y combinaciones. Hay afirmaciones de que es mejor aprenderlo desde el principio, lo que evita tener que reconectar su pensamiento a la hora de programar. No tengo ese lujo y me niego a desechar mi carrera por alguna teoría de la torre de marfil. Como todo lo demás, lo resolveré.
Al principio pensé que todo el concepto no tenía sentido. Simplemente parecía innecesario y demasiados problemas. Lo sé, esto es una locura. Obviamente, se necesita un cierto nivel de comprensión antes de poder apreciar los beneficios de algo o descartarlo por mejores métodos.
La reutilización del código requiere la voluntad de no repetir el código, la comprensión de cómo lograrlo, la planificación inicial. ¿Debería evitar reutilizar el código cuando haya decidido que tiene un caso en el que simplemente no vale la pena? Y ningún lenguaje es tan estrictamente OO que arroje un error cuando piense que debería haber heredado el código de otra clase. En el mejor de los casos, proporcionan un entorno propicio para implementarlo.
Creo que el mayor beneficio de OOP es la aceptación general de cómo se debe organizar el código. Todo lo demás es salsa. Un equipo de programadores puede no estar totalmente de acuerdo sobre cómo deberían estructurarse todas las clases, pero deberían poder encontrar el código.
He visto suficiente código de procedimiento para saber que podría estar en cualquier lugar, y a veces está en todas partes.
fuente
OOP le ofrece más formas de reutilizar el código. Eso es todo.
fuente
Reutilización horizontal: aspectos, rasgos, injertos.
Classic OO a veces se queda corto en la reutilización de código, especialmente cuando te vuelves loco por la falta de una mejor manera de compartir la funcionalidad real entre las clases. Para este problema, se han creado mecanismos de reutilización horizontal, como AOP, rasgos e injertos.
Programación Orientada a Aspectos
Considero AOP como la mitad naranja que falta de OOP. AOP no es realmente tan conocido, pero ha llegado al código de producción.
Trataré de explicarlo en términos simples: imagine que puede inyectar y filtrar la funcionalidad con una estructura especial llamada aspecto, estos aspectos tienen "métodos" que definen qué y cómo se verá afectado a través de la reflexión , pero en el momento de la compilación Este proceso se llama tejido .
Un ejemplo sería un aspecto que dice "para todos los métodos de ciertas clases que comienzan con get, su programa escribirá en un archivo de registro los datos que se obtuvieron y el momento en que se obtuvieron".
Mire estas dos charlas si quiere entender mejor el AOP:
Rasgos e injertos
Los rasgos son otro constructo para definir el código reutilizable que complementa a OOP, son similares a los mixins , pero más limpios.
En lugar de explicarlos, hay un gran PHP RFC que explica ambos . Los rasgos están llegando a PHP por cierto, ya están comprometidos con el tronco.
En resumen
OOP es clave en la modularidad, aún, en mi opinión y como lo conocemos hoy en día, OOP todavía está incompleto .
fuente
OOP Proporciona un conjunto de herramientas útiles que le permiten escribir código que puede usarse en más lugares de los que podría tener sin esas herramientas. Si escribe una
PrintIt
función que toma cualquier objeto antiguo y lo llama.toString()
, habrá reutilizado ese código tan pronto como lo llame con más de un tipo de objeto. Con estas herramientas, cada línea de código hace más.La programación funcional es muy popular en este momento entre los hipsters. Le proporciona un conjunto de herramientas completamente separado para que cada línea de código haga más. Probablemente no sea mejor o no funcione, pero proporciona otra herramienta en la caja de herramientas.
(Había una idea loca para un nivel adicional de reutilización orientada a objetos: la idea era que pudiéramos definir una sola
Customer
clase y usarla en cada aplicación que escribimos. Entonces las aplicaciones serían un poco de pegamento aquí y allá. Esto no funcionó. Pero eso no significa que el OO falló, o incluso que la reutilización falló. Los tipos básicos de reutilización de código dentro de las aplicaciones hicieron posible escribir aplicaciones que hicieron más y escribirlas más rápido).fuente
Leyendo las publicaciones anteriores, algunas observaciones:
fuente
El problema es más sutil en mi humilde opinión:
Por lo tanto, OOP en sí mismo no es malo desde el punto de vista de hacer código reutilizable , pero los tipos de código que se escriben usando OOP son intrínsecamente difíciles de reutilizar .
Además, la programación funcional puede dar como resultado un código más reutilizable . Pero obtener las abstracciones correctas para escribir un código funcional sensato mientras se cumple un plazo puede no ser factible. Y las abstracciones de "mitad derecha" serán más fáciles de expresar al estilo OOP. Y no tenderá a resultar en un código más fácil de reutilizar : un mayor nivel de abstracciones significa que la comprensión del código requerirá una mayor inversión inicial de la capacidad cognitiva limitada de los programadores.
Como ejemplo práctico: el código del juego implica mucho estado mutable, porque esta es la forma natural de pensar en la codificación de un juego, a menos que sea un rompecabezas / algoritmo, por lo que obviamente termina siendo estructurado usando OO. Y, por supuesto, es difícil de reutilizar. Pero el mismo código, que contiene el mismo conocimiento, sería aún más difícil de reutilizar sin OOP . Y reescribirlo para que sea un estilo funcional podría necesitar cambiar totalmente la forma en que piensas sobre ese código, el conocimiento detrás de él. Sí, el conocimiento resultante detrás del código sería mucho más claro después de la reescritura de OO a FP tal vez ... pero el costo podría ser enorme y podría serel tipo de costo que también tendrían que pagar las personas que deseen reutilizar el código increíblemente inteligente y bien abstraído con el que terminan , por lo que, paradójicamente, las personas terminarían sin reutilizar el código, incluso si técnicamente es más reutilizable.
... lo que lleva a la última sutileza: la reutilización del código se trata de la interfaz People | Code , no solo del código. OOP hace un trabajo decente al servir esta interfaz porque se correlaciona bien con cuántas personas piensan acerca de muchos tipos de código escritos hoy en día. FP podría ser mejor para la reutilización de código, pero en mi opinión, no para reutilizar fácilmente el tipo de código que la gente realmente necesita escribir hoy en día. Esto cambiará a medida que cambie el tipo de código que necesitamos para escribir.
PD Y si alguien quiere decir que "OO no se trata de estado mutable, también puede tener OO con estado inmutable" ... Yo llamo a eso "FP usando clases como espacios de nombres". Es excelente cuando funciona para usted y evita algunas deficiencias de los sistemas de módulos de algunos idiomas y puede dar como resultado un código más reutilizable. Pero eso no es OO;)
fuente