¿Puede demasiada abstracción ser mala?

46

Como programadores, siento que nuestro objetivo es proporcionar buenas abstracciones sobre el modelo de dominio y la lógica empresarial dados. Pero, ¿dónde debería detenerse esta abstracción? Cómo hacer una compensación entre la abstracción y todos sus beneficios (flexibilidad, facilidad de cambio, etc.) y la facilidad de comprender el código y todos sus beneficios.

Creo que tiendo a escribir código demasiado abstracto y no sé qué tan bueno es; A menudo tiendo a escribirlo como si fuera una especie de micro marco, que consta de dos partes:

  1. Micro módulos que están conectados en el micro marco: estos módulos son fáciles de entender, desarrollar y mantener como unidades individuales. Este código básicamente representa el código que realmente hace las cosas funcionales, descritas en los requisitos.
  2. Código de conexión; ahora aquí creo que se encuentra el problema. Este código tiende a ser complicado porque a veces es muy abstracto y es difícil de entender al principio; esto surge debido al hecho de que es solo pura abstracción, la base en la realidad y la lógica de negocios que se realiza en el código presentado 1; Por esta razón, no se espera que este código se cambie una vez probado.

¿Es este un buen enfoque en la programación? ¿Que, teniendo código cambiante muy fragmentado en muchos módulos y muy fácil de entender y código cambiante muy complejo desde el punto de vista de abstracción? Si todo el código es uniformemente complejo (es decir, el código 1 es más complejo e interconectado y el código 2 es más simple) para que cualquiera que lo revise pueda entenderlo en un tiempo razonable, pero el cambio es costoso o la solución presentada anteriormente es buena, donde "cambiar el código" es muy fácil de entender, depurar, cambiar y "vincular el código" es un poco difícil.

Nota: ¡no se trata de la legibilidad del código! Ambos códigos en 1 y 2 son legibles, pero el código en 2 viene con abstracciones más complejas, mientras que el código 1 viene con abstracciones simples.

m3th0dman
fuente
3
Los comentarios y los nombres claros se inventan para acelerar el tiempo necesario para comprender el código complejo. Está perfectamente bien que su código de nivel inferior sea más complejo; en algún nivel, es casi seguro que estás llamando a un nivel mucho más complejo y mucho más bajo de todos modos.
DougM
25
"Demasiado" es malo por definición.
Jon Purdy
@JimmyHoffa: Tengo que mantener esos tipos en su lugar. Y no seas celoso, no puedo escribir Haskell todo el día. Es principalmente PHP, JavaScript y OCaml en realidad.
Jon Purdy

Respuestas:

78

Las primeras palabras de TC ++ PL4:

Todos los problemas en informática pueden resolverse mediante otro nivel de indirección, excepto el problema de demasiadas capas de indirección. - David J. Wheeler

(David Wheeler fue mi asesor de tesis. La cita sin la última línea importante a veces se llama "La primera ley de la informática").

Bjarne
fuente
66
¿Y cómo sabes cuando tienes demasiados niveles de indirección? Tendería a decir que viene con experiencia, pero un programador más experimentado entiende fácilmente más indirección, por lo tanto, no ve un problema con demasiados niveles.
m3th0dman
2
@ m3th0dman: tiene el nivel correcto de abstracción cuando resulta fácil realizar cambios en el futuro. Por supuesto, también puede preguntar cómo sabe cuándo ocurrirá eso, lo que simplemente repite el ciclo de preguntas de una manera diferente.
1
esta pregunta depende del nivel del programador ... tendrás programadores complejos que comprenderán tu loca arquitectura de capa de 8 niveles y la encontrarán brillante, mientras que otros codificadores simples pero suaves lo encontrarán ridículo y discutirán sobre tu loca de 8 niveles proyecto en capas ... aquí es donde la documentación vale la pena, no solo le permite documentar su código, sino que le permite defenderlo
Ryan
1
perdone mi ignorancia, pero no entiendo "TC ++ PL4"
LastTr tribunal
30

Sí definitivamente. La cuestión es que ninguna abstracción es perfecta. Todos los detalles de la capa sobre la que se ubican las abstracciones están ahí por una razón, y puede simplificar muchas cosas, pero si esa complejidad no fuera necesaria en algún momento, probablemente no estaría allí en primer lugar. Y eso significa que en algún momento, cada abstracción se filtrará de alguna manera.

Y ahí es donde radica el verdadero problema. Cuando las abstracciones fallan, mientras más capas haya colocado entre el código que escribió y lo que realmente está sucediendo, más difícil será resolver el problema y solucionarlo, porque hay más lugares donde podría estar el problema. Y cuantas más capas haya, más tienes que saber para rastrearlo.

Mason Wheeler
fuente
1
"Y eso significa que en algún momento, cada abstracción se filtrará de alguna manera": Verdadero. Una mejor abstracción es aquella que se filtra con menos frecuencia.
Giorgio
11
A la luz de la respuesta de Bjarne (y haciendo referencia a la página wiki de David Wheeler ), ¿tal vez pueda cambiar la atribución de su presupuesto? :)
congusbongus
2
@CongXu: Por cierto, he ido desde el otro extremo: buscando en Google "citas de Bjarne Stroustrup" y no he encontrado una sola referencia de Bjarne que haya pronunciado la frase "agregar otra capa de indirección" ... No es concluyente, por supuesto, pero lo hace hacer que sea muy poco probable que él haya sido el primero en pronunciarlo.
Marjan Venema
1
Más capas de abstracción significan abstracciones simples y, por lo tanto, menos fugas por abstracción. Entonces, en una formulación matemática (por supuesto, sin ninguna prueba), la suma de la fuga de abstracción puede ser constante a medida que cambia el número de niveles de abstracción.
m3th0dman
2
Una vez, ingenuamente, tomé el consejo de un senior para agregar una abstracción donde no era necesaria. Nunca se usó más allá de lo que quería hacer en primer lugar.
Cees Timmerman
15

Si, absolutamente.

La analogía que me gusta usar para explicar la programación es la de un sastre. Al hacer un traje, un buen sastre siempre dejará una pequeña cantidad de tela en lugares estratégicos dentro de la prenda para permitir que la prenda se pueda llevar dentro o fuera, sin cambiar su forma o estructura general.

Good Tailor's no deja resmas de tela en cada costura solo en caso de que crezca un tercer brazo o quede embarazada. Demasiado material en los lugares equivocados hará que la prenda no quede bien ajustada, y el uso de la prenda adicional simplemente obstaculiza el uso normal. Si tiene poca tela y la prenda es propensa a las lágrimas y no podrá ser alterada para hacer frente a cambios menores en el físico de su usuario, afectando la forma en que se sienta la prenda.

Tal vez algún día, nuestro Good Tailor tenga la tarea de hacer un vestido tan ajustado que tenga que coserlo. Y tal vez a nuestro Good Tailor se le pida que use ropa de maternidad, donde el estilo y el ajuste son segundos para la comodidad y la capacidad de expansión. Pero antes de emprender cualquiera de esos trabajos especiales, un buen Sastre sería lo suficientemente sabio como para que todos conozcan los compromisos que se están haciendo para lograr esos objetivos.

A veces, estos compromisos son el camino correcto a seguir, y las personas están dispuestas a aceptar sus consecuencias. Pero en la mayoría de los casos, el enfoque de dejar un poco donde más cuenta superará cualquier beneficio percibido.

Entonces, relacionando esto con la abstracción. Es absolutamente posible tener demasiadas capas de abstracción, al igual que es posible tener muy pocas. El verdadero arte del programador, como nuestros amigos a medida, es dejar un poco donde más cuenta.

Volviendo al tema.

El problema con el código generalmente no es la abstracción, sino las dependencias. Como ha señalado, es el código que conecta objetos discretos lo que es un problema, porque existe una dependencia implícita entre ellos. En algún momento, la comunicación entre las cosas solo debe ser concreta, pero juzgar dónde está ese punto generalmente requiere algunas conjeturas.

Dicho esto, "Micro" cualquier cosa suele ser una indicación de que ha sobregranizado el diseño de su objeto, y probablemente esté utilizando Type como sinónimo de lo que deberían ser datos . Tener menos cosas también significa menos dependencias necesarias para comunicarse entre ellas.

Soy un gran admirador de la mensajería asincrónica entre sistemas por este motivo. Termina con dos sistemas que dependen del mensaje , en lugar de uno al otro. Dándole un acoplamiento menos estrecho entre los sistemas de comunicación. En ese punto, si necesita tener una dependencia entre sistemas, debe considerar si tiene los bits que dependen de los lugares correctos. Y a menudo es el caso que no.

Finalmente, el código complicado será complicado. A menudo no hay forma de evitar eso. Pero el código que tiene menos dependencias es mucho más fácil de entender que uno que se basa en varios estados externos.

Matt D
fuente
2
+1 para "Good Tailor's no deja resmas de tela en cada costura solo en caso de que crezca un tercer brazo o quede embarazada". A menudo tendemos a diseñar software de esta manera, lamentablemente.
Kemoda
Junto con la comprensibilidad, también se puede encontrar útil la abstracción al doblar una línea curva en una recta. Lo que significa que estás reduciendo la complejidad y / o la entropía con la abstracción. Tal vez algo así como un controlador de datos de tipo Curry donde la grasa que afeitas todavía sea útil más adelante.
Cody
13

Creo que nuestro objetivo es proporcionar buenas abstracciones sobre el modelo de dominio y la lógica de negocios dados.

Tengo una opinión diferente: nuestro objetivo es resolver un problema de negocios. Las abstracciones son solo una técnica para organizar una solución. Otra respuesta utiliza la analogía de un sastre haciendo ropa. Tengo otra analogía en la que me gusta pensar: un esqueleto. El código es como un esqueleto, y las abstracciones son las articulaciones entre los huesos. Si no tiene articulaciones, simplemente termina con un solo hueso que no puede moverse en absoluto y es inútil. Pero si tienes demasiadas articulaciones, terminas con un montón de gelatina descuidada que no puede sostenerse por sí sola. El truco es encontrar el equilibrio adecuado: suficientes articulaciones para permitir el movimiento, pero no tanto que no haya una forma o estructura definida real.

Jordan Lev
fuente