¿Qué es la "abstracción prematura"?

10

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.

James
fuente
1
Lo opuesto a la abstracción prematura es YAGNI : no lo vas a necesitar, lo que en mi opinión casi siempre está mal. Casi. Lo he visto suceder, pero es raro. Principalmente estoy de acuerdo con lo que estás diciendo aquí.
user1118321

Respuestas:

19

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.

Jerry Coffin
fuente
Entonces, la abstracción prematura no es el acto de abstraer, es el acto de abstraer más allá del nivel de abstracción de las especificaciones. Eso tiene mucho más sentido, y pude ver que realmente está sucediendo. Supongo que solo necesito aclararles a mis colegas que estoy trabajando al nivel de abstracción descrito por mi gerente.
James
1
@James: también puede significar abstraer "demasiado" detrás de las especificaciones de la versión 1.0, ya que cree que conoce un nuevo requisito en la especificación de una versión posterior, por lo tanto, ya implementa v1.0 de una manera más general que necesario. Algunas cosas, es bueno imaginar lo que podría suceder en una versión posterior, pero también existe un cierto riesgo de ingeniería excesiva.
Doc Brown
@DocBrown Yo llamaría a eso concreción prematura. El acto de abstracción es eliminar piezas de información, no agregarlas. Si está agregando más a la abstracción de lo necesario, entonces está asumiendo algo sobre niveles más bajos de abstracción. Me gustaría diferenciar entre los dos, ya que creo que llamar a eso "abstracción" no tiene mucho sentido ya que la definición de abstracción es "el proceso de extracción de la esencia subyacente" Donde la concreción se caracteriza o pertenece a la experiencia inmediata. de cosas o eventos reales ".
James
6

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. ;)

Neil
fuente
Parece un poco classexcéntrico ... Incluso si hay muchas clases, la abstracción no se limita a ser utilizada en beneficio de ellas.
Deduplicador
1
@Dupuplicator Lo suficientemente justo, pero eso no cambia mi punto. Si se utiliza la abstracción, debería ser inmediatamente beneficiosa o debería ser un cambio planificado en un futuro próximo. No importa que nos estamos refiriendo a clases o programación funcional.
Neil
3

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étodo OpenBag.

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:

  • Hay varias clases similares que podrían formar una jerarquía.
  • En realidad, comparten algo en común, de modo que una clase base realiza un propósito útil.

Para mí, la "abstracción prematura" es asumir que alguien BaggingRobot debe heredar de algunos BaseRoboty, lo que es peor, tratar de desarrollar un conjunto de métodos BaseRobotantes incluso de saber qué es común a todos los robots.

Simon B
fuente
La abstracción no es sinónimo de clases abstractas. Una interfaz es una abstracción. Estoy hablando de abstracciones en general, no solo de clases abstractas. Quizás podría haberlo aclarado usando una interfaz. Si desarrolla su sistema en la misma capa de abstracción que su cliente, entonces es probable que termine con algunas clases abstractas que deben ampliarse ya que el lenguaje es naturalmente abstracto. Trabajar más bajo que eso es lo que yo llamo "concreción prematura", donde ingenuamente asumes que las ideas de los clientes sobre cómo funcionará el sistema son las mismas que las tuyas.
James
Un objeto BaggingRobot que coloca objetos Item en objetos Bag ya es una abstracción de un robot de ensacado real que coloca cosas en bolsas.
user253751
1

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.

(1) Para mí, esto parece 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.

(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

public class Item {
/* Relevant item attributes as specified by customer */
}
public class BaggingRobot {
  private Collection<Item> items;

  public void bag(Item item);
}

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.

JimJam
fuente
"Parece un poco como si quisieras resolver un problema que aún no existe, y que no tienes una buena razón para suponer que ocurrirá, a menos que solo creas que el cliente está equivocado en lo que está solicitando". - Esto no es en absoluto lo que dije, de hecho, dejé en claro que solo estaba construyendo en base a las palabras que usaba el cliente. Es el acto de no querer hacer esto lo que me llevó a usar abstracciones.
James
"Recomendaría más comunicación en lugar de implementar una solución de conjetura" - ¿Quieres decir como sugerí? Para citar lo que dije en OP "la solución a esto no es crear su propia concreción y desperdiciar recursos cuando descubra que adivinó mal, es obtener más información del cliente".
James
"Si bien puede parecer inocuo simplemente poner 'resumen' en la definición de clase y sentirse seguro sabiendo que puede extenderlo más tarde" - Cuando digo "abstracción" quiero decir "abstracción" no me refiero a "palabra clave abstracta". Las interfaces pueden ser abstracciones, las abstracciones son una lógica difusa, de eso está hablando toda esta publicación. El cliente se está comunicando en términos de abstracciones, por lo que debemos programar en términos abstractos hasta que sepamos más sobre el dominio.
James
1
"es posible que nunca necesites": esto no tiene ningún sentido. Un cliente dice "Quiero un robot que empaque artículos", usted crea una abstracción que cumple con ese criterio. Cualquier información adicional que obtenga del cliente será información detallada sobre cómo desea que se realice el ensacado. Esto no invalida su abstracción, el cliente no cambia repentinamente de opinión acerca de una idea central detrás de lo que está comprando. El robot todavía va a empacar artículos. La abstracción que creaste aún se aplicará.
James
"o puede que se encuentre extendiéndolo de formas que complican demasiado el diseño en el futuro, al abstraer las cosas incorrectas" ... ¿Leyó honestamente lo que dije o simplemente el título? ¿Seriamente? Leer punto (1) y (2)
James