Quando escrever código abstrato e quando ser mais específico?


9

Estou trabalhando em uma pequena ferramenta como um projeto de brinquedo para mostrar a diferença entre dois diretórios, mostrando quais arquivos / diretórios foram adicionados, removidos, modificados etc.

Eu estava tentando representar essas alterações como objetos simplesmente 'ChangeItem', sem distinção entre se era um arquivo ou diretório. No entanto, isso criou muitos problemas, por exemplo, como exibi-los em uma árvore, como saber quem é o pai de uma criança, etc. E também foi muito pouco intuitivo.

Em seguida, divido as alterações entre as alterações de diretório e de arquivo. Isso imediatamente tornou muito fácil codificar e entender o que estava acontecendo. Agora é muito mais simples selecionar todos os arquivos em um diretório, etc.

Minha pergunta é: como alguém pode saber se deve usar abstração ou se é mais específico em seu código? Como você pode saber se possui muita ou pouca abstração?

Respostas:


9

Como um pintor sabe se é muito ou pouco roxo?

Ele mistura as cores, tenta um traço, faz alguns esboços e vê o que acontece. Depois, ele ajusta as proporções até que o desenho inteiro pareça agradável e irradie harmonia.

Fazemos o mesmo com o código. Temos uma idéia de implementação pela primeira vez, refletimos sobre ela, analisamos seus aspectos fortes e semanais e tentamos ver se funciona. Em seguida, sintonizamos a idéia em um processo iterativo para ajustar as proporções de abstratividade, encapsulamento, polimorfismo e o que quer que seja até que pareça correta e funcione conforme necessário.


21

Você escreve um código concreto primeiro.

Você escreve código abstrato quando necessário, porque simplifica o código concreto.

É mais fácil começar com o concreto e encontrar as abstrações depois de estudar o que é semelhante e diferente sobre o concreto.


13
Lembre-se sempre da regra dos três: uma abstração sem pelo menos três clientes não é uma abstração. É uma ilusão. Geralmente errado. Uma boa abstração é extraída , não projetada.
Jörg W Mittag

3

Você escreve código abstrato ao escrever bibliotecas e deve generalizar a funcionalidade para que funcione sob uma ampla variedade de condições.

Mas escrever bibliotecas dessa maneira é difícil. Em um aplicativo normal (por exemplo, um aplicativo de linha de negócios), esse tipo de generalização é considerado uma forma de "otimização prematura", geralmente caracterizada como "Você não vai precisar" (YAGNI).

Há um ponto de inflexão em que o código repetitivo exige que uma solução mais generalizada seja projetada. Mas normalmente esse tipo de refatoração para remover redundância é muito mais simples do que escrever uma biblioteca generalizada.

No final, a complexidade adicional necessária para implementar soluções abstratas deve ser justificada pela flexibilidade que elas oferecem.


3

A regra geral que sigo, que é bastante comum, é que você não deve tentar abstrair algo até que se encontre escrevendo pela terceira vez.

Na primeira vez, você simplesmente não entende o domínio do problema e acaba arquitectando demais todas as peças erradas. Na segunda vez, você está perfeitamente posicionado para criar a solução ideal para o seu último problema. Na terceira vez, você está finalmente em uma boa posição para criar abstrações apropriadas que o ajudarão nas coisas que precisam mudar, e não atrapalharão em fazer as coisas simples.


1
A terceira vez é uma boa regra de ouro. Acho raro generalizar muito antes da terceira vez escrevendo algo.
Quentin-starin

1
Também não depende do tamanho do código semelhante? Você não copiava e colava duas páginas de código que eram diferentes apenas por duas linhas, apenas porque ainda não havia atingido o mágico "três vezes".
Scott Whitlock

@ scott-whitlock: Obviamente. É por isso que é uma regra de ouro. Ignore-o conforme apropriado. Além disso, há uma diferença entre abstrações orgânicas (por exemplo, "eu precisava que a barra fosse quase exatamente foo, então acabei de adicionar um parâmetro opcional a foo") e abstrações que fazem parte do seu projeto inicial.
btilly

1
@ Scott Whitlock: "Você não copia e cola duas páginas de código que são diferentes apenas por duas linhas". Isso não é um pedido de abstração. Ainda é apenas um bom design. A regra 3x deve manter-se muito, muito rigorosamente, para evitar desenhos prematuramente abstratos.
S.Lott

"Conforme apropriado" é a frase-chave aqui. Meus dois centavos - geralmente a "prefere composição à herança" se aplica. Às vezes, um problema que alguns resolvem com uma abstração seria melhor como if (cond) { //use one object} else {// use the other object }, esp. quando é um conjunto de decisões binárias.
Michael K

2

Ao ler a pergunta, eu diria que você pode ser abstrato e específico. É apenas uma questão de contexto, use a representação mais abstrata possível em cada contexto.

Para seu aplicativo de brinquedo específico, ChangeItemé a representação mais abstrata das alterações. Então você fica mais específico com DirectoryChangeIteme FileChangeItem, por herança. Você pode usar um padrão composto para modelar a árvore. Quando você deseja exibi-lo, pode usar as representações específicas e, ao atravessá-lo, pode usar a representação abstrata.

E para dar uma resposta concreta à pergunta: seja o mais específico possível até sentir que precisa de outra camada abaixo dela.


1

Normalmente, a abstração é útil para combater coisas como Complexidade, Entropia, para tornar seu código cibernético e até com uma legibilidade de baixo nível. Eu codificaria primeiro - SOMENTE se a abstração não for óbvia na frente. A maioria das abstrações ocorre quando mais de uma implementação compartilha o mesmo padrão.

Pense na abstração como a congruência ou unidade de 2 ou mais Conjuntos. Tome um diagrama de Venn como um modelo simplista: a parte em que os círculos se sobrepõem ou, em outras palavras, os conjuntos se fundem.

Se eu tiver dois conjuntos: A: {a, b, c, d, e} e B: {d, e, f, g, h}. O ponto em que eu começaria a procurar abstrair é a unidade de A + B; {d, e} é onde abstrair. Da mesma forma, se aqueles na diferença de A e B (AB ou BA) são isomórficos entre si, significando seu baixo custo para criar a, b ou c a partir de f, g ou h (e vice-versa), então eu manteria a abstração No fundo da minha mente.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.