used programming most languages examples programming-languages functional-programming memory-leaks abstraction leaky-abstraction

programming-languages - programming - python



Significado de la abstracción con fugas? (10)

Aquí hay un ejemplo de meatspace :

Los automóviles tienen abstracciones para los conductores. En su forma más pura, hay un volante, un acelerador y un freno. Esta abstracción esconde muchos detalles sobre lo que hay debajo del capó: motor, levas, correa dentada, 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 aún maneja la rueda y usa los pedales para iniciar y detener.

En realidad, es bastante notable ... ¡un niño de 16 años o de 80 años puede operar esta maquinaria complicada sin saber realmente cómo funciona en su interior!

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 mientras cambia de marcha, mientras que en la CVT se siente una torsión 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 enciendes la radio, los faros y el aire acondicionado al mismo tiempo, verás que tu consumo de gasolina disminuye.

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


Bueno, en cierto modo es algo puramente teórico, aunque no carece de importancia.

Usamos abstracciones para hacer las cosas más fáciles de comprender. Es posible que opere 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. Trato con un conjunto ordenado de caracteres para ocultar el hecho de que estoy tratando con números. Trato con los números para ocultar el hecho de que estoy tratando con 1s y 0s.

Una abstracción con fugas es aquella que no oculta los detalles que debe ocultar. Si es una cadena de llamada. Longitud en una cadena de 5 caracteres en Java o .NET podría obtener cualquier respuesta de 5 a 10, debido a los detalles de la implementación en los que los idiomas que 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 tener fugas significa que encontrar la longitud requeriría más espacio de almacenamiento (para almacenar la longitud real) o cambiar de O (1) a O (n) (para determinar cuál es la longitud real). Si me importa la respuesta real (a menudo, en realidad no), necesitas trabajar en el conocimiento de lo que realmente está sucediendo.

Los casos más discutibles ocurren con casos como donde un método o una propiedad le permite ingresar al funcionamiento interno, ya sea que se trate de filtraciones de abstracción o formas bien definidas de pasar a un nivel más bajo de abstracción, a veces puede ser una cuestión en la que las personas no estén de acuerdo.


Continuaré dando ejemplos utilizando RPC.

En el mundo ideal de RPC, una llamada a un procedimiento remoto debería parecerse a una llamada a un procedimiento local (o así dice la historia). Debería ser completamente transparente para el programador, de modo que cuando llaman a SomeObject.someFunction() no tienen idea de si SomeObject (o simplemente someFunction de hecho) se almacenan y ejecutan localmente o se almacenan y ejecutan de forma remota. La teoría dice que esto hace que la programación sea más simple.

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

  • llamando a través de un objeto proxy
  • serializando sus parámetros
  • Hacer una conexión de red (si no está ya establecida)
  • Transmitir los datos al proxy remoto.
  • haciendo que el proxy remoto restaure los datos y llame a la función remota en su nombre
  • serializando el (los) valor (es) de retorno
  • Transmitiendo los valores de retorno al proxy local.
  • reensamblando los datos serializados
  • devolviendo la respuesta desde la función remota

Solo en el tiempo son aproximadamente tres órdenes (o más) de diferencia de magnitud. Esos tres o más órdenes de magnitud van a marcar una gran diferencia en el rendimiento que hará que su abstracción de una llamada a un procedimiento se convierta en algo obvio la primera vez que trata a un RPC por error como una llamada de función real. Además, una llamada de función real, a menos que haya problemas serios 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 verán afectados como casos de falla por encima de lo que cabría esperar de una llamada local regular:

  • Es posible que no puedas crear una instancia de tu proxy local.
  • Es posible que no puedas crear una instancia de tu 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 hacer que esté intacto o en absoluto

Así que ahora su llamada RPC, que es "como una llamada de función local", tiene una gran cantidad de condiciones de falla adicionales con las que no tiene que lidiar cuando hace llamadas de función local. La abstracción se ha filtrado de nuevo, incluso más duro.

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


El hecho de que, en algún momento , 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 consulta SQL :

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

Y es 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 los nombres de columna 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. Fue abstraído para usted al principio, pero tiene fugas. Necesitas aprenderlo en algún momento.


La abstracción con fugas tiene que ver con 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 la manera correcta (no la abstracción permeable):

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

más descripción here .


Simplemente significa que su abstracción expone algunos de los detalles de la implementación, o que necesita estar al tanto de los detalles de la implementación al usar la abstracción. El término se atribuye a Joel Spolsky , alrededor del año 2002. Consulte el article wikipedia para obtener más información.

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


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 valor del modelo y el color.

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


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

Observe en el Uso de API de ejemplo que necesita .save () 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 muchos a muchos se guarda en la base de datos subyacente inmediatamente, mientras que la actualización de un atributo singular no se refleja en la db 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 una base de datos relacional respaldó las fugas del almacén de datos ... a medida que el sistema de integridad de RDBS aparece a través de la delgada capa de una interfaz de objeto.


Wikipedia tiene una article 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ía el cierre 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. Esto no quiere decir, sin embargo, que hay una mejor manera de hacerlo.


Este es un ejemplo familiar para los desarrolladores de .NET: la clase de Page de ASP.NET intenta ocultar los detalles de las operaciones HTTP, en particular la administración de datos de formularios, para que los desarrolladores no tengan que lidiar con los valores publicados (porque asigna automáticamente los valores de los formularios a controles del servidor).

Pero si va más allá de los escenarios de uso más básicos, la abstracción de la Page 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á por usted a menos que los agregue en el momento adecuado : antes de que el motor subyacente asigne los valores de los formularios entrantes a los controles apropiados. Cuando tienes que aprender eso, la abstracción se ha filtrado .