¿Qué significa el término "abstracción con fugas"? (Explique con ejemplos. A menudo me cuesta asimilar una mera teoría).
¿Qué significa el término "abstracción con fugas"? (Explique con ejemplos. A menudo me cuesta asimilar una mera teoría).
Respuestas:
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.
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.
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.
Aquí hay un ejemplo familiar para los desarrolladores de .NET: la Page
clase 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 Page
abstracció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 .
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.
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 someFunction
para 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:
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:
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.
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.
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.
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.
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".
... 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.all
a 25 millones de usuarios aumentará el uso de memoria y causará problemas. Necesita conocer algunos detalles subyacentes. La abstracción tiene fugas.
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 SQL
consulta:
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.
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);
}
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í .