He escuchado la frase arrojándose y para mí los argumentos suenan completamente locos (lo siento si estoy dando vueltas aquí, no es mi intención), generalmente va algo en la línea de:
No desea crear una abstracción antes de saber cuál es el caso general, de lo contrario (1) podría estar poniendo cosas en sus abstracciones que no pertenecen, u (2) omitiendo cosas importantes.
(1) Para mí, esto suena como que el programador no está siendo lo suficientemente pragmático, han asumido que las cosas existirían en el programa final que no existe, por lo que están trabajando con un nivel de abstracción bajo, el problema no es abstracción prematura, es concreción prematura.
(2) Omitir cosas importantes es una cosa, es completamente posible que se omita algo de la especificación que luego resulta ser importante, la solución a esto no es crear su propia concreción y desperdiciar recursos cuando se entera de que adivinado mal, es para obtener más información del cliente.
Siempre deberíamos trabajar desde las abstracciones hasta las concreciones, ya que esta es la forma más pragmática de hacer las cosas, y no al revés.
Si no lo hacemos, corremos el riesgo de malinterpretar a los clientes y crear cosas que necesitan ser cambiadas, pero si solo construimos las abstracciones que los clientes han definido en su propio idioma, nunca correremos el riesgo (al menos ni tan cerca como tomar un tiro en la oscuridad con cierta concreción), sí, es posible que los clientes cambien de opinión sobre los detalles, pero las abstracciones que solían comunicar originalmente lo que quieren tienden a ser válidas.
Aquí hay un ejemplo, digamos que un cliente desea que cree un robot de ensacado de artículos:
public abstract class BaggingRobot() {
private Collection<Item> items;
public abstract void bag(Item item);
}
Estamos construyendo algo a partir de las abstracciones que el cliente usó sin entrar en más detalles con cosas que no sabemos. Esto es extremadamente flexible, he visto que esto se llama "abstracción prematura" cuando en realidad sería más prematuro suponer cómo se implementó el ensacado, digamos después de discutir con el cliente que quieren que se empaquete más de un artículo a la vez . Para actualizar mi clase, todo lo que necesito es cambiar la firma, pero para alguien que comenzó desde abajo, eso podría implicar una gran revisión del sistema.
No existe la abstracción prematura, solo la concreción prematura. ¿Qué hay de malo en esta declaración? ¿Dónde están los defectos en mi razonamiento? Gracias.
Respuestas:
Al menos en mi opinión, la abstracción prematura es bastante común, y fue especialmente tan temprana en la historia de la POO.
Al menos por lo que vi, el principal problema que surgió fue que la gente leía los ejemplos típicos de jerarquías orientadas a objetos. Se les dijo mucho acerca de preparar todo para enfrentar los cambios futuros que pudieran surgir (a pesar de que no había una razón particularmente buena para creer que lo harían). Otro tema común a muchos artículos durante un tiempo fue cosas como el ornitorrinco, que desafía las reglas simples sobre "los mamíferos son así" o "las aves son así".
Como resultado, terminamos con un código que realmente solo necesitaba tratar con, digamos, registros de empleados, pero que fueron escritos cuidadosamente para estar listos si alguna vez contrataste un arácnido o tal vez un crustáceo.
fuente
Es importante recordar que la abstracción es un medio para un fin. Utiliza la abstracción para uniformar el comportamiento en todo el programa y hace que la adición de nuevas clases sea sencilla en los casos en que esperas que se agreguen nuevas clases, pero solo cuando la abstracción es necesaria en ese mismo momento.
No agregaría la abstracción simplemente porque podría necesitarla (sin una base real para pensar que necesitará agregar nuevas clases en el futuro). Una metáfora adecuada aquí podría ser la fontanería. Esperemos que acepte que una tubería de 6 direcciones que permita que el agua fluya hacia arriba / abajo, este / oeste, norte / sur sería el tipo de tubería más flexible que podría tener. Teóricamente, podría usar una tubería de 6 direcciones en cualquier lugar donde se requiera una tubería y bloquear las direcciones innecesarias, ¿verdad?
Si trató de solucionar un problema con una fuga debajo de su fregadero y descubrió que todas las secciones de la tubería eran piezas de tubería de 6 direcciones, querría arrancarse el cabello frustrado ante el tipo que lo diseñó de esa manera. No solo no sabe dónde está el problema, sino que seguramente sería más sencillo comenzar desde cero de la manera adecuada.
Por supuesto, la codificación no es fontanería, pero la metáfora sigue en pie. La abstracción es como usar esas piezas de tubería de 6 direcciones. Úselos cuando honestamente cree que algún día en un futuro cercano necesitará conectar tuberías desde las 6 direcciones. De lo contrario, la abstracción es simplemente una complicación, no muy diferente a usar un patrón donde no se requiere ninguno o usar una clase de dios que intenta hacer todo. Si no se está utilizando, y probablemente nunca se utilizará, finalmente está agregando una clase adicional para nada.
Es cierto que el arte de escribir programas es muy abstracto conceptualmente. Simplemente vale la pena mencionar que las abstracciones no existen por el simple hecho de ser una abstracción sino porque son prácticas de alguna manera real. Si siente la necesidad de utilizar la abstracción, que así sea, pero no me pida que revise sus tuberías después. ;)
fuente
class
excéntrico ... Incluso si hay muchas clases, la abstracción no se limita a ser utilizada en beneficio de ellas.Cuando aprendí acerca del Análisis y Diseño Orientado a Objetos, hace muchos años, comenzamos con una descripción sencilla en inglés del sistema que el cliente necesitaba.
Mirando a través de eso, cualquier sustantivo (o frase nominal) se consideraría como una posible clase. Cualquier verbo (o frase verbal) sería un método potencial en las clases. Así que "robot de ensacado" podría ser una clase
BaggingRobot
. "Abrir una bolsa" podría convertirse en un métodoOpenBag
.Después de algunas iteraciones, esto se convertiría en un diagrama de clase.
En este punto, no hay clases abstractas. El cliente no quiere un concepto abstracto de robot de ensacado. Quieren un robot que ponga cosas en bolsas. Todas las clases son concretas y tienen un conjunto de métodos.
Las clases abstractas solo se introducen cuando queda claro que:
Para mí, la "abstracción prematura" es asumir que alguien
BaggingRobot
debe heredar de algunosBaseRobot
y, lo que es peor, tratar de desarrollar un conjunto de métodosBaseRobot
antes incluso de saber qué es común a todos los robots.fuente
Parece un poco como si quisiera resolver un problema que aún no existe, y que no tiene una buena razón para suponer que ocurrirá, a menos que solo crea que el cliente está equivocado en lo que está solicitando. Si ese es el caso, recomendaría más comunicación sobre la implementación de una solución de conjetura, abstracta o de otro tipo. Si bien puede parecer inocuo simplemente poner "abstracto" en la definición de la clase y sentirse seguro sabiendo que puede extenderlo más tarde, es posible que nunca lo necesite, o puede que lo extienda de maneras que complican demasiado el diseño la línea, al abstraer las cosas equivocadas.
Siguiendo con su ejemplo, ¿imagina que es el robot en sí mismo , los artículos que se están empacando o el método de embolsado que cambiará en la línea?
La abstracción prematura realmente solo significa que no tiene una buena razón para realizar la abstracción y, dado que las abstracciones están lejos de ser gratuitas en muchos idiomas, puede incurrir en gastos generales sin justificación.
Editar Para responder algunos puntos de OP en los comentarios, estoy actualizando esto para aclarar y responder de una manera que no requiera una larga cadena de comentarios al abordar los puntos (1) y (2) más específicamente.
(El énfasis es mío). Asumir que las cosas existirían en el programa final que no es exactamente lo que veo en su ejemplo. El cliente solicitó un robot para embolsar artículos. Esta es una solicitud muy específica, aunque algo vaga en su lenguaje. El cliente quiere un robot que empaque los artículos, por lo que produce un par de objetos
Su modelo es simple y preciso, sigue los requisitos establecidos por el cliente sin agregar complejidad a la solución y sin suponer que el cliente desea más de lo que pidió. Si, cuando se le presenta esto, aclaran la necesidad de que el robot tenga una mecánica de ensacado intercambiable, solo entonces tiene suficiente información para justificar la creación de una interfaz u otro método de abstracción, ya que ahora puede señalar un valor específico que se agrega a El sistema a través de la abstracción.
Por el contrario, si comienza con la abstracción del pragmatismo puro, pasa el tiempo creando una interfaz separada e implementándola en una concreción, o crea una clase abstracta, o la forma de abstracción que desee. Si luego resulta que el cliente está satisfecho con esto, y no es necesaria una extensión adicional, ha gastado tiempo y recursos en vano y / o ha introducido gastos generales y complejidad en el sistema sin ningún beneficio.
En lo que respecta a (2), estoy de acuerdo en que omitir cosas importantes no es en sí mismo un sello distintivo de abstracción prematura. Abstracción o no, puede omitir algo de importancia y, a menos que se encuentre muy por debajo de la línea de una cadena de abstracción, no será más difícil ni más fácil resolverlo de ninguna manera.
En su lugar , interpretaría que eso significa que cualquier abstracción corre el riesgo de ofuscar su modelo de dominio. La abstracción incorrecta puede hacer que un sistema sea muy difícil de razonar, ya que está creando relaciones que pueden afectar drásticamente el mayor crecimiento del modelo de dominio y la comprensión del dominio. Corre el riesgo de omitir información no importante sobre lo que se está abstrayendo , sino sobre el sistema en su conjunto , al llevar su modelo por el agujero de conejo equivocado.
fuente