¿Significado de la abstracción con fugas?

89

¿Qué significa el término "abstracción con fugas"? (Explique con ejemplos. A menudo me cuesta asimilar una mera teoría).

Geonne
fuente
posible duplicado de interfaces
Fluent
14
Es posible que desee leer el artículo original de Joel Spolsky The Law of Leaky Abstractions que, hasta donde yo sé, es el origen del término.
Daniel Pryden
1
La mayoría de las respuestas del engaño propuesto se refieren a interfaces fluidas.
David Thornley
@David: La segunda publicación más votada responde lo que significa la abstracción con fugas, y con un gran ejemplo.
missingfaktor
4
Cuando buscas en Google esta pregunta 4 años después, es difícil adivinar qué publicación solía ser la segunda más votada.
John Reynolds

Respuestas:

105

Aquí hay un ejemplo de espacio de carne :

Los automóviles tienen abstracciones para los conductores. En su forma más pura, hay volante, acelerador y freno. Esta abstracción esconde muchos detalles sobre lo que hay debajo del capó: motor, levas, correa de distribución, bujías, radiador, etc.

Lo bueno de esta abstracción es que podemos reemplazar partes de la implementación con partes mejoradas sin volver a capacitar al usuario. Digamos que reemplazamos la tapa del distribuidor con encendido electrónico, y reemplazamos la leva fija con una leva variable. Estos cambios mejoran el rendimiento, pero el usuario sigue conduciendo con el volante y utiliza los pedales para arrancar y parar.

En realidad, es bastante notable ... ¡un joven de 16 u 80 años puede operar esta complicada pieza de maquinaria sin saber realmente mucho sobre cómo funciona por dentro!

Pero hay fugas. La transmisión es una pequeña fuga. En una transmisión automática, puede sentir que el automóvil pierde potencia por un momento cuando cambia de marcha, mientras que en CVT siente un par suave hasta el final.

También hay fugas más grandes. Si acelera el motor demasiado rápido, puede dañarlo. Si el bloque del motor está demasiado frío, es posible que el automóvil no arranque o que tenga un rendimiento deficiente. Y si enciende la radio, los faros y el aire acondicionado al mismo tiempo, verá disminuir el rendimiento de la gasolina.

Mark E. Haase
fuente
7
Gracias por el ejemplo. Nadie más parecía ser capaz de dar una explicación sencilla.
Sebastian Patten
7
Esta es una gran respuesta, especialmente porque demuestra el punto de vista del usuario, que es de lo que se trata la versión del software.
Chad
1
¿Qué significa meatspace? ¿Explicación laica?
brumScouse
1
@brumScouse "meatspace" significa el mundo físico y fuera de línea. Se utiliza para contrastar con el mundo ciberespacial en línea. Editaré mi respuesta para incluir un enlace a la definición.
Mark E. Haase
1
Me gusta cómo esta publicación señala que "todavía hay filtraciones". Se trata de minimizarlos.
alaboudi
51

Simplemente significa que su abstracción expone algunos de los detalles de la implementación, o que debe conocer los detalles de la implementación cuando utilice la abstracción. El término se atribuye a Joel Spolsky , alrededor de 2002. Consulte el artículo de wikipedia para obtener más información.

Un ejemplo clásico son las bibliotecas de red que le permiten tratar archivos remotos como locales. El desarrollador que utilice esta abstracción debe ser consciente de que los problemas de red pueden hacer que esto falle en formas que los archivos locales no lo hacen. Luego, debe desarrollar código para manejar específicamente errores fuera de la abstracción que proporciona la biblioteca de red.

tvanfosson
fuente
7
@mehaase No veo qué importa si su abstracción tiene fugas por diseño o por negligencia. He ampliado la respuesta con un ejemplo y más información del artículo de referencia para que pueda sostenerse por sí solo. Además, no creo que la "abstracción con fugas" deba ser necesariamente un peyorativo. Para mí, simplemente describe una situación en la que usted, como desarrollador, debe tener más cuidado al trabajar con la abstracción. El diseño puede ser bueno, malo o indiferente independientemente de las "fugas".
tvanfosson
13

Wikipedia tiene una definición bastante buena para esto.

Una abstracción con fugas se refiere a cualquier abstracción implementada, destinada a reducir (u ocultar) la complejidad, donde los detalles subyacentes no están completamente ocultos

O en otras palabras, para el software es cuando puede observar los detalles de implementación de una función a través de limitaciones o efectos secundarios en el programa.

Un ejemplo rápido serían los cierres de C # / VB.Net y su incapacidad para capturar parámetros de referencia / salida. La razón por la que no se pueden capturar se debe a un detalle de implementación de cómo se produce el proceso de elevación. Sin embargo, esto no quiere decir que haya una mejor manera de hacerlo.

JaredPar
fuente
13

Aquí hay un ejemplo familiar para los desarrolladores de .NET: la Pageclase de ASP.NET intenta ocultar los detalles de las operaciones HTTP, particularmente la gestión de los datos del formulario, para que los desarrolladores no tengan que lidiar con los valores publicados (porque asigna automáticamente los valores del formulario al servidor control S).

Pero si va más allá de los escenarios de uso más básicos, la Pageabstracción comienza a filtrarse y se vuelve difícil trabajar con páginas a menos que comprenda los detalles de implementación de la clase.

Un ejemplo común es agregar controles dinámicamente a una página: el valor de los controles agregados dinámicamente no se asignará a menos que los agregue en el momento adecuado : antes de que el motor subyacente asigne los valores del formulario entrante a los controles apropiados. Cuando tienes que aprender eso, la abstracción se ha filtrado .

Jeff Sternal
fuente
Webforms tenía un fondo en su cubo. Lo peor fue que las abstracciones apenas veladas equivalían a trabajar con Http como si estuvieras trabajando en una guantera.
brumScouse
9

Bueno, en cierto modo es una cosa puramente teórica, aunque no sin importancia.

Usamos abstracciones para hacer las cosas más fáciles de comprender. Puedo operar en una clase de cadena en algún idioma para ocultar el hecho de que estoy tratando con un conjunto ordenado de caracteres que son elementos individuales. Me ocupo de un conjunto ordenado de caracteres para ocultar el hecho de que estoy tratando con números. Me ocupo de los números para ocultar el hecho de que estoy tratando con unos y ceros.

Una abstracción con fugas es aquella que no oculta los detalles que pretende ocultar. Si llama a string.Length en una cadena de 5 caracteres en Java o .NET, podría obtener cualquier respuesta de 5 a 10, debido a los detalles de implementación donde esos lenguajes llaman caracteres son realmente puntos de datos UTF-16 que pueden representar 1 o .5 de un personaje. La abstracción se ha filtrado. Sin embargo, no filtrarlo significa que encontrar la longitud requeriría más espacio de almacenamiento (para almacenar la longitud real) o cambiaría de O (1) a O (n) (para calcular cuál es la longitud real). Si me importa la respuesta real (a menudo a usted realmente no le importa), debe trabajar en el conocimiento de lo que realmente está sucediendo.

Los casos más discutibles ocurren con casos como en los que un método o propiedad le permite entrar en el funcionamiento interno, ya sean fugas de abstracción o formas bien definidas de pasar a un nivel más bajo de abstracción, a veces puede ser un asunto en el que la gente no está de acuerdo.

Jon Hanna
fuente
2
Y trabajas con 1 y 0 para ocultar el hecho de que estás trabajando con electrónica y física (comentario muy tardío, lo sé)
Davy8
7

Continuaré en la línea de dar ejemplos utilizando RPC.

En el mundo ideal de RPC, una llamada a procedimiento remoto debería verse como una llamada a procedimiento local (o eso dice la historia). Debe ser completamente transparente para el programador, de manera que cuando llamen SomeObject.someFunction()no tengan idea de si SomeObject(o simplemente someFunctionpara el caso) se almacenan y ejecutan localmente o se almacenan y ejecutan de forma remota. La teoría dice que esto simplifica la programación.

La realidad es diferente porque hay una GRAN diferencia entre hacer una llamada de función local (incluso si está utilizando el lenguaje interpretado más lento del mundo) y:

  • llamar a través de un objeto proxy
  • serializando sus parámetros
  • hacer una conexión de red (si aún no está establecida)
  • transmitir los datos al proxy remoto
  • hacer que el proxy remoto restaure los datos y llame a la función remota en su nombre
  • serializar los valores de retorno
  • transmitir los valores de retorno al proxy local
  • reensamblaje de los datos serializados
  • devolver la respuesta de la función remota

Solo en el tiempo, eso es aproximadamente tres órdenes (¡o más!) De diferencia de magnitud. Esos tres + órdenes de magnitud van a marcar una gran diferencia en el rendimiento que hará que su abstracción de una llamada a procedimiento se filtre de forma bastante obvia la primera vez que trate por error un RPC como una llamada de función real. Además, una llamada de función real, salvo problemas graves en su código, tendrá muy pocos puntos de falla fuera de los errores de implementación. Una llamada RPC tiene todos los siguientes problemas posibles que se incluirán como casos de falla más allá de lo que esperaría de una llamada local normal:

  • es posible que no pueda crear una instancia de su proxy local
  • es posible que no pueda crear una instancia de su proxy remoto
  • Es posible que los proxies no puedan conectarse
  • Es posible que los parámetros que envíe no lo hagan intacto o en absoluto
  • el valor de retorno que envía el control remoto puede no hacerlo intacto o en absoluto

Así que ahora su llamada RPC, que es "como una llamada de función local", tiene un montón de condiciones de falla adicionales con las que no tiene que lidiar cuando hace llamadas a funciones locales. La abstracción se ha vuelto a filtrar, incluso con más fuerza.

Al final, RPC es una mala abstracción porque gotea como un tamiz en todos los niveles, cuando tiene éxito y cuando falla en ambos.

SOLO MI CORRECTA OPINIÓN
fuente
<pimp> Me gusta más el enfoque de Erlang para esto, ya que no trata de ocultar la diferencia entre una llamada a una función y el envío de un mensaje a un proceso hasta el punto de que los dos usan una sintaxis muy diferente. Y el envío de un mensaje de proceso remoto es visiblemente diferente de un envío de proceso local, aunque usa la misma sintaxis general. </pimp>
SOLO MI OPINIÓN correcta
2
Bueno, esta es la única respuesta que realmente da un buen ejemplo (comprensión de lectura, amigos), por lo que obtiene mi +1.
Mark E. Haase
4

Un ejemplo en el ejemplo de varios a muchos de django ORM :

Observe en el ejemplo de uso de la API que debe guardar () el objeto de artículo base a1 antes de poder agregar objetos de publicación al atributo de muchos a muchos. Y observe que la actualización del atributo de muchos a muchos guarda en la base de datos subyacente inmediatamente, mientras que la actualización de un atributo singular no se refleja en la base de datos hasta que se llama a .save ().

La abstracción es que estamos trabajando con un gráfico de objetos, donde los atributos de valor único y los atributos de valor múltiple son solo atributos. Pero la implementación como un almacén de datos respaldado por una base de datos relacional se filtra ... a medida que el sistema de integridad del RDBS aparece a través de la fina capa de una interfaz de objeto.

hash1baby
fuente
3

¿Qué es la abstracción?

La abstracción es una forma de simplificar el mundo. Significa que no tiene que preocuparse por lo que realmente está sucediendo debajo del capó o detrás de la cortina. Significa que algo es a prueba de idiotas.

Ejemplo de abstracción: las complejidades de volar un 737/747 se "abstraen"

Los aviones son piezas de maquinaria muy complicadas. Tienes motores a reacción, sistemas de oxígeno, sistemas eléctricos, sistemas de tren de aterrizaje, etc. pero el piloto no tiene que preocuparse por las complejidades del motor a reacción ... todo eso se "abstrae". Esto significa que el piloto solo debe preocuparse por dirigir el avión: izquierda para ir a la izquierda y derecha para ir a la derecha, tirar hacia arriba para ganar elevación y empujar hacia abajo para descender.

Es bastante simple ... en realidad mentí: controlar el volante es un poco más complicado. En un mundo ideal, eso es lo único que debería preocupar al piloto . Pero este no es el caso en la vida real: si vuela un avión como un mono, sin ningún conocimiento real de cómo funciona un avión, o de ninguno de los detalles de implementación, es probable que se estrelle y mate a todos a bordo.

Abstracciones con fugas en el ejemplo 737

En realidad, un piloto tiene que preocuparse por MUCHAS cosas importantes, no todo se ha abstraído: los pilotos tienen que preocuparse por la velocidad del viento, el empuje, los ángulos de ataque, el combustible, la altitud, los problemas climáticos, los ángulos de descenso y si el piloto va en la dirección correcta. Las computadoras pueden ayudar al piloto en estas tareas, pero no todo está automatizado / simplificado.

Por ejemplo, si el piloto se detiene con demasiada fuerza en la columna, el avión obedecerá, pero entonces el piloto se arriesgará a detener el avión y, una vez que se detenga, es muy difícil recuperar el control antes de que se estrelle de nuevo contra el suelo. .

En otras palabras, no es suficiente que el piloto simplemente controle el volante sin saber nada más ......... nooooo ....... debe conocer los riesgos y limitaciones subyacentes del avión. antes de volar uno ... debe saber cómo funciona el avión y cómo vuela el avión; debe conocer los detalles de la implementación ... debe saber que si se levanta con demasiada fuerza se producirá una pérdida o que un aterrizaje demasiado abrupto destruirá el avión.

Esas cosas no se abstraen. Se abstraen muchas cosas, pero no todo. El piloto solo necesita preocuparse por la columna de dirección y quizás una o dos cosas más. La abstracción tiene "fugas".

Abstracciones con fugas en el código

... es lo mismo en su código. Si no conoce los detalles de implementación subyacentes, la mayoría de las veces, se arrinconará.

Aquí hay un ejemplo de codificación:

Los ORM eliminan gran parte de la molestia de lidiar con consultas de bases de datos, pero si alguna vez ha hecho algo como:

User.all.each do |user|
   puts user.name # let's print each user's name
end

Entonces te darás cuenta de que es una buena forma de eliminar tu aplicación si tienes más de un par de millones de usuarios. No todo se abstrae. Debe saber que llamar User.alla 25 millones de usuarios aumentará el uso de memoria y causará problemas. Necesita conocer algunos detalles subyacentes. La abstracción tiene fugas.

BKSpurgeon
fuente
0

El hecho de que en algún momento , que estará guiado por su escala y ejecución, será necesario que se familiarice con los detalles de implementación de su marco de abstracción para comprender por qué se comporta de esa manera.

Por ejemplo, considere esta SQLconsulta:

SELECT id, first_name, last_name, age, subject FROM student_details;

Y su alternativa:

SELECT * FROM student_details;

Ahora, parecen soluciones lógicamente equivalentes, pero el rendimiento de la primera es mejor debido a la especificación de nombres de columnas individuales.

Es un ejemplo trivial, pero finalmente vuelve a la cita de Joel Spolsky:

Todas las abstracciones no triviales, hasta cierto punto, tienen fugas.

En algún momento, cuando alcance una cierta escala en su operación, querrá optimizar la forma en que funciona su DB (SQL). Para hacerlo, necesitará saber cómo funcionan las bases de datos relacionales. Te fue abstraído al principio, pero tiene fugas. Necesitas aprenderlo en algún momento.

Johnny
fuente
-1

Supongamos que tenemos el siguiente código en una biblioteca:

Object[] fetchDeviceColorAndModel(String serialNumberOfDevice)
{
    //fetch Device Color and Device Model from DB.
    //create new Object[] and set 0th field with color and 1st field with model value. 
}

Cuando el consumidor llama a la API, obtiene un objeto []. El consumidor debe comprender que el primer campo de la matriz de objetos tiene un valor de color y el segundo campo es el valor del modelo. Aquí la abstracción se ha filtrado de la biblioteca al código del consumidor.

Una de las soluciones es devolver un objeto que encapsule el modelo y el color del dispositivo. El consumidor puede llamar a ese objeto para obtener el modelo y el valor del color.

DeviceColorAndModel fetchDeviceColorAndModel(String serialNumberOfTheDevice)
{
    //fetch Device Color and Device Model from DB.
    return new DeviceColorAndModel(color, model);
}
Niranjan R
fuente
-3

La abstracción con fugas se trata de encapsular el estado. ejemplo muy simple de abstracción con fugas:

$currentTime = new DateTime();

$bankAccount1->setLastRefresh($currentTime);
$bankAccount2->setLastRefresh($currentTime);
$currentTime->setTimestamp($aTimestamp);

class BankAccount {
    // ...

    public function setLastRefresh(DateTimeImmutable $lastRefresh)
    {
        $this->lastRefresh = $lastRefresh;
    } }

y de la manera correcta (no abstracción con fugas):

class BankAccount
{
    // ...

    public function setLastRefresh(DateTime $lastRefresh)
    {
        $this->lastRefresh = clone $lastRefresh;
    }
}

más descripción aquí .

Alireza Rahmani Khalili
fuente