Abstração demais pode ser ruim?

46

Como programadores, sinto que nosso objetivo é fornecer boas abstrações no modelo de domínio e na lógica de negócios. Mas onde essa abstração deve parar? Como fazer a troca entre abstração e todos os seus benefícios (flexibilidade, facilidade de alteração, etc.) e facilidade de entender o código e todos os seus benefícios.

Acredito que escrevo códigos excessivamente abstratos e não sei como é bom; Costumo escrever como se fosse algum tipo de micro-framework, que consiste em duas partes:

  1. Micródulos acoplados à microestrutura: esses módulos são fáceis de entender, desenvolver e manter como unidades únicas. Esse código basicamente representa o código que realmente executa as coisas funcionais, descritas nos requisitos.
  2. Código de conexão; Agora, aqui, acredito, está o problema. Esse código tende a ser complicado porque às vezes é muito abstrato e difícil de ser entendido no início; isso ocorre devido ao fato de ser apenas pura abstração, sendo a base da realidade e da lógica de negócios executada no código apresentado 1; por esse motivo, não se espera que este código seja alterado uma vez testado.

Essa é uma boa abordagem de programação? Isso, tendo o código de alteração muito fragmentado em muitos módulos e muito fácil de entender e o código sem alteração muito complexo a partir da abstração POV? Todo o código deve ser uniformemente complexo (ou seja, código 1 mais complexo e interligado e código 2 mais simples), para que qualquer pessoa que o veja possa entendê-lo em um período de tempo razoável, mas a mudança seja cara ou a solução apresentada acima seja boa, onde "alterar código" é muito fácil de entender, depurar, alterar e "vincular código" é meio difícil.

Nota: não se trata de legibilidade de código! Os códigos 1 e 2 são legíveis, mas o código 2 vem com abstrações mais complexas, enquanto o código 1 vem com abstrações simples.

m3th0dman
fonte
3
Comentários e nomes claros são inventados para acelerar o tempo necessário para entender códigos complexos. Não há problema em seu código de nível inferior ser mais complexo; em algum nível, você certamente está chamando um nível muito mais complexo e muito mais baixo de qualquer maneira.
DougM
25
"Demais" é ruim por definição.
Jon Purdy
@ JimmyHoffa: Tenho que manter esses tipos no lugar deles. E não fique com ciúmes - não escrevo Haskell o dia todo . Na maioria das vezes, é PHP, JavaScript e OCaml.
Jon Purdy

Respostas:

78

As primeiras palavras de TC ++ PL4:

Todos os problemas em ciência da computação podem ser resolvidos por outro nível de indireção, exceto pelo problema de muitas camadas de indireção. - David J. Wheeler

(David Wheeler foi meu orientador de tese. A citação sem a última linha importante às vezes é chamada de "A primeira lei da Ciência da Computação".)

Bjarne
fonte
6
E como você sabe quando tem muitos níveis de indireção? Eu diria que isso vem com a experiência, mas um programador mais experiente entende facilmente mais indiretamente, portanto, não vê um problema com muitos níveis.
M3th0dman
2
@ m3th0dman - você tem o nível certo de abstração quando se torna fácil fazer alterações no futuro. Obviamente, você também pode perguntar como sabe quando isso ocorrerá, que apenas repete o ciclo de perguntas de uma maneira diferente.
1
essa pergunta depende do nível do programador .. você terá programadores complexos que entenderão sua arquitetura louca de camadas de 8 camadas e a acharão brilhante, enquanto outros codificadores simples, porém suaves, acharão ridículo e discutirão sobre sua louca de 8 camadas projeto em camadas .. isso é onde a documentação compensa, não só permitem que você documentar o seu código, mas permite que você para defendê-la
Ryan
1
perdoe a minha ignorância, mas eu não estou entendendo "TC ++ PL4"
LastTribunal
30

Sim definitivamente. O problema é que nenhuma abstração é perfeita. Todos os detalhes da camada em que as abstrações estão no topo estão lá por uma razão e podem simplificar muitas coisas, mas se essa complexidade não fosse necessária em algum momento, provavelmente não estaria lá em primeiro lugar. E isso significa que, em algum momento, toda abstração vazará de alguma maneira.

E é aí que reside o verdadeiro problema. Quando as abstrações falham, quanto mais você separa o código que você escreveu e o que realmente está acontecendo, mais difícil é descobrir o problema e corrigi-lo, porque há mais lugares onde o problema pode estar. E quanto mais camadas houver, mais você precisará saber para localizá-las.

Mason Wheeler
fonte
1
"E isso significa que, em algum momento, toda abstração vazará de alguma forma.": Verdade. Uma abstração melhor é aquela que vaza com menos frequência.
Giorgio
11
À luz da resposta de Bjarne (e referenciando página wiki de David Wheeler ), talvez você pode mudar a sua citação atribuição? :)
congusbongus
2
@CongXu: Btw, eu já fiz isso do outro lado: pesquisando as "citações de Bjarne Stroustrup" e não encontrei uma única referência de Bjarne ter pronunciado a frase "adicionando outra camada de indireção" ... Não é conclusivo, é claro, mas tornar altamente improvável que ele foi o primeiro a pronunciá-lo.
Marjan Venema
1
Mais camadas de abstração significam abstrações simples e, portanto, menos vazamento por abstração. Portanto, em uma formulação matemática (é claro, sem nenhuma prova), a soma do vazamento da abstração pode ser constante à medida que o número de níveis de abstração muda.
m3th0dman
2
Certa vez, ingenuamente, segui o conselho de um veterano para adicionar uma abstração onde não era necessária. Nunca foi usado além do que eu queria fazer em primeiro lugar.
precisa saber é o seguinte
15

Sim absolutamente.

A analogia que eu gosto de usar para explicar a programação é a de um alfaiate. Ao fazer um traje, um bom Alfaiate sempre deixa uma pequena quantidade de tecido em locais estratégicos dentro da peça para permitir que a peça seja retirada ou retirada, sem alterar sua forma ou estrutura geral.

Os Bons Alfaiates não deixam resmas de tecido em cada costura, apenas no caso de você crescer um terceiro braço ou engravidar. Demasiado material nos lugares errados resultará em um ajuste inadequado e vestuário mal vestido, o tecido extra simplesmente atrapalha o uso normal. Pouco tecido e a peça de roupa são propensos a rasgar e não poderão ser alterados para lidar com pequenas alterações no físico de seu usuário, afetando a maneira como a peça fica.

Talvez um dia, nosso Bom Alfaiate seja encarregado de fazer um vestido tão apertado que ele tenha que costurar seu vestido. E talvez seja pedido ao nosso Bom Alfaiate que use roupas de maternidade, onde o estilo e a forma sejam o segundo em conforto e capacidade de expansão. Porém, antes de realizar qualquer um desses trabalhos especiais, um bom Alfaiate seria sábio o suficiente para conscientizar todos sobre os compromissos que estão sendo feitos para alcançar esses objetivos.

Às vezes, esses compromissos são o caminho correto a ser seguido e as pessoas estão dispostas a aceitar suas conseqüências. Mas, na maioria dos casos, a abordagem de deixar um pouco o que mais importa superará quaisquer benefícios percebidos.

Então, relacionando isso de volta à abstração. É absolutamente possível ter muitas camadas de abstração, assim como é possível ter muito pouco. A verdadeira arte do programador, como nossos amigos alfaiates, é deixar um pouco onde mais importa.

Voltando ao tópico.

O problema com o código geralmente não é abstração, mas dependências. Como você apontou, é o código que conecta objetos discretos que é um problema, porque há uma dependência implícita entre eles. Em algum momento, a comunicação entre as coisas só precisa ser concreta, mas julgar onde esse ponto está geralmente requer alguma adivinhação.

Dito isto, "Micro" qualquer coisa é geralmente uma indicação de que você sobrecarregou demais o layout do objeto e provavelmente está usando Type como sinônimo do que deveria ser Data . Ter menos coisas também significa menos dependências necessárias para se comunicar entre elas.

Sou um grande fã de mensagens assíncronas entre sistemas por esse motivo. Você acaba com dois sistemas dependentes da mensagem , e não um com o outro. Proporcionando um acoplamento menos rígido entre os sistemas de comunicação. Nesse ponto, se você precisar ter uma dependência entre os sistemas, precisará considerar se possui os bits que dependem no (s) lugar (s) certo (s). E geralmente é o caso de você não.

Finalmente, código complicado vai ser complicado. Muitas vezes não há maneira de contornar isso. Mas o código que possui menos dependências é muito mais fácil de entender do que aquele que se baseia em vários estados externos.

Matt D
fonte
2
+1 em "Bons Alfaiates não deixe resmas de tecido em cada costura, apenas no caso de você crescer um terceiro braço ou engravidar". Infelizmente, costumamos projetar software dessa maneira.
Kemoda
Juntamente com a compreensibilidade, também é possível encontrar a abstração útil ao dobrar uma linha curva em uma reta. Significando que você está reduzindo a complexidade e / ou entropia com a abstração. Talvez algo como um manipulador de dados do tipo Curry, onde a gordura que você raspa ainda seja útil mais tarde.
Cody
13

Sinto que nosso objetivo é fornecer boas abstrações no modelo de domínio e na lógica de negócios fornecidos.

Eu tenho uma visão diferente: nosso objetivo é resolver um problema de negócios. Abstrações são apenas uma técnica para organizar uma solução. Outra resposta usa a analogia de um alfaiate que faz roupas. Tenho outra analogia em que gosto de pensar: um esqueleto. O código é como um esqueleto, e as abstrações são as articulações entre os ossos. Se você não tem articulações, simplesmente acaba com um único osso que não pode se mover e é inútil. Mas se você tem muitas articulações, acaba com uma pilha de gelatina desleixada que não consegue se sustentar sozinha. O truque é encontrar o equilíbrio certo - articulações suficientes para permitir o movimento, mas não tanto que não exista nenhuma forma ou estrutura definida.

Jordan Lev
fonte