Comment déterminer les niveaux d'abstraction

35

Je lisais aujourd'hui un livre intitulé "Code propre" et je suis tombé sur un paragraphe où l'auteur parlait des niveaux d'abstraction par fonction, il a classé certains codes en niveaux d'abstraction faible / intermédiaire / élevé.

Ma question est: quels sont les critères pour déterminer le niveau d’abstraction?

Je cite le paragraphe du livre:

Afin de nous assurer que nos fonctions font «une chose», nous devons nous assurer que les déclarations de notre fonction ont toutes le même niveau d'abstraction. Il est facile de voir en quoi Listing 3-1 enfreint cette règle. Il y a des concepts à un très haut niveau d'abstraction, tels que getHtml (); d'autres qui sont à un niveau d'abstraction intermédiaire, tels que: String pagePathName = PathParser.render (pagePath); et d'autres encore qui sont remarquablement bas, tels que: .append ("\ n").

OKAN
la source
2
Connexes: Qu'est-ce que l'abstraction? .
Adam Lear

Réponses:

27

L'auteur explique que, dans la sous-section "Lecture du code de haut en bas" de la partie qui traite des abstractions (mien d'indentation hiérarchique):

[...] nous voulons pouvoir lire le programme comme s'il s'agissait d'un ensemble de paragraphes TO , chacun décrivant le niveau actuel d'abstraction et référençant les paragraphes TO suivants au niveau inférieur.

  • Pour inclure les configurations et les démontages, nous incluons les configurations, puis le contenu de la page de test, puis les démontages.
    • Pour inclure les configurations, nous incluons la configuration de la suite s'il s'agit d'une suite, puis nous incluons la configuration normale.
      • Pour inclure la configuration de la suite, nous recherchons la page "SuiteSetUp" dans la hiérarchie parent et ajoutons une instruction include avec le chemin de cette page.
        • Pour rechercher le parent ...

Le code qui irait avec ceci ressemblerait à ceci:

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
}

Etc. Chaque fois que vous approfondissez la hiérarchie des fonctions, vous devez modifier les niveaux d'abstraction. Dans l'exemple ci - dessus, IncludeSetups, IncludeTestPageContentet IncludeTeardownssont tous au même niveau d'abstraction.

Dans l'exemple donné dans le livre, l'auteur suggère que la grande fonction devrait être divisée en de plus petites fonctions très spécifiques qui ne font qu'une chose. Si cela est fait correctement, la fonction refactorisée ressemblerait aux exemples ici. (La version refactorisée est donnée dans l'extrait 3-7 du livre.)

Adam Lear
la source
10

Je pense que pour comprendre cette question, il faut comprendre ce qu'est une abstraction. (Je suis trop paresseux pour trouver une définition formelle, donc je suis sur le point de m'énerver, mais voilà ...) Une abstraction est quand vous prenez un sujet complexe ou une entité et cachez la plupart de ses détails tout en exposant la fonctionnalité qui définit toujours l'essence de cet objet.

Je crois que l'exemple que le livre vous a donné était une maison. Si vous jetez un coup d'oeil très détaillé à la maison, vous verrez qu'elle est faite de planches, de clous, de fenêtres, de portes ... Mais le dessin humoristique d'une maison à côté d'une photo est toujours une maison, même s'il en manque beaucoup de ces détails.

Même chose avec un logiciel. Comme vous le recommandez, chaque fois que vous programmez, vous devez considérer votre logiciel sous forme de couches. Un programme donné peut facilement comporter plus d'une centaine de couches. En bas, vous pouvez avoir des instructions d'assemblage qui s'exécutent sur un processeur. À un niveau supérieur, ces instructions peuvent être combinées pour former des routines d'E / S de disque. À un niveau encore supérieur, vous n'avez pas besoin de travailler avec Disk I / O directement parce que vous pouvez utiliser les fonctions Windows pour simplement ouvrir / lire / écrire / chercher / fermer un fichier. Ce sont toutes des abstractions avant même que vous obteniez votre propre code d'application.

Dans votre code, les couches d'abstraction continuent. Vous pourriez avoir des routines de niveau inférieur / réseau / manipulations de données. À un niveau supérieur, vous pouvez combiner ces routines en sous-systèmes définissant la gestion des utilisateurs, la couche d'interface utilisateur et l'accès à la base de données. Encore une autre couche, ces sous-systèmes peuvent être combinés dans des composants de serveur qui s’unissent pour faire partie d’un système plus vaste.

La clé de chacune de ces couches d'abstraction est que chacune d'elles cache les détails exposés par la ou les couches précédentes et présente une interface très propre à utiliser par la couche suivante. Pour ouvrir un fichier, vous ne devriez pas avoir besoin de savoir comment écrire des secteurs individuels ni quelles interruptions matérielles traiter. Mais si vous commencez à voyager le long de la chaîne de la couche d'abstraction, vous serez certainement en mesure de tracer depuis l'appel de la fonction Write () jusqu'à l'instruction exacte envoyée au contrôleur de disque dur.

Ce que l’auteur vous dit de faire, c’est que lorsque vous définissez une classe ou une fonction, réfléchissez à la couche que vous êtes. Si vous avez une classe qui gère des sous-systèmes et des objets utilisateur, la même classe ne doit pas effectuer de manipulation de chaîne de bas niveau ni contenir un grand nombre de variables uniquement pour effectuer des appels de socket. Cela constituerait une violation des couches d'abstraction croisées et le fait d'avoir une classe / fonction ne ferait qu'une chose (PRS - Principe de responsabilité unique).

DXM
la source
2

Ma question est: quels sont les critères pour déterminer le niveau d’abstraction?

Le niveau d'abstraction est censé être évident. C'est abstrait si cela fait partie du domaine du problème et non du langage de programmation. Il est difficile d’être plus clair que "hautement abstrait" == "pas réel" == "problème". Et "pas abstrait == concret == partie de la langue". C'est supposé être trivial de décider du niveau d'abstraction. Il ne doit y avoir aucune subtilité.

.append("\n")n'est pas abstrait. Il met simplement un caractère sur une chaîne. Ce serait concret. Pas abstrait.

String pagePathName = PathParser.render(pagePath);traite des cordes. Des choses concrètes. En partie sur les fonctionnalités concrètes du langage de programmation. Utilisation partielle des concepts abstraits de "chemin" et de "parseur".

getHtml(); Abstrait. Traite des "balises" et des choses qui ne sont pas triviales, concrètes, les fonctionnalités du langage.

Résumé == pas une langue.

Concrete == une fonctionnalité de langue.

S.Lott
la source
1
Si vous définissez abstract comme une qualité décrivant les éléments créés par un programmeur, à savoir les abstractions générées par ce dernier, alors je suis enclin à accepter vos définitions de mots. Mais tous les langages de programmation sont des abstractions sur quelque chose de plus concret. Le choix du langage de programmation détermine dans une large mesure le niveau d'abstraction auquel vous commencez.
Robert Harvey
1

Je pense que le niveau d'abstraction est simple ... Si la ligne de code n'implémente pas directement la responsabilité de la méthode, c'est un autre niveau d'abstraction. Par exemple, si mon nom de méthode est SaveChangedCustomers () et prend une liste de TOUS les clients en tant que paramètre, la seule responsabilité consiste à enregistrer tous les clients de la liste qui ont été modifiés:

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

Souvent, au lieu d'appeler la méthode CustomerIsChanged (), vous trouverez la logique permettant de déterminer si le client a été intégré dans la boucle foreach. Déterminer si la fiche client a changé n’est PAS la responsabilité de cette méthode! C'est un niveau d'abstraction différent. Mais que se passe-t-il si la logique pour prendre cette décision n’est qu’une ligne de code? Peu importe !!! C'est un niveau d'abstraction différent et doit être en dehors de cette méthode.

utilisateur7542047
la source