¿Cuál es el valor de ocultar los detalles a través de abstracciones? ¿No hay valor en la transparencia?

30

Fondo

No soy un gran fanático de la abstracción. Admito que uno puede beneficiarse de la adaptabilidad, portabilidad y reutilización de las interfaces, etc. Hay un beneficio real allí, y no deseo cuestionar eso, así que ignorémoslo.

Existe el otro "beneficio" principal de la abstracción, que es ocultar la lógica de implementación y los detalles de los usuarios de esta abstracción. El argumento es que no necesita conocer los detalles, y que uno debe concentrarse en su propia lógica en este punto. Tiene sentido en teoría.

Sin embargo, cada vez que mantengo aplicaciones empresariales grandes, siempre necesito conocer más detalles. Se convierte en una gran molestia profundizar cada vez más en la abstracción a cada paso solo para descubrir exactamente qué hace algo; es decir, tener que hacer una "declaración abierta" unas 12 veces antes de encontrar el procedimiento almacenado utilizado.

Esta mentalidad de 'ocultar los detalles' parece simplemente interferir. Siempre deseo más interfaces transparentes y menos abstracción. Puedo leer el código fuente de alto nivel y saber lo que hace, pero nunca sabré cómo lo hace, cuándo lo hace, es lo que realmente necesito saber.

¿Que está pasando aqui? ¿Todos los sistemas en los que he trabajado han sido mal diseñados (al menos desde esta perspectiva)?

Mi filosofía

Cuando desarrollo software, siento que trato de seguir una filosofía que siento está estrechamente relacionada con la filosofía de ArchLinux :

Arch Linux conserva las complejidades inherentes de un sistema GNU / Linux, mientras las mantiene bien organizadas y transparentes. Los desarrolladores y usuarios de Arch Linux creen que tratar de ocultar las complejidades de un sistema en realidad da como resultado un sistema aún más complejo y, por lo tanto, debe evitarse.

Y por lo tanto, nunca trato de ocultar la complejidad de mi software detrás de las capas de abstracción. Intento abusar de la abstracción, no convertirme en esclava de ella.

Pregunta en el fondo

  1. ¿Hay un valor real en ocultar los detalles?
  2. ¿No estamos sacrificando la transparencia?
  3. ¿No es valiosa esta transparencia?
usuario606723
fuente
77
Se puede abusar de la abstracción en forma de mal diseño. Pero eso no significa que la abstracción en principio no sea valiosa.
Bernard
44
Creo que hay una buena pregunta allí, sin embargo, se parece mucho a una diatriba contra la abstracción. ¿Podrías dejar de enfatizar eso y sacar tu pregunta real más?
PersonalNexus
44
¿Estás seguro de que estás usando la definición correcta de "ocultar los detalles"? En este contexto, se trata de reducir el acoplamiento , no de evitar que aprendas el funcionamiento interno de algo.
Andres F.
24
A menos que desee programar con un voltímetro y un osciloscopio en su escritorio, está programando contra nada más que abstracciones además de abstracciones además de abstracciones. ¿Tiene algún valor ocultar los detalles que de hecho está manipulando, no bits, sino voltajes? ¿Hacer eso sacrifica la transparencia? ¿Es valiosa esa transparencia?
Eric Lippert
8
Creo que con lo que tienes problemas no es la abstracción, son capas vacías de indirección que realmente no abstraen nada. Sí, a menudo se encuentran en sistemas de grandes empresas y no, no son buenos.
Michael Borgwardt

Respuestas:

47

La razón para ocultar los detalles no es mantener los detalles ocultos; es para hacer posible modificar la implementación sin romper el código dependiente.

Imagine que tiene una lista de objetos y que cada objeto tiene una Namepropiedad y otros datos. Y muchas veces, necesita encontrar un elemento en la lista que Namecoincida con una cadena determinada.

La forma obvia es recorrer cada elemento uno por uno, y verificar si Namecoincide con la cadena. Pero si encuentra que eso está tomando demasiado tiempo (como lo haría si tuviera varios miles de elementos en la lista), es posible que desee reemplazarlo con una búsqueda en el diccionario de objetos de cadena.

Ahora, si todas sus búsquedas se realizaron al recuperar la lista y recorrerla, tiene mucho trabajo por hacer para solucionar esto. Es aún más difícil si estás en una biblioteca y otros usuarios la están usando; ¡no puedes salir y arreglar su código!

Pero si tuviera un FindByNamemétodo para encapsular el proceso de búsqueda de nombres, simplemente puede cambiar la forma en que se implementa y todo el código que lo llama continuará funcionando, y se volverá mucho más rápido de forma gratuita. Ese es el valor real de la abstracción y la encapsulación.

Mason Wheeler
fuente
Estoy de acuerdo con esto, pero este no era el punto de la pregunta. Estoy completamente de acuerdo en que un método para encapsular una funcionalidad específica es útil, pero siento que este no es siempre el motivo. ¿Me equivoco?
user606723
3
@ Usuario606723: Debería serlo. Eso no significa que siempre lo sea . Algunas personas no entienden el punto y simplemente acumulan más capas encima de otras capas y convierten las cosas en un desastre. Es por eso que los programadores experimentados aconsejan a los nuevos desarrolladores que nunca adopten una nueva tecnología o técnica hasta que la entiendan.
Mason Wheeler
3
@ user606723: la transparencia fomenta el acoplamiento estrecho, por lo que, aunque no siempre es malo, pero generalmente lo es.
Malfist
3
El problema que describe Mason, de personas que se amontonan en capas en una forma de programación de culto de carga, es por qué sospecho de demasiada herencia, y por qué la composición debería ser favorecida sobre la herencia. Parece ser especialmente un problema para los programadores de Java.
jhocking
2
No, el acoplamiento apretado no siempre es malo. Con frecuencia es malo, pero hacer grandes esfuerzos para evitarlo puede producir problemas aún peores, como la codificación suave.
Mason Wheeler
16

Acabo de leer la sección en Code Complete sobre abstracción, así que ahí es donde la mayoría de estas fuentes.

El punto de abstracción es eliminar la necesidad de preguntar "¿cómo se implementa esto?". Cuando llamas user.get_id(), sabes que ides lo que vas a recuperar. Si tiene que preguntar "¿cómo obtiene esto la identificación de usuario?" entonces probablemente no necesites un ido get_id()devuelva algo inesperado y mal diseñado.

Utiliza la abstracción para permitirte diseñar:

a house with doors and windows

no diseño

a box with four walls,
    with 3 holes,
        two of which fit panes of glass surrounded by wood frames,
        one that fits a large plank of wood with hinges and a metal knob,
etc.
TorelTwiddler
fuente
No estoy hablando de estas interfaces. Estas interfaces están bien. Estoy hablando de enormes sistemas complejos que están segmentados detrás de muchas abstracciones diferentes.
user606723
99
@ user606723 Entonces su pregunta es sobre el diseño excesivamente complejo, en lugar de abstracciones
Andres F.
3
+1 para el código completo. Cubre tanto por qué la abstracción es necesaria para diseñar como por qué el nivel incorrecto de abstracción dificulta el diseño. Para llevar su ejemplo más allá, si estoy trabajando en la oficina de zonificación, quiero pensar en sus casas, sin perder los detalles. Pero si pensabas en las casas como yo, entonces no podrías construir una.
Spencer Rathbun
esta pregunta debería cerrarse o cambiar el título
Jake Berger
8

¿Hay un valor real en ocultar los detalles?

Sí. Al presentar abstracciones podemos pensar y programar en un nivel superior.

Imagine modelar sistemas físicos sin cálculo ni álgebra matricial. Es completamente poco práctico. Del mismo modo, si solo podemos programar a nivel escalar, no podremos resolver problemas interesantes. Incluso las aplicaciones web relativamente simples pueden beneficiarse en gran medida de abstracciones como las bibliotecas de etiquetas. Es mucho más fácil insertar una etiqueta que significa "campos de entrada de dirección" que crear repetidamente cuatro campos de texto y un cuadro de selección. Y si decide expandirse en el extranjero, puede modificar la definición de la etiqueta, en lugar de corregir todos los formularios para manejar direcciones internacionales. El uso efectivo de la abstracción es lo que hace que algunos programadores sean diez veces más efectivos que otros.

Los humanos tienen una memoria de trabajo limitada. La abstracción nos permite razonar sobre sistemas grandes.

Aren't we sacrificing transparency?

No. Si no se utilizan abstracciones, el propósito de un componente de software queda oculto en detalles repetidos. Los desarrolladores pasan sus días vadeando código como este:

for (i = 0; i < pilgrim.wives.size(); ++i) {
  wife = pilgrim.wives[i];
  for (j = 0; j < wife.sacks.size(); ++j) {
     sack = wife.sacks[i];
     for (k = 0; j < sack.cats.size(); ++j) {
        cat = sack.cats[k];
        for (m = 0; m < cat.kits.size(); ++m) {
           ++count;
        }
     }
  }
}

y pensando "oh sí, otro ciclo de cuatro niveles sobre los kits", en lugar de ver

pilgrim.kits.each { ++count; }

¿No es valiosa esta transparencia?

Como señaló, la indirección tiene un costo. No tiene sentido crear capas "por si acaso". Use la abstracción para reducir la duplicación y aclarar el código.

Kevin Cline
fuente
7

Cuando las personas dicen que las abstracciones ocultan los detalles de la implementación, en realidad no significan "ocultar" en el sentido de que es difícil de encontrar. Lo que significan es detalles de implementación separados de la interfaz pública, para mantener la interfaz simple, concisa y manejable. Al igual que un automóvil "oculta" la mayoría de sus partes vitales, y solo ofrece un conjunto de controles bastante rudimentario para operarlos, un módulo de software "oculta" la mayor parte de su funcionalidad en sus entrañas y solo expone un número limitado de métodos de acceso a condúcelo. Imagine un automóvil en el que tiene que operar manualmente todas las partes internas del motor (y hay un montón de ellas), le sería muy difícil vigilar el tráfico y encontrar el camino.

Pero mantener la interfaz simple no es simplemente una cosa estética; Puede marcar la diferencia entre un proyecto exitoso y una Marcha de la Muerte. Juguemos al abogado del diablo por un minuto; imagine un proyecto de software sin ninguna abstracción en absoluto. Si necesita mantener un valor, use una variable global. Si necesita usar la funcionalidad más de una vez, copie y pegue. Si necesita dos versiones diferentes de una determinada sección de código, copie y pegue, envuélvala en una ifdeclaración y modifique ambas ramas. Técnicamente hablando, funciona, pero dentro de unos meses, estarás luchando contra algunos problemas realmente desagradables:

  • Cuando encuentre y repare un error, es probable que también exista en otras instancias de código similar pegadas con copia, por lo que además de encontrar y corregir el error, también debe buscar otros eventos y solucionarlos.
  • Para encontrar un error o implementar un cambio, un programador de mantenimiento debe poder entender el código relevante. La dificultad para hacerlo aumenta con el tamaño de la sección de código relevante, pero aún más con su alcance. Mantener media docena de variables en tu cabeza mientras te desplazas mentalmente por algún código es factible; pero si tiene unos cientos de ellos, su productividad se ve gravemente afectada (me gusta comparar el proceso de pensamiento con un programa que se queda sin RAM física y tiene que sumergirse en el archivo de intercambio: en lugar de leer el código con fluidez de una sola vez , el programador tiene que saltar de un lado a otro para buscar cosas).
  • El alcance de una pieza de código también afecta el tamaño de la base de código que uno tiene que cavar para encontrar el error. Si tiene una función de diez líneas con dos parámetros, y no tiene valores globales, y conoce los valores de la entrada y la línea en la que se bloquea, encontrar el error suele ser trivial y, a menudo, no requiere nada más que mirar el código. Si se trata de unos cientos de líneas, veinte parámetros, quince globales y requiere algunas otras funciones de naturaleza similar, te espera un dolor grave.
  • Sin una abstracción adecuada, cualquier cambio puede afectar potencialmente grandes partes de la base de código, ya que prácticamente cualquier cosa puede depender del código que se va a cambiar. Un síntoma típico con tales bases de código es que realiza un pequeño cambio aparentemente inocente, y una característica completamente no relacionada se rompe repentinamente. Con la abstracción, puede limitar la cantidad de daño que puede hacer un cambio y hacer que el impacto sea más predecible. Si cambia el nombre de un campo privado, solo tiene que verificar un archivo fuente; Si cambia el nombre de una variable global, debe ejecutar toda la base de código.

En una base de código mal abstraída, el impacto generalmente crece exponencialmente con el tamaño de la base de código, es decir, agregar una cantidad constante de código aumenta el esfuerzo de mantenimiento en un factor constante. Para empeorar las cosas, agregar más programadores a un proyecto no aumenta la productividad linealmente, sino logarítmicamente en el mejor de los casos (porque cuanto más grande sea su equipo, más gastos generales se requieren para la comunicación).

tdammers
fuente
2

Creo que deberías entender cómo funciona si es necesario. Una vez que haya determinado que hace lo que pensaba que haría, entonces tiene tranquilidad. Nunca pensé que el objetivo era ocultarlo para siempre.

Una vez que configura una alarma en un reloj que está seguro de que funcionará, puede dormir un poco sabiendo que sonará a la hora correcta. Despertar una hora antes para poder ver los segundos transcurrir es un desperdicio.

JeffO
fuente
1
Claro, pero a menudo no se me pide que cambie la forma en que funciona mi despertador, o que otras personas cambien la forma en que funciona mi despertador sin estar completamente informado de los cambios.
user606723
1
¿Ves los cambios de código para cada marco que alguna vez has usado?
JeffO
1
no, pero no mantengo cambios de código para cada marco que he usado.
user606723
3
Ya has probado el punto de JeffO: tampoco estás en el negocio de mantener relojes despertadores. Si compra uno y comienza a usarlo sin hacer un desmantelamiento completo y un análisis de cómo funciona, ha aceptado que el interior será abstracto para usted. Nada dice que no se puede romper para descubrir cómo funciona, pero ¿con qué frecuencia lo considera necesario?
Blrfl
2

Para responder sus preguntas específicamente:

¿Hay un valor real en ocultar los detalles?

Sí. Como usted reconoce en la primera línea de su pregunta.

¿No estamos sacrificando la transparencia?

Realmente no. Una abstracción bien escrita facilitará la comprensión de los detalles si es necesario.

¿No es valiosa esta transparencia?

Sí. Las abstracciones deben diseñarse e implementarse para facilitar la comprensión de los detalles cuando sea necesario / deseado.

Craig
fuente
Finalmente una respuesta que me gusta.
user606723
1

Diría que ocultar los detalles es genial cuando las cosas ocultas funcionan.

Por ejemplo, supongamos que desarrollamos una interfaz que define comportamientos (es decir, GetListItems, SendListItem), que son dos características que el usuario inicia mediante un clic en un botón o algo así ... AHORA, cada usuario puede tener su propio "ListItemStore" ... digamos está en Facebook, en MySpace ... (por ejemplo) ... y dice que está guardado como una propiedad / configuración del usuario en algún lugar de la aplicación a través de las preferencias del usuario ... y dice que es posible que los desarrolladores de aplicaciones agreguen ListItemStore adicionales en el transcurso de tiempo (mybook, espacio facial, etc.)

ahora hay muchos detalles al conectarse a Facebook y obtener elementos ... y hay tantos detalles al conectarse a MySpace ... y así sucesivamente ...

ahora, después de escribir el código inicial de "acceso a la tienda", es posible que no sea necesario modificarlo (bueno, en el caso de Facebook probablemente necesitemos un desarrollador a tiempo completo para mantenerse al día con los cambios, zing ...),

así que cuando usas el código es algo así como:

    new ItemManager(user) //passes in user, allowing class to get all user properties
    ItemManager.GetListItems()

y ahora tiene los datos del Usuario de donde sea que lo hayan almacenado, y dado que todo lo que me preocupa es obtener la lista de elementos y hacer algo con ellos, y dado que solo tomó 2 líneas que funcionarán sin importar cómo se agregan muchas más tiendas, puedo volver a responder / publicar preguntas en la pila ... jajaja ...

Entonces, toda la plomería para que eso suceda está "oculta" y a quién le importa cómo lo hace, siempre y cuando obtenga la lista correcta de elementos ... si tiene pruebas unitarias, entonces puede descansar más fácilmente porque los resultados deberían ' Ya se ha cuantificado.

hanzolo
fuente
Sí, pero la parte que debe mantenerse nunca son esas dos líneas. Es imposible arruinarlos. Siempre es el segundo, tercer y cuarto nivel inferior el que necesitas cambiar. Estoy de acuerdo en que esto es genial cuando tienes una API en la que puedes confiar para que sea estable , pero ¿y si no puede ser estable solo por la complejidad de tu negocio?
user606723
1
@ user606723 si su API no es estable, entonces es probable que sea ​​inmadura o más bien la abstracción incorrecta
sdg
@ user606723 - Eso es cierto, y en esos casos las convenciones de nomenclatura en sí mismas deberían definir alguna forma de transparencia que oculte la lógica / detalle de programación real ... y si alguna vez tiene que modificar la fuente real, se deben expresar más detalles e ideas a través de nombres informativos así que, en esencia, la transparencia se puede lograr con un nombre adecuado hasta el final, sin embargo, realmente no deberíamos necesitar bajar todo el tiempo muy a menudo.
hanzolo
@sdg, o porque los requisitos del sistema siempre están cambiando. Porque las leyes cambian, porque las API de otros cambian, está fuera de nuestro control.
user606723
1
@ user606723: en realidad trabajo en un sistema SaaS financiero y veo las dificultades de no tener suficiente abstracción en cada ciclo de lanzamiento. parte de esto es el resultado de un diseño deficiente, pero generalmente es el resultado de insertar código donde no estaba destinado originalmente. Bajar la cadena puede ser doloroso sin esos comentarios, nombres y encapsulación . si todo lo que tuviera que hacer fuera Remeasurements.GetRemeasureType (grant), y luego reMeasure.PerformCalc (), eso sería mucho mejor que agregar sobrecargas y leer las diferentes ramas lógicas para llegar al cálculo adecuado o agregar uno nuevo
hanzolo
1

Lo que usted denomina "Ocultar", muchos lo ven como una separación de preocupaciones (por ejemplo, Implementación vs. Interfaz).

En mi opinión, uno de los principales beneficios de la abstracción es reducir el desorden de detalles innecesarios del espacio cerebral limitado del desarrollador.

Si se ofuscara el código de implementación, podría verlo como un obstáculo para la transparencia, pero la abstracción tal como la veo, es solo una buena organización.

Somantra
fuente
1

En primer lugar, cualquier cosa más allá de una sola instrucción de código de máquina es esencialmente abstracción: un while...dobucle es una forma simbólica consistente de representar las comparaciones y las llamadas de dirección necesarias para repetir un conjunto de instrucciones hasta que se cumpla una condición. Del mismo modo, el tipo int es una abstracción para X número de bits (dependiendo de su sistema). La programación tiene que ver con la abstracción.

Probablemente estaría de acuerdo en que esas abstracciones primitivas son muy útiles. Bueno, así es poder construir el tuyo. OOAD y OOP son todo.

Suponga que tiene un requisito en el que los usuarios desean poder exportar los datos desde una pantalla en una variedad de formatos: texto delimitado, Excel y PDF. ¿No es útil que pueda crear una interfaz llamada "Exportador" con un método de exportación (datos), en base al cual puede construir un DelimitedTextExporter, un ExcelExporter y un PDFExporter, cada uno de los cuales sabe cómo crear su salida particular? Todo lo que el programa de llamadas necesita saber es que puede llamar al método de exportación (datos), y cualquier implementación que se use hará lo suyo. Además, si las reglas de texto delimitado cambian, puede cambiar el DelimitedTextExporter sin tener que meterse con el ExcelExporter, posiblemente rompiéndolo.

Casi todos los patrones de diseño conocidos utilizados en la programación OO dependen de la abstracción. Recomiendo leer Freeman y Freeman's Head First Design Patterns para tener una mejor idea de por qué la abstracción es algo bueno

Matthew Flynn
fuente
1
incluso el código de la máquina es una abstracción, hay procesos reales, físicos, que ocurren debajo de la lógica, incluso la electrónica digital es una abstracción sobre lo que realmente sucede, ya que cualquiera que haya hecho un hash de overclocking de un chip puede testificar ante
jk.
Demasiado cierto, aunque parece más concreto a nivel de instrucción de máquina.
Matthew Flynn
1

Creo que entiendo tu opinión sobre esto, y creo que tengo una opinión similar.

He trabajado con desarrolladores de Java que convierten 50 clases de línea de código en 3 clases y 3 interfaces porque es fácil de entender. Y no pude soportarlo.

La cosa era terriblemente difícil de entender, casi imposible de depurar y nunca fue necesario "cambiar la implementación".

Por otro lado, también he visto código en el que varios objetos comparten un comportamiento similar y se usan en un solo lugar, y realmente podría usar bucles comunes de clasificación / procesamiento si los métodos hubieran estado expuestos a través de una interfaz común.

Por lo tanto, en mi humilde opinión, los objetos centrales que es probable que se usen en escenarios similares generalmente se benefician de un comportamiento común al que debería accederse a través de la interfaz. Pero eso es todo, abstraer cosas simples porque es correcto, o hace posible cambiar las implementaciones, es solo una forma de hacer que el código sea desordenado.

Por otra parte, prefiero clases más largas e inteligentes que una cantidad explosiva de clases pequeñas con todos los problemas de administración de por vida, y relaciones difíciles de ver y gráficos de llamadas de espagueti. Entonces algunas personas no estarán de acuerdo conmigo.

Descifrador
fuente
1

El propósito de guía de su escondite y la abstracción debe desacoplando el usuario de la aplicación para que puedan ser cambiados de forma independiente si el consumidor es, junto con los detalles de la implementación, debido a tocar el violín con sus partes internas tanto se echan en piedra y se hace más difícil introducir nuevas características o mejores algoritmos en el futuro.

Al escribir un módulo, las partes ocultas de la implementación le dan la tranquilidad de poder cambiarlas sin arriesgarse a romper otro código que no se le ocurre.

Otra ventaja de proporcionar interfaces opacas es que reducen significativamente el área de superficie entre subsistemas. Al reducir la cantidad de formas en que pueden interactuar, pueden volverse más predecibles, más fáciles de probar y tener menos errores. Las interacciones entre módulos también aumentan de forma cuadrática con el número de módulos, por lo que es valioso tratar de controlar este crecimiento de complejidad.


Dicho esto, por supuesto, es posible ocultar demasiado y anidar interfaces demasiado profundas. El trabajo del programador, como humano inteligente, es diseñar el sistema de manera que sea de máxima utilidad, al tiempo que minimiza la complejidad y maximiza la capacidad de mantenimiento.

hugomg
fuente
0

En tantos casos, simplemente no necesita saber cómo se implementan las cosas. Casi puedo garantizar que escribirás un código como este people.Where(p => p.Surname == "Smith")tantas veces al día, pero casi nunca pensarás "¿cómo funciona Where()realmente este método?" Simplemente no te importa, sabes que este método está ahí y que te da los resultados que deseas. ¿Por qué te importaría cómo funciona?

Esto es exactamente lo mismo para cualquier software interno; el hecho de que no esté escrito por Oracle, Microsoft, etc., no significa que deba investigar cómo se implementa. Puede esperar razonablemente que un método llamado le GetAllPeopleWithSurname(string name)devuelva una lista de personas que tienen ese apellido. Podría iterar sobre una lista, podría usar un diccionario, podría hacer algo completamente loco, pero no debería importarle .

Hay una excepción a esta regla, por supuesto (¡no sería una regla sin una!) Y eso es si hay un error en el método. Entonces, en el ejemplo anterior, si tiene una lista con 3 personas y sabe que uno de ellos tiene el apellido Smith y no se devuelven en la lista, entonces le importa la implementación de ese método porque está claramente roto .

La abstracción, cuando se hace correctamente, es maravillosa porque te permite filtrar todo lo que no es útil cuando tienes que leerlo en una fecha posterior. No olvide que se dedica mucho más tiempo a leer el código que al escribirlo, por lo tanto, se debe hacer énfasis en hacer que la tarea sea lo más fácil posible. También podría estar pensando que la abstracción significa una jerarquía de objetos tan larga como su brazo, pero puede ser tan simple como refactorizar un método de 100 líneas en 10 métodos, cada uno de 10 líneas de largo. Entonces, lo que una vez fueron 10 pasos, todos juntos, ahora son 10 pasos separados que le permiten ir directamente al lugar donde se esconde este molesto error.

Stuart Leyland-Cole
fuente
Eh, pero digamos que eres tú quien mantiene la implementación. Quiero decir, a alguien le importa la implementación, y esa persona eres tú. También resulta ser el usuario de la implementación ... Los requisitos comerciales cambian (en formas que no puede predecir) causando cambios en muchas capas. Creo que mi punto es que un error no es la única excepción a esa regla.
user606723
El problema esPeopleFactory.People.Strategy.MakePeople.(CoutryLaw.NameRegistry.NameMaker.Make()) as People.Female
codificador
@ user606723 No tiene que preocuparse por cada línea de código en su base de código todo el tiempo. Si hay un error en esa implementación o se ha marcado como necesario reescribirlo (porque es lento, está mal escrito o lo que sea) y lo está reescribiendo, entonces le importa. De lo contrario, debe mantenerse fuera del camino. Tal vez su problema es que está tratando de poseer todo el código todo el tiempo. En mi opinión, solo debes concentrarte en el código en el que estás trabajando en un momento en particular.
Stuart Leyland-Cole
@Coder ¡Obviamente es una forma de abstracción bastante extrema! Al principio pensé que era el tipo de cosas en contra de lo que estaba opuesto el OP, pero al leer el resto de sus respuestas, parece que ven toda abstracción como mala, mala, mala. Es por eso que traté de explicar los diferentes niveles de abstracción en mi respuesta.
Stuart Leyland-Cole
0

Las abstracciones dan como resultado el ocultamiento de información. Esto debería terminar en un acoplamiento inferior. Esto debería conducir a menos riesgos en el cambio. Esto debería llevar a programadores felices, a no ponerse nerviosos al tocar el código.

Esas ideas se expresan a través de tres leyes esenciales en la arquitectura de software:

Ley de Simon: "Las jerarquías reducen la complejidad". (Las jerarquías introducen la abstracción)

Ley de Parna: "Solo lo que está oculto se puede cambiar sin riesgo".

Ley de Constantin: los programas robustos necesitan poco acoplamiento y alta cohesión

ins0m
fuente
"Las jerarquías reducen la complejidad". - No necesariamente cierto.
Codificador
Ninguna metodología de diseño es determinista. Esta ley no proviene de TI / CS, está formulada en un sentido mucho más amplio y también es referida por matemáticas, físicos, etc. Es un principio válido, pero nadie puede evitar que cree jerarquías sin sentido.
ins0m
0

También estoy en el negocio de aplicaciones empresariales, y esta pregunta me llamó la atención porque yo mismo tengo la misma pregunta. Hasta el momento tuve algunos conocimientos sobre el tema de la abstracción en el transcurso de mi carrera, pero mi conocimiento no es la respuesta universal. Continúo aprendiendo / escuchando nuevas ideas y pensamientos, así que lo que creo ahora puede cambiar.

Cuando mantenía una aplicación de atención médica grande y compleja, me gustabas, odiaba todas las abstracciones allí. Calcular dónde va todo el código fue dolor en el cuello. Saltar alrededor de diferentes clases me mareó. Entonces me dije a mí mismo "la abstracción apesta, minimizaré la abstracción cuando diseño cosas".

Luego, llegó el momento en que tuve que diseñar una aplicación (componente de servicio web relativamente pequeño) desde cero. Recordando todo el dolor, tenía un diseño bastante plano del componente. El problema era que, cuando los requisitos cambiaban, tenía que hacer cambios en muchos lugares diferentes (los requisitos eran bastante fluidos y no podía hacer nada al respecto). Fue tan malo que básicamente descarté mi diseño inicial y lo rediseñé con abstracción, y las cosas mejoraron: no tuve que hacer cambios en muchos lugares cuando los requisitos cambiaron más.

Entregué la solicitud, me senté por unas semanas y luego me dijeron que comenzara a mantenerla. Había pasado un tiempo, no recordaba todo, así que luché un poco para entender mi propio código, y la abstracción no estaba ayudando.

Luego me pusieron en muchos otros proyectos diferentes y tuve la oportunidad de jugar un poco más con los niveles de abstracción. Lo que realmente encuentro es, y esta es solo mi opinión personal, la abstracción ayuda mucho en el desarrollo pero tiene un impacto negativo cuando no escribiste el código y estás tratando de entender todo al nivel más profundo de una aplicación; Pasará más tiempo saltando por diferentes clases e intentando hacer las conexiones.

Mi sensación es que la abstracción es tan valiosa durante el tiempo de desarrollo que vale la pena el problema que atravesamos como mantenedores al tratar de entender el código. El software existe para resolver problemas comerciales, los problemas comerciales evolucionan con el tiempo; por lo tanto, el software tiene que evolucionar con el tiempo. Sin abstracción, evolucionar el software es muy difícil. Se puede diseñar la abstracción de manera que el responsable de mantenimiento pueda navegar fácilmente por la base del código una vez que vean el patrón de la estructura del código, de modo que solo la curva de aprendizaje inicial sea frustrante.

Alvin
fuente
0

Como otros han dicho, "ocultar detalles" detrás de una abstracción les permite cambiar sin afectar a los usuarios. Esta idea proviene de los Criterios de Parnas para ser utilizados en sistemas de descomposición en módulos (1972) , y está relacionada con la idea de tipos de datos abstractos (ADT) y programación orientada a objetos.

Aproximadamente al mismo tiempo, el Modelo relacional de datos de Codd para grandes bancos de datos compartidos (1970) fue motivado (ver el resumen y la introducción) al querer cambiar la representación del almacenamiento interno de las bases de datos, sin afectar a los usuarios de la base de datos. Había visto a programadores que regularmente tomaban días, modificando páginas de código, para hacer frente a pequeños cambios de almacenamiento.

Dicho esto, una abstracción no es muy útil si tienes que ver lo que hay dentro para poder usarla. Puede ser muy difícil diseñarlo bien. Un ejemplo de una buena abstracción es la suma: ¿cuándo fue la última vez que tuvo que pensar en lo que sucede dentro? (pero a veces lo hace, por ejemplo, por desbordamiento).

El problema esencial (en mi humilde opinión) es que para diseñar bien los módulos (en el sentido de Parnas), debe predecir qué cambiará y qué no. Es difícil predecir el futuro, pero si tienes mucha experiencia con algo y lo entiendes claramente, puedes hacer un buen trabajo de predicción. Y, por lo tanto, puede diseñar un módulo (abstracción) que funcione bien.

Sin embargo, parece el destino de todas las abstracciones, incluso las mejores, que eventualmente habrá cambios imprevistos (y posiblemente imprevisibles) que requieren romper la abstracción. Para abordar esto, algunas abstracciones tienen un escape, donde puede obtener acceso a un nivel más profundo si realmente lo necesita.

Todo esto parece muy negativo. Pero creo que la verdad es que estamos rodeados de abstracciones que funcionan tan bien que no las notamos ni nos damos cuenta de lo que están ocultando. Solo notamos las malas abstracciones, por lo que tenemos una visión icónica de ellas.

13ren
fuente
0

Las abstracciones son principalmente para el beneficio de sus consumidores (por ejemplo, programadores de aplicaciones). Los programadores del sistema (diseñador) tienen más trabajo que hacer para que sean hermosos y útiles, por lo que los principiantes no suelen hacer un buen diseño.

¿Quizás no te gustan las abstracciones porque siempre agregan complejidad? ¿Quizás los sistemas en los que has trabajado tenían abstracción (uso excesivo de abstracciones)? No son una panacea.

El trabajo extra y la complejidad de una abstracción útil deberían dar sus frutos, pero es difícil saberlo con certeza. Si piensa en una abstracción como un punto de pivote, el diseño del software puede flexionarse en ambos lados: las implementaciones de la abstracción se pueden modificar sin romper el código del cliente, y / o los nuevos clientes pueden reutilizar fácilmente la abstracción para hacer cosas nuevas.

Casi podría medir el retorno de la inversión de las abstracciones al mostrar que han sido "flexionadas" con el tiempo en una o ambas direcciones: cambios de implementación relativamente indoloros y nuevos clientes adicionales.

Por ejemplo: usando la abstracción de la clase Socket en Java, estoy seguro de que mi código de aplicación de Java 1.2 todavía funciona bien en Java 7 (aunque puede haber algunos cambios en el rendimiento). Desde Java 1.2, definitivamente ha habido muchos clientes nuevos que también utilizaron esta abstracción.

En cuanto a la infelicidad con las abstracciones, si hablo con los desarrolladores que mantienen el código detrás la clase Socket, entonces tal vez sus vidas no sean tan color de rosa y color de rosa como los clientes que usaron Socket para escribir aplicaciones divertidas. Trabajar en la implementación de una abstracción seguramente es más trabajo que usarlo. Pero eso no lo hace malo.

En cuanto a la transparencia, en una estrategia de diseño de arriba hacia abajo, la transparencia total genera un mal diseño. Los programadores inteligentes tienden a aprovechar al máximo la información que tienen a su disposición, y el sistema se acopla estrechamente. El cambio más pequeño de detalles (p. Ej., Cambiar el orden de los bytes en una estructura de datos) en un módulo podría romper algún código en otro lugar, porque un programador inteligente usó esa información para hacer algo útil. David Parnas señaló este problema en artículos tan antiguos como 1971, donde propuso ocultar información en los diseños.

Su referencia a ArchLinux tiene sentido para mí si considera que el "interior" del sistema operativo es la implementación compleja de la abstracción que es el sistema operativo para las aplicaciones que se ejecutan en él. Mantenlo simple en las entrañas de la abstracción.

Fuhrmanator
fuente
0

Contestaré tu pregunta con una pregunta; cuando manejaste al trabajo esta mañana (supongo que de hecho lo hiciste), ¿te importó exactamente cómo el motor abrió las válvulas para dejar entrar las mezclas de combustible y aire, y luego las encendió? No. No te importa cómo funciona el motor de tu automóvil cuando conduces por la carretera. Te importa que hace el trabajo.

Supongamos que un día su automóvil no funciona. No arranca, tira una varilla, rompe un cinturón, se abate inexplicablemente en esa barrera de concreto sin culpa tuya mientras estabas ocupado enviando mensajes de texto. Ahora, necesita un auto nuevo (al menos temporalmente). ¿Te importa exactamente cómo funciona este auto nuevo? No. Lo que le importa es primero que funcione, y segundo, que puede usar los mismos conocimientos y habilidades que utilizó para conducir su automóvil viejo para conducir el nuevo. Idealmente, debería parecerle que no ha habido cambios en el automóvil que conduce. Siendo realistas, la forma en que funciona este nuevo automóvil debería darle la menor cantidad de "sorpresas" posible.

Estos principios básicos son el principio central detrás de la encapsulación y la abstracción. El conocimiento de cómo un objeto hace lo que hace no debería ser un requisito para usarlo para hacer lo que hace. Incluso en la programación de computadoras, los detalles de las rutas eléctricas dentro de la CPU que ejecuta su programa se resumen detrás de al menos media docena de capas de instrucciones de E / S, controladores, software del sistema operativo y tiempo de ejecución. Muchos ingenieros de software muy exitosos escriben código perfectamente bueno sin preocuparse una vez por la arquitectura exacta del hardware, o incluso la compilación del sistema operativo, que lo ejecutará. Incluyéndome a mí.

La encapsulación / ocultación de información permite la mentalidad de "no importa cómo funciona, solo importa que lo haga". Su objeto debe exponer lo que es útil para el consumidor, de manera que el consumidor pueda consumirlo fácilmente. Ahora, de vuelta en el mundo real, esto no significa que un automóvil no deba brindarle al usuario ninguna información sobre el funcionamiento interno, o que el automóvil solo debe permitir al usuario la funcionalidad más básica como el encendido, el volante, y pedales. Todos los automóviles tienen velocímetros y medidores de combustible, tacómetros, luces idiotas y otros comentarios. Prácticamente todos los automóviles también tienen interruptores para varios subsistemas independientes, como faros, intermitentes, radio, ajuste del asiento, etc. Algunos automóviles permiten una entrada bastante esotérica del usuario, como la sensibilidad del diferencial central de deslizamiento limitado. En todos los casos, si sabes lo suficiente, puedes abrirlo y cambiar las cosas para que funcione de una manera ligeramente diferente. Pero, en la mayoría de los casos, tal vez, solo tal vez, ¿el usuario no debería poder controlar directa e independientemente las bombas de combustible desde el interior de la cabina? ¿Quizás, solo quizás, el usuario no debería poder activar sus luces de freno sin pisar realmente el pedal del freno?

La abstracción permite "esto no es lo mismo que eso, pero como ambos son X, puedo usarlos como lo haría con cualquier mentalidad X". Si su objeto hereda o implementa una abstracción, sus consumidores deben esperar que su implementación produzca el mismo o similar resultado que otras implementaciones conocidas de la abstracción. Un Toyota Camry y un Ford Fusion son ambos "autos". Como tal, tienen un conjunto común de funcionalidad esperada, como un volante. Gírelo en el sentido contrario a las agujas del reloj, el automóvil va a la izquierda. Gírelo en sentido horario, el auto va a la derecha. Puedes subirte a cualquier automóvil en los Estados Unidos y esperar que el automóvil tenga un volante y al menos dos pedales, el de la derecha es el pedal de "auto va" y el del centro es el pedal de "auto se detiene" .

Un corolario de la abstracción es la "teoría del menor asombro". Si se puso al volante de un automóvil nuevo para una prueba de manejo, giró el volante en el sentido de las agujas del reloj y el automóvil giró a la izquierda, por lo menos quedaría asombrado. Acusaría al vendedor de vender un TPV y es poco probable que escuche alguna de sus razones por las cuales el nuevo comportamiento es "mejor" de lo que está acostumbrado, o qué tan bien está "documentado" este comportamiento o cómo " transparente "es el sistema de control. A pesar de que este automóvil nuevo y todos los demás que ha conducido siguen siendo "automóviles", al conducir este automóvil tiene que cambiar algunos conceptos fundamentales de cómo se supone que se debe conducir un automóvil para conducirlo con éxito. Eso suele ser algo malo y solo sucede cuando hay una ventaja intuitiva para el nuevo paradigma. Quizás la adición de cinturones de seguridad es un buen ejemplo; Hace 50 años recién entraste y te fuiste, pero ahora tienes que abrocharte el cinturón, la ventaja intuitiva es que no pasas por el parabrisas ni entras en el asiento del pasajero si tienes un accidente. Incluso entonces, los conductores resistieron; muchos propietarios de automóviles cortaron los cinturones de seguridad del automóvil hasta que se aprobaron leyes que ordenaban su uso.

KeithS
fuente