Come determinare i livelli di astrazione

30

Stavo leggendo un libro oggi chiamato "Pulisci codice" e mi sono imbattuto in un paragrafo in cui l'autore era parlando dei livelli di astrazione per una funzione, ha classificato alcuni codici come livello basso / intermedio / alto di astrazione.

La mia domanda è quali sono i criteri per determinare il livello di astrazione?

Cito il paragrafo dal libro:

In order to make sure our functions are doing “one thing,” we need to make sure that the statements within our function are all at the same level of abstraction. It is easy to see how Listing 3-1 violates this rule. There are concepts in there that are at a very high level of abstraction, such as getHtml(); others that are at an intermediate level of abstraction, such as: String pagePathName = PathParser.render(pagePath); and still others that are remarkably low level, such as: .append("\n").

    
posta OKAN 27.09.2011 - 05:30
fonte

4 risposte

24

L'autore spiega che nella sottosezione "Leggere il codice dall'alto verso il basso" della parte che parla delle astrazioni (miniera di rientri gerarchica):

[...] we want to be able to read the program as though it were a set of TO paragraphs, each of which is describing the current level of abstraction and referencing subsequent TO paragraphs at the next level down.

  • To include the setups and teardowns, we include setups, then we include the test page content, and then we include the teardowns.
    • To include the setups, we include the suite setup if this is a suite, then we include the regular setup.
      • To include the suite setup, we search the parent hierarchy for the "SuiteSetUp" page and add an include statement with the path of that page.
        • To search the parent ...

Il codice che andrebbe insieme a questo sarebbe qualcosa di simile a questo:

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 così via. Ogni volta che vai più in profondità nella gerarchia delle funzioni, dovresti cambiare i livelli di astrazione. Nell'esempio sopra, IncludeSetups , IncludeTestPageContent e IncludeTeardowns sono tutti allo stesso livello di astrazione.

Nell'esempio fornito nel libro, l'autore suggerisce che la grande funzione dovrebbe essere suddivisa in più piccole che sono molto specifiche e fanno una sola cosa. Se fatto bene, la funzione refactored sarebbe simile agli esempi qui. (La versione refactored è riportata nel Listato 3-7 del libro.)

    
risposta data 27.09.2011 - 06:02
fonte
9

Penso che per capire questa domanda, devi capire cos'è un'astrazione. (Sono troppo pigro per trovare una definizione formale, quindi sono sicuro che sto per venir maneggiato, ma qui va ...) Un'astrazione è quando prendi un soggetto o un'entità complessi e nascondi la maggior parte dei suoi dettagli esponendo la funzionalità che definisce ancora l'essenza di quell'oggetto.

Credo che l'esempio che il libro ti ha dato fosse una casa. Se guardi in modo molto dettagliato la casa, vedrai che è fatta di tavole, chiodi, finestre, porte ... Ma un disegno a fumetti di una casa accanto a una fotografia è ancora una casa, anche se manca molti di questi dettagli.

La stessa cosa con il software. Ogni volta che si programma, proprio come il libro consiglia, è necessario pensare al proprio software come livelli. Un dato programma può facilmente avere oltre cento strati. Nella parte inferiore, potresti avere istruzioni di assemblaggio che girano su una CPU, a un livello più alto queste istruzioni potrebbero essere combinate per formare routine di I / O su disco, ad un livello ancora più alto, non è necessario lavorare con Disk I / O direttamente perché puoi usare le funzioni di Windows semplicemente per aprire / leggere / scrivere / cercare / chiudere un file. Queste sono tutte astrazioni anche prima di arrivare al tuo codice applicazione.

All'interno del tuo codice, i livelli di astrazione continuano. Potresti avere routine di stringa / rete / manipolazione dei dati di livello inferiore. Ad un livello superiore è possibile combinare tali routine in sottosistemi che definiscono la gestione degli utenti, il livello dell'interfaccia utente, l'accesso al database. Ancora un altro livello questi sottosistemi potrebbero essere combinati in componenti server che si uniscono per diventare parte di un sistema aziendale più grande.

La chiave per ciascuno di questi livelli di astrazione è che ognuno nasconde i dettagli esposti dai precedenti layer e presenta un'interfaccia molto pulita da consumare dal livello successivo. Per aprire un file, non dovresti sapere come scrivere singoli settori o quali interrupt hardware elaborare. Ma se inizi a percorrere la catena del livello di astrazione, sarai sicuramente in grado di risalire dalla chiamata della funzione Write (), fino all'istruzione esatta che viene inviata al controller del disco rigido.

Ciò che l'autore ti sta dicendo di fare è quando definisci una classe o una funzione, pensa a quale livello sei uno. Se si dispone di una classe che gestisce sottosistemi e oggetti utente, la stessa classe non deve eseguire manipolazioni di stringhe di basso livello o contenere un intero gruppo di variabili solo per effettuare chiamate socket. Questa sarebbe la violazione dei livelli di astrazione incrociati e anche di avere una classe / funzione fare una sola cosa (SRP - Single Responsibility Principle).

    
risposta data 27.09.2011 - 06:10
fonte
2

My question is what is the criteria for determining the level of abstraction?

Il livello di astrazione dovrebbe essere ovvio. È astratto se fa parte del dominio del problema - non fa parte del linguaggio di programmazione. È difficile essere più chiaro di "altamente astratto" == "non vero" == "dominio problematico". E "non astratto == concreto == parte della lingua". Dovrebbe essere banale decidere il livello di astrazione. Non ci dovrebbe essere alcuna sottigliezza.

.append("\n") non è astratto. Mette semplicemente un personaggio su una stringa. Sarebbe concreto. Non astratto.

String pagePathName = PathParser.render(pagePath); riguarda le stringhe. Cose concrete In parte su concrete funzionalità di linguaggio di programmazione. Lavorare parzialmente con concetti astratti "path" e "parser".

getHtml(); Astratto. Gestisce "Markup" e cose che non sono caratteristiche banali, concrete e linguistiche.

Abstract == non è una funzione linguistica.

Concrete == una funzionalità linguistica.

    
risposta data 27.09.2011 - 06:00
fonte
0

Penso che il livello di astrazione sia semplice ... se la linea di codice non implementa direttamente la singola responsabilità del metodo, è un altro livello di astrazione. Ad esempio, se il mio nome metodo è SaveChangedCustomers () e prende come parametro un elenco di TUTTI i clienti, la sola responsabilità è quella di salvare tutti i clienti nell'elenco che sono stati modificati:

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

Spesso, invece di chiamare il metodo CustomerIsChanged (), troverai la logica per determinare se il cliente è stato modificato incorporato nel ciclo foreach. Determinare se il record del cliente è cambiato NON è responsabilità di questo metodo! È un diverso livello di astrazione. Ma cosa succede se la logica per fare quella determinazione è solo una riga di codice? Non importa !!! È un diverso livello di astrazione e deve essere al di fuori di questo metodo.

    
risposta data 23.08.2017 - 18:38
fonte

Leggi altre domande sui tag