web-dev-qa-db-fra.com

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

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, alors ils travaillent avec un niveau d'abstraction bas, le 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 pour communiquer à l'origine ce qu'ils veulent ont tendance à être toujours valables.

Voici un exemple, disons 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.

10
James

À 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. Ils ont beaucoup parlé de tout préparer pour faire face aux changements futurs qui pourraient se produire (même s'il n'y avait aucune raison particulièrement bonne 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 du 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é.

19
Jerry Coffin

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 nécessaire 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 recommencer à zéro de manière appropriée.

Bien sûr, le codage n'est pas 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 pensez honnêtement que vous pourriez un jour dans un proche avenir avoir besoin de 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 tente 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 le plaisir d'être une abstraction, mais parce qu'elles sont pratiques d'une manière réelle. 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. ;)

6
Neil

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. Ainsi, "robot d'ensachage" pourrait être une classe BaggingRobot. "Ouvrir un sac" pourrait devenir la 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, une "abstraction prématurée" suppose que tout BaggingRobotdoit hériter de certains BaseRobot et, pire, essayer de développer un ensemble de méthodes pour BaseRobot avant même de savoir ce qui est commun à tous les robots.

3
Simon B

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 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 la conception de manière excessive la ligne, en faisant abstraction des mauvaises choses.

En suivant votre exemple, imaginez-vous qu'il s'agit du robot lui-même , les articles étant mis en sac ou la méthode d'ensachage 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.

Edit 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 adressant les points (1) et (2) plus Plus précisément.

(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 de l'abstraction, 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, seulement , alors avez-vous suffisamment d'informations pour justifier la création d'une interface ou une autre méthode d'abstraction, puisque vous pouvez maintenant pointer vers une valeur spécifique qui est ajoutée au système via 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 omettre des 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 soit trouvé loin dans la chaîne d'abstraction, il ne sera pas plus difficile ni 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 abstraite , mais sur le système dans son ensemble , en prenant votre modèle dans le mauvais trou de lapin.

1
JimJam