Qu'est-ce que «l'abstraction prématurée»?

10

J'ai entendu la phrase être lancée et pour moi les arguments semblent complètement fous (désolé si je fais de la paille ici, ce n'est pas mon intention), généralement cela va quelque chose dans le sens de:

Vous ne voulez pas créer une abstraction avant de savoir quel est le cas général, sinon (1) vous pourriez mettre dans vos abstractions des choses qui n'appartiennent pas, ou (2) omettre des choses importantes.

(1) Pour moi, cela semble que le programmeur n'est pas assez pragmatique, ils ont fait des suppositions que les choses existeraient dans le programme final qui ne fonctionne pas, donc ils travaillent avec un niveau d'abstraction bas, le problème n'est pas l'abstraction prématurée, c'est la concrétion prématurée.

(2) L'omission de choses importantes est une chose, il est tout à fait possible que quelque chose soit omis de la spécification qui s'avère plus tard important, la solution à cela n'est pas de trouver vos propres ressources de concrétion et de gaspillage lorsque vous vous découvrez deviné mal, c'est pour obtenir plus d'informations du client.

Nous devons toujours travailler des abstractions jusqu'aux concrétions car c'est la façon la plus pragmatique de faire les choses, et non l'inverse.

Si nous ne le faisons pas, nous risquons de mal comprendre les clients et de créer des choses qui doivent être changées, mais si nous construisons uniquement les abstractions que les clients ont définies dans leur propre langue, nous ne risquons jamais ce risque (au moins loin d'être aussi probable que de prendre un coup dans le noir avec une certaine concrétion), oui, il est possible que les clients changent d'avis sur les détails, mais les abstractions qu'ils utilisaient à l'origine pour communiquer ce qu'ils veulent ont tendance à être toujours valables.

Voici un exemple, supposons qu'un client souhaite que vous créiez un robot d'ensachage d'articles:

public abstract class BaggingRobot() {
    private Collection<Item> items;

    public abstract void bag(Item item);
}

Nous construisons quelque chose à partir des abstractions utilisées par le client sans entrer dans les détails avec des choses que nous ne savons pas. C'est extrêmement flexible, j'ai vu cela être appelé "abstraction prématurée" alors qu'en réalité il serait plus prématuré de supposer comment l'ensachage a été mis en œuvre, disons après avoir discuté avec le client qu'il veut que plus d'un article soit mis en sac à la fois . Afin de mettre à jour ma classe, tout ce dont j'ai besoin est de changer la signature, mais pour quelqu'un qui a commencé de bas en haut, cela pourrait impliquer une refonte complète du système.

Il n'y a pas d'abstraction prématurée, seulement de concrétion prématurée. Quel est le problème avec cette déclaration? Où sont les défauts de mon raisonnement? Merci.

James
la source
1
L'opposé de l'abstraction prématurée est YAGNI - You Ain't Gonna Need It, qui à mon avis est presque toujours faux. Presque. Je l'ai vu arriver, mais c'est rare. Je suis principalement d'accord avec ce que vous dites ici.
user1118321

Réponses:

19

À mon avis, au moins, l'abstraction prématurée est assez courante, et elle l'était surtout au début de l'histoire de la POO.

Au moins d'après ce que j'ai vu, le problème majeur qui s'est posé est que les gens lisent les exemples typiques de hiérarchies orientées objet. On leur a beaucoup parlé de tout préparer pour faire face aux changements futurs qui pourraient survenir (même s'il n'y avait aucune raison particulière de croire qu'ils le feraient). Un autre thème commun à de nombreux articles pendant un certain temps était des choses comme l'ornithorynque, qui défie les règles simples sur «les mammifères sont tous comme ça» ou «les oiseaux sont tous comme ça».

En conséquence, nous nous sommes retrouvés avec un code qui n'avait vraiment besoin que de traiter, par exemple, les dossiers des employés, mais qui avait été soigneusement écrit pour être prêt si vous aviez engagé un arachnide ou peut-être un crustacé.

Jerry Coffin
la source
Donc, l'abstraction prématurée n'est pas l'acte d'abstraire, c'est l'acte d'abstraire au-delà du niveau d'abstraction des spécifications. Cela a beaucoup plus de sens et je pouvais voir que cela se produisait. Je suppose que je dois juste préciser à mes collègues que je travaille au niveau d'abstraction décrit par mon manager.
James
1
@James: cela peut aussi signifier d'abstraire "trop" au-delà des spécifications de la version 1.0, car vous croyez connaître une nouvelle exigence dans les spécifications d'une version ultérieure, donc implémentez déjà la v1.0 d'une manière plus générale que nécessaire. Quelque chose, il est bon d’envisager ce qui pourrait arriver dans une version ultérieure, mais il y a aussi un certain risque de suringénierie.
Doc Brown
@DocBrown J'appellerais cela une concrétion prématurée. L'acte d'abstraction consiste à supprimer des informations et non à les ajouter. Si vous ajoutez plus à l'abstraction que nécessaire, vous supposez quelque chose à propos de niveaux d'abstraction inférieurs. Je voudrais faire la différence entre les deux car je pense qu'appeler "abstraction" n'a pas beaucoup de sens car la définition de l'abstraction est "le processus d'extraction de l'essence sous-jacente" Où est la concrétion "caractérisée par ou appartenant à l'expérience immédiate des choses ou des événements réels ".
James
6

Il est important de se rappeler que l'abstraction est un moyen de parvenir à une fin. Vous utilisez l'abstraction pour uniformiser le comportement dans votre programme et simplifiez l'ajout de nouvelles classes dans les cas où vous vous attendez à ce que de nouvelles classes soient ajoutées, mais uniquement lorsque l'abstraction est nécessaire à ce moment précis.

Vous n'ajouteriez pas d'abstraction simplement parce que vous pourriez en avoir besoin (sans aucune base réelle pour penser que vous devrez ajouter de nouvelles classes à l'avenir). Une métaphore appropriée ici pourrait être la plomberie. J'espère que vous conviendrez qu'un tuyau à 6 directions qui permet à l'eau de monter / descendre, est / ouest, nord / sud serait le type de tuyau le plus flexible que vous pourriez avoir. Vous pourriez théoriquement utiliser un tuyau à 6 directions partout où un tuyau est requis et bloquer les directions inutiles, non?

Si vous avez essayé de résoudre un problème de fuite sous votre évier et que vous avez trouvé que toutes les sections de tuyau étaient des morceaux de tuyau à 6 directions, vous voudriez vous arracher les cheveux, frustré par le gars qui l'a conçu de cette façon. Non seulement vous ne savez pas où est le problème, mais il serait presque certainement plus simple de simplement recommencer à zéro de manière appropriée.

Bien sûr, le codage n'est pas de la plomberie, mais la métaphore est toujours d'actualité. L'abstraction, c'est comme utiliser ces pièces de tuyau à 6 directions. Utilisez-les lorsque vous croyez honnêtement que vous devrez peut-être un jour dans un proche avenir connecter des tuyaux dans les 6 directions. Sinon, l'abstraction est simplement une complication, pas très différente de l'utilisation d'un modèle où aucun n'est requis ou de l'utilisation d'une classe divine qui essaie de tout faire. S'il n'est pas utilisé et ne sera probablement jamais utilisé, vous ajoutez finalement une classe supplémentaire pour rien.

Certes, l'art d'écrire des programmes est conceptuellement très très abstrait. Il convient simplement de mentionner que les abstractions n'existent pas pour être une abstraction, mais parce qu'elles sont pratiques d'une certaine manière. Si vous ressentez le besoin d'utiliser l'abstraction, qu'il en soit ainsi, mais ne me demandez pas de vérifier votre plomberie par la suite. ;)

Neil
la source
Vous semblez un peu classexcentrique… Même s'il y a beaucoup de classes, l'abstraction n'est pas limitée à être utilisée / bénéfique pour elles.
Déduplicateur
1
@Deduplicator Assez bien, mais cela ne change pas mon point. Si l'abstraction est utilisée, elle devrait être immédiatement bénéfique ou devrait être un changement planifié dans un avenir proche. Peu importe que nous parlions de classes ou de programmation fonctionnelle.
Neil
3

Lorsque j'ai découvert l'analyse et la conception orientées objet, il y a de nombreuses années, nous commencions par une description en anglais simple du système dont le client avait besoin.

En regardant à travers cela, tout nom (ou phrase nominale) serait considéré comme une classe possible. Tous les verbes (ou phrases verbales) seraient des méthodes potentielles sur les classes. Donc, "robot d'ensachage" pourrait être une classe BaggingRobot. "Ouvrir un sac" pourrait devenir une méthode OpenBag.

Après quelques itérations, cela deviendrait un diagramme de classes.

À ce stade, il n'y a pas de classes abstraites. Le client ne veut pas d'un concept abstrait de robot d'ensachage. Ils veulent un robot qui met les choses dans des sacs. Toutes les classes sont concrètes et ont un ensemble de méthodes.

Les classes abstraites ne sont introduites que lorsqu'il devient clair que:

  • Il existe plusieurs classes similaires qui pourraient former une hiérarchie.
  • Ils partagent en fait quelque chose en commun, de sorte qu'une classe de base remplit un objectif utile.

Pour moi, "l'abstraction prématurée" suppose que tout le monde BaggingRobot doit hériter de certains BaseRobotet, pire encore, essayer de développer un ensemble de méthodes BaseRobotavant même de savoir ce qui est commun à tous les robots.

Simon B
la source
L'abstraction n'est pas synonyme de classes abstraites. Une interface est une abstraction. Je parle des abstractions en général, pas seulement des classes abstraites. J'aurais peut-être pu clarifier cela en utilisant une interface. Si vous développez votre système sur la même couche d'abstraction que votre client, il se peut que vous vous retrouviez avec des classes abstraites qui doivent être étendues car le langage est naturellement abstrait. Travailler plus bas est ce que j'appelle la «concrétion prématurée», où vous supposez naïvement que les idées des clients sur le fonctionnement du système sont les mêmes que les vôtres.
James
Un objet BaggingRobot qui place des objets Item dans des objets Bag est déjà l'abstraction d'un vrai robot d'ensachage qui met des choses dans des sacs.
user253751
1

Cela semble un peu comme si vous vouliez résoudre un problème qui n'existe pas encore et que vous n'avez aucune bonne raison de supposer que cela se produira, sauf si vous pensez simplement que le client a tort dans ce qu'il demande. Si tel est le cas, je recommanderais plus de communication que la mise en œuvre d'une solution de devinettes, abstraite ou autre. Bien qu'il puisse sembler inoffensif de simplement gifler "abstrait" sur la définition de la classe et de se sentir en sécurité en sachant que vous pouvez l'étendre plus tard, vous pourriez constater que vous n'avez jamais besoin de le faire, ou vous pouvez vous retrouver à l'étendre de manière à compliquer excessivement la conception. la ligne, en faisant abstraction des mauvaises choses.

Pour reprendre votre exemple, imaginez-vous que c'est le robot lui - même , les articles qui sont mis en sac ou la méthode de mise en sac qui changera la ligne?

L'abstraction prématurée signifie vraiment que vous n'avez aucune bonne raison d'effectuer l'abstraction et comme les abstractions sont loin d'être gratuites dans de nombreuses langues, vous pouvez encourir des frais généraux sans justification.

Modifier Pour répondre à certains points d'OP dans les commentaires, je mets à jour ceci pour clarifier et répondre d'une manière qui ne nécessite pas une longue chaîne de commentaires tout en abordant les points (1) et (2) plus spécifiquement.

(1) Pour moi, cela semble que le programmeur n'est pas assez pragmatique, ils ont fait des hypothèses que les choses existeraient dans le programme final qui ne fonctionne pas , donc ils travaillent avec un niveau d'abstraction bas, le problème n'est pas l'abstraction prématurée, c'est la concrétion prématurée.

(Je souligne). En supposant que des choses existeraient dans le programme final, ce n'est pas exactement ce que je vois dans votre exemple. Le client a demandé un robot d'ensachage. Il s'agit d'une demande très spécifique, quoique quelque peu vague dans sa langue. Le client veut un robot qui sache des articles, donc vous produisez une paire d'objets

public class Item {
/* Relevant item attributes as specified by customer */
}
public class BaggingRobot {
  private Collection<Item> items;

  public void bag(Item item);
}

Votre modèle est simple et précis, il suit les exigences fixées par le client sans ajouter de complexité à la solution et sans supposer que le client voulait plus que ce qu'il demandait. Si, lorsqu'ils sont présentés, ils clarifient la nécessité pour le robot d'avoir des mécanismes d'ensachage interchangeables, alors seulement vous avez suffisamment d'informations pour justifier la création d'une interface ou d'une autre méthode d'abstraction, car vous pouvez maintenant indiquer une valeur spécifique qui est ajoutée à le système à travers l'abstraction.

Au contraire, si vous commencez par l'abstraction du pur pragmatisme, vous passez du temps à créer une interface distincte et à l'implémenter dans une concrétion, ou à créer une classe abstraite, ou la manière d'abstraction que vous aimez. S'il s'avère que le client en est satisfait et qu'aucune autre extension n'est nécessaire, vous avez dépensé du temps et des ressources en vain et / ou introduit des frais généraux et de la complexité dans le système sans aucun gain.

En ce qui concerne (2), je conviens que l' omission de choses importantes n'est pas à première vue une marque d'abstraction prématurée. Abstraction ou non, vous pouvez omettre quelque chose d'important et à moins qu'il ne se trouve loin dans la chaîne d'abstraction, il ne sera pas plus difficile ou plus facile de trier cela de toute façon.

Au lieu de cela , j'interpréterais cela comme signifiant que toute abstraction court le risque d'obscurcir votre modèle de domaine. Une abstraction incorrecte peut rendre un système très difficile à raisonner, car vous créez des relations qui peuvent considérablement affecter la croissance future du modèle de domaine et la compréhension du domaine. Vous courez le risque d'omettre des informations non importantes sur la chose à extraire , mais sur le système dans son ensemble , en prenant votre modèle dans le mauvais trou de lapin.

JimJam
la source
"Il semble que vous souhaitiez résoudre un problème qui n'existe pas encore et que vous n'avez aucune raison de supposer que cela se produira, sauf si vous pensez simplement que le client a tort dans ce qu'il demande." - Ce n'est pas du tout ce que j'ai dit, en fait j'ai précisé que je construisais uniquement à partir des mots utilisés par le client. C'est le fait de ne pas vouloir faire ça ce qui m'a poussé à utiliser des abstractions.
James
"Je recommanderais plus de communication que l'implémentation d'une solution de devinettes" - Vous voulez dire comme je l'ai suggéré? Pour citer ce que j'ai dit dans OP "la solution à cela n'est pas de trouver vos propres ressources de concrétion et de gaspillage lorsque vous découvrez que vous vous êtes trompé, c'est d'obtenir plus d'informations du client."
James
"Bien qu'il puisse sembler inoffensif de simplement gifler 'abstrait' sur la définition de classe et de se sentir en sécurité en sachant que vous pouvez l'étendre plus tard" - Quand je dis "abstraction", je veux dire "abstraction", je ne veux pas dire "mot clé abstrait". Les interfaces peuvent être des abstractions, les abstractions sont de la logique floue, c'est de cela dont parle tout cet article. Le client communique en termes d'abstractions, nous devons donc programmer en termes abstraits jusqu'à ce que nous en sachions plus sur le domaine.
James
1
"vous pourriez trouver que vous n'avez jamais besoin de le faire" - Cela n'a aucun sens. Un client dit "Je veux un robot qui sache des objets", vous créez une abstraction qui répond à ces critères. Toute autre information que vous obtiendrez du client sera une information détaillée sur la façon dont il souhaite que l'ensachage soit effectué. Cela n'invalide pas votre abstraction, le client ne change pas soudainement d'avis sur une idée fondamentale derrière ce qu'il achète. Le robot va toujours mettre des articles en sac. L'abstraction que vous avez créée s'applique toujours.
James
"ou vous pourriez vous retrouver à l'étendre de manière à compliquer excessivement le design sur toute la ligne, en faisant abstraction des mauvaises choses." ... Avez-vous lu honnêtement ce que j'ai dit ou juste le titre? Sérieusement? Lire les points (1) et (2)
James