Como determinar os níveis de abstração


35

Hoje eu estava lendo um livro chamado "Código Limpo" e me deparei com um parágrafo em que o autor estava falando sobre os níveis de abstração por função, ele classificou algum código como baixo / intermediário / alto nível de abstração.

Minha pergunta é: quais são os critérios para determinar o nível de abstração?

Cito o parágrafo do livro:

Para garantir que nossas funções estejam realizando "uma coisa", precisamos garantir que as declarações dentro de nossa função estejam no mesmo nível de abstração. É fácil ver como a Lista 3-1 viola essa regra. Existem conceitos que estão em um nível muito alto de abstração, como getHtml (); outros que estão em um nível intermediário de abstração, como: String pagePathName = PathParser.render (pagePath); e ainda outros que são notavelmente baixos, como: .append ("\ n").


Respostas:


27

O autor explica que na subseção "Lendo código de cima para baixo" da parte que fala sobre abstrações (mina de indentação hierárquica):

[...] queremos poder ler o programa como se fosse um conjunto de parágrafos TO , cada um dos quais descrevendo o nível atual de abstração e referenciando parágrafos TO subsequentes no próximo nível abaixo.

  • Para incluir as configurações e desmontagens, incluímos configurações, o conteúdo da página de teste e as desmontagens.
    • Para incluir as configurações, incluímos a configuração da suíte, se for uma suíte, e a configuração regular.
      • Para incluir a configuração do conjunto, pesquisamos na hierarquia pai a página "SuiteSetUp" e adicionamos uma instrução de inclusão com o caminho dessa página.
        • Para pesquisar os pais ...

O código que iria junto com isso seria algo como isto:

public void CreateTestPage()
{
    IncludeSetups();
    IncludeTestPageContent();
    IncludeTeardowns();
}

public void IncludeSetups()
{
    if(this.IsSuite())
    {
        IncludeSuiteSetup();
    }

    IncludeRegularSetup();
}

public void IncludeSuiteSetup()
{
    var parentPage = FindParentSuitePage();

    // add include statement with the path of the parentPage
}

E assim por diante. Toda vez que você se aprofundar na hierarquia de funções, deverá alterar os níveis de abstração. No exemplo acima, IncludeSetups, IncludeTestPageContente IncludeTeardownsestão todos no mesmo nível de abstracção.

No exemplo dado no livro, o autor sugere que a grande função deve ser dividida em menores, que são muito específicas e fazem apenas uma coisa. Se bem feita, a função refatorada seria semelhante aos exemplos aqui. (A versão refatorada é fornecida na Lista 3-7 do livro.)


10

Eu acho que para entender essa pergunta, você precisa entender o que é uma abstração. (Estou com preguiça de encontrar uma definição formal, então tenho certeza de que estou prestes a ser enganada, mas aqui vai ...) Uma abstração é quando você pega um assunto ou entidade complexo e oculta a maioria dos detalhes enquanto expõe a funcionalidade que ainda define a essência desse objeto.

Acredito que o exemplo que o livro lhe deu foi uma casa. Se você der uma olhada muito detalhada na casa, verá que ela é feita de tábuas, pregos, janelas, portas ... Mas o desenho de uma casa ao lado de uma fotografia ainda é uma casa, mesmo que esteja ausente muitos desses detalhes.

A mesma coisa com o software. Sempre que você programa, como o livro recomenda, você precisa pensar no seu software como camadas. Um determinado programa pode facilmente ter bem mais de cem camadas. Na parte inferior, você pode ter instruções de montagem que são executadas em uma CPU; em um nível superior, essas instruções podem ser combinadas para formar rotinas de E / S de disco; em um nível ainda mais alto, não é necessário trabalhar com o Disk I / O diretamente, porque você pode usar as funções do Windows para simplesmente Abrir / Ler / Gravar / Procurar / Fechar um arquivo. Essas são todas abstrações antes mesmo de você chegar ao seu próprio código de aplicativo.

Dentro do seu código, as camadas de abstração continuam. Você pode ter rotinas de manipulação de cadeia / rede / dados de nível inferior. Em um nível superior, você pode combinar essas rotinas em subsistemas que definem gerenciamento de usuários, camada da interface do usuário e acesso ao banco de dados. Ainda outra camada, esses subsistemas podem ser combinados em componentes de servidor que se juntam para se tornar parte de um sistema corporativo maior.

A chave para cada uma dessas camadas de abstração é que cada uma oculta os detalhes expostos pelas camadas anteriores e apresenta uma interface muito limpa para ser consumida pela próxima camada acima. Para abrir um arquivo, você não precisa saber como escrever setores individuais ou o hardware interrompe o processo. Porém, se você começar a percorrer a cadeia da camada de abstração, poderá rastrear desde a chamada de função Write () até a instrução exata que é enviada ao controlador do disco rígido.

O que o autor está dizendo para você fazer é quando você define uma classe ou uma função, pense em qual camada você é uma. Se você tem uma classe que está gerenciando subsistemas e objetos de usuário, a mesma classe não deve estar executando manipulação de seqüência de caracteres de baixo nível ou conter um monte de variáveis ​​apenas para fazer chamadas de soquete. Isso seria a violação de atravessar camadas de abstração e também de ter uma classe / função fazendo apenas uma coisa (SRP - Single Responsibility Princípio).


2

Minha pergunta é: quais são os critérios para determinar o nível de abstração?

O nível de abstração é suposto ser óbvio. É abstrato se faz parte do domínio do problema - não faz parte da linguagem de programação. É difícil ser mais claro do que "altamente abstrato" == "não real" == "domínio do problema". E "não abstrato == concreto == parte da linguagem". É suposto ser trivial decidir o nível de abstração. Não deveria haver nenhuma sutileza.

.append("\n")não é abstrato. Apenas coloca um personagem em uma string. Isso seria concreto. Não é abstrato.

String pagePathName = PathParser.render(pagePath);lida com Strings. Coisas concretas. Parcialmente em recursos concretos da linguagem de programação. Parcialmente trabalhando com os conceitos abstratos de "caminho" e "analisador".

getHtml(); Abstrato. Lida com "Marcações" e coisas que não são triviais, concretas, recursos de linguagem.

Resumo == não é um recurso de idioma.

Concreto == um recurso de idioma.


11
Se você definir resumo como uma qualidade que descreva as coisas que um programador cria, ou seja, abstrações geradas por programadores, estou inclinado a concordar com suas definições de palavras. Mas todas as linguagens de programação são abstrações sobre algo mais concreto. A escolha da linguagem de programação determina, em grande medida, em que nível de abstração você inicia.
Robert Harvey

1

Eu acho que o nível de abstração é simples ... se a linha de código não implementa diretamente a responsabilidade única do método, é outro nível de abstração. Por exemplo, se o nome do meu método for SaveChangedCustomers () e usar uma lista de TODOS os clientes como parâmetro, a única responsabilidade é salvar todos os clientes na lista que foram alterados:

foreach(var customer in allCustomers)
{
    if (CustomerIsChanged(customer)
        customer.Save();
}

Frequentemente, em vez de chamar o método CustomerIsChanged (), você encontrará a lógica para determinar se o cliente mudou incorporado no loop foreach. Determinar se o registro do cliente foi alterado NÃO é responsabilidade deste método! É um nível diferente de abstração. Mas e se a lógica para fazer essa determinação for apenas uma linha de código? Não importa!!! É um nível diferente de abstração e precisa estar fora desse método.

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.