Dans cet article de Stephen Figgins publié en 2003 sur linuxdevcenter.com , BitTorrent de Bram Cohen est décrit comme utilisant le modèle de conception "Tout réparer".
Une approche moins commune qui rend BitTorrent plus difficile à comprendre, mais mérite d'être étudiée, est l'utilisation de l'idempotence par Cohen. Un processus est idempotent lorsque son application plus d'une fois n'entraîne aucune modification supplémentaire. Cohen dit qu'il utilise un modèle de conception qu'il appelle "Tout réparer", une fonction qui peut réagir à un certain nombre de changements sans vraiment noter ce que tout cela pourrait changer. Il explique, "vous notez l'événement qui s'est passé, puis appelez la fonction tout corriger qui est écrite de cette manière très idempotente, et nettoie tout ce qui pourrait se passer et recalcule le tout à partir de zéro." Tandis que l'idempotence facilite certains calculs difficiles, il rend les choses un peu compliquées. Ce n'est pas toujours clair quel appel va changer, le cas échéant. Vous n'avez pas besoin de savoir à l'avance. Vous êtes libre d'appeler la fonction,
Cela semble assez beau à première vue.
Cependant, il me semble qu'appeler une fonction idempotente "tout réparer" améliorerait la robustesse du système au détriment de l'efficacité et risquerait de gâcher le système conteneur (qui pourrait préférer des processus soigneusement planifiés et exécutés).
Je ne peux pas dire que je l'ai déjà utilisé auparavant. Je ne parviens pas non plus à trouver la source de son application en ligne (mais j’ai trouvé celle qui prétend être basée sur celle-ci.). Je ne peux pas non plus y trouver de référence en dehors de cet article (et je considère que mon google-fu est plutôt bon), mais j'ai trouvé une entrée pour "Idempotent Capability" sur SOApatterns.org .
Cette idée est-elle mieux connue sous un autre nom?
Quel est le motif de conception "Tout réparer"? Quels sont ses avantages et ses inconvénients?
la source
This sounds quite nice on the face of it.
Vraiment? Cela me semble horrible!Réponses:
Supposons que votre page HTML soit assez compliquée: si vous sélectionnez un élément dans une liste déroulante, un autre contrôle peut apparaître ou les valeurs d'un troisième contrôle peuvent être modifiées. Vous pouvez aborder ceci de deux manières:
Ecrivez un gestionnaire distinct pour chaque contrôle qui répond aux événements de ce contrôle et met à jour les autres contrôles en fonction des besoins.
Ecrivez un seul gestionnaire qui examine l'état de tous les contrôles de la page et corrige simplement tout .
Le second appel est "idempotent" car vous pouvez l’appeler encore et encore et les commandes seront toujours bien organisées. Considérant que le premier appel peut avoir des problèmes si un appel est perdu ou répété, par exemple si l'un des gestionnaires effectue une bascule.
La logique pour le deuxième appel serait un peu plus obscure, mais il suffit d'écrire un seul gestionnaire.
Et vous pouvez toujours utiliser les deux solutions, appelant la fonction "Tout corriger" au besoin "juste pour être du bon côté".
La deuxième approche est particulièrement intéressante lorsque l’état peut provenir de différentes sources, par exemple de la part de l’utilisateur ou du serveur. Dans ASP.NET, la technique s’intègre très bien avec le concept de publication car vous exécutez simplement la fonction Tout corriger à chaque rendu de la page.
Maintenant que j'ai mentionné les événements perdus ou répétés, et l'état de différentes sources, je pense qu'il est évident que cette approche correspond bien à un espace problématique comme celui de BitTorrent.
Les inconvénients? L'inconvénient évident est qu'il y a un impact négatif sur les performances car il est moins efficace de tout réviser tout le temps. Mais une solution telle que BitTorrent est optimisée pour évoluer et non pour évoluer, c'est donc bon pour ce genre de chose. Selon le problème que vous essayez de résoudre, il se peut que cela ne vous convienne pas.
la source
Je pense que l'article est un peu démodé parce que, comme je l'ai lu, ce n'est pas vraiment une idée peu orthodoxe ou nouvelle. Cette idée est présentée comme un motif distinct lorsqu'il ne s'agit que d'une simple implémentation d'Observer. En repensant à ce que je faisais à l'époque, je me souviens d'avoir travaillé sur la logique pour rester assis derrière une interface assez complexe avec un certain nombre de panneaux différents avec des données interdépendantes. L'utilisateur peut modifier les valeurs et / ou exécuter une routine d'optimisation et, en fonction de ces actions, des événements sont générés que l'interface utilisateur écoute et met à jour si nécessaire. Il y avait un certain nombre de problèmes au cours du développement où certains panneaux ne mettraient pas à jour quand ils le devraient. La solution (rester dans la conception) était de générer des événements à partir d'autres événements. En fin de compte, au moment où tout fonctionnait correctement, presque chaque changement a eu pour conséquence de rafraîchir tous les panneaux. Toute la difficulté d'essayer d'isoler lorsqu'un groupe donné avait besoin d'actualiser n'avait servi à rien. Et ça n'avait pas d'importance quand même. C'était effectivement une optimisation prématurée. J'aurais économisé une tonne de temps et d'efforts en réduisant simplement le tout en un seul événement qui a tout rafraîchi.
Il existe d'innombrables systèmes conçus dans le «tout réparer» ou tout rafraîchir. Pensez à toutes les interfaces CRUD qui ajoutent / mettent à jour une ligne, puis actualisent à nouveau la base de données. Ce n'est pas une approche exotique, c'est juste la solution évidente non intelligente. Vous devez comprendre qu'en 2003, c'était le comble de la «fièvre de modèle». D'après ce que je pouvais dire, les gens pensaient que nommer de nouveaux modèles serait un chemin vers la gloire et la richesse. Ne vous méprenez pas, je pense que le concept de motif est extrêmement utile pour décrire des solutions abstraites. Les choses ont tout simplement déraillé. C'est malheureux parce que cela a créé beaucoup de cynisme à propos du concept de motif en général. Ce n'est que dans ce contexte qu'il est logique de parler de solution "peu orthodoxe". Il' s semblable à l'orthodoxie autour des ORM ou des conteneurs DI. Ne pas les utiliser est considéré comme peu orthodoxe, alors que les gens construisaient des logiciels bien avant que ces outils n'existent et, dans de nombreux cas, ces outils sont excessifs.
Revenons donc à 'tout réparer'. Un exemple simple est le moyen de calcul. La solution simple consiste à totaliser et diviser par la cardinalité des valeurs. Si vous ajoutez ou modifiez un numéro, il vous suffit de le refaire depuis le début. Vous pouvez garder la trace de la somme et du nombre de chiffres et quand quelqu'un ajoute un nombre, vous augmentez le nombre et l'ajoutez à la somme. Maintenant, vous ne ré-ajoutez pas tous les chiffres. Si vous avez déjà travaillé avec Excel avec une formule faisant référence à une plage et modifié une valeur unique dans cette plage, vous avez un exemple du modèle 'Tout corriger', c'est-à-dire que toute formule faisant référence à cette plage sera recalculée indépendamment du fait que cette valeur était pertinente (par exemple, en utilisant quelque chose comme sumif ()).
Cela ne veut pas dire que ce n’est pas un choix judicieux dans un contexte donné. Dans l'exemple moyen, disons que nous devons maintenant prendre en charge les mises à jour. Maintenant, j'ai besoin de connaître l'ancienne valeur et de ne changer que la somme par le delta. Rien de tout cela n'est vraiment difficile tant que vous n'envisagez pas d'essayer de le faire dans un environnement distribué ou concurrent. Vous devez maintenant gérer toutes sortes de problèmes épineux de synchronisation et vous allez probablement créer un goulot d'étranglement majeur qui ralentit les choses beaucoup plus que de recalculer.
Le résultat est que l’approche «tout réparer» ou «tout rafraîchir» est beaucoup plus facile à obtenir. Vous pouvez faire fonctionner une approche plus sophistiquée, mais elle est beaucoup plus compliquée et donc plus susceptible d’être viciée. En outre, dans de nombreux contextes, l’approche consistant à «actualiser tout» peut être plus efficace. Par exemple, les approches de copie à l'écriture sont généralement plus lentes pour les approches à un seul thread, mais lorsque vous avez une simultanéité élevée, cela peut vous permettre d'éviter les verrous et donc d'améliorer les performances. Dans d'autres cas, cela peut vous permettre de regrouper les modifications par lot de manière efficace. Donc, pour la plupart des problèmes, vous voudrez probablement commencer par une approche de tout actualiser, sauf si vous avez une raison spécifique pour laquelle vous ne pouvez pas le faire, puis vous inquiétez de faire quelque chose de plus complexe une fois que vous en avez besoin.
la source
Pas sûr que ce soit un "modèle de conception", mais je classerais ce type de comportement comme configuration d'état final ou configuration d'état souhaité , dans la veine de DSC Puppet, Chef ou Powershell.
Ces solutions fonctionnent généralement au niveau de la gestion des systèmes, et non pas au niveau de la logique métier comme le décrit la question, mais il s’agit du même paradigme. Bien que ces outils soient généralement de nature déclarative, les mêmes principes peuvent être appliqués dans le code de procédure ou les scripts.
la source
Je l'ai principalement utilisé dans les interfaces utilisateur. La bonne chose est que vous écrivez une fois, et il gère tout aussi bien du cas le plus simple au plus difficile (par exemple si l'utilisateur fait pivoter l'écran, ou sur un ordinateur portable / de bureau si l'utilisateur redimensionne une fenêtre, et pratiquement tout change ).
Il n'y a pas beaucoup de raisons de s'inquiéter de l'efficacité. Dans l'interface utilisateur, les éléments les plus coûteux sont des éléments tels que le redessinage d'un élément déplacé. Le calcul de l'emplacement de chaque élément et de sa taille est généralement assez rapide. Tout ce que vous avez à faire est que chaque fois que vous trouvez qu'un élément doit rester exactement à l'endroit où il appartient, aucun code n'est exécuté pour le déplacer. Les vrais changements sont tout ce que vous avez dû faire de toute façon.
la source
Cela ressemble à des principes de programmation réactifs. "Tout réparer" examine l'état "principal" actuel et propage tout le reste qui devrait être affecté - les "états calculés". Si vous optimisez cette dérivation, elle peut atteindre une efficacité élevée, a-la React, mais si vous le faites naïvement, les performances risquent de ne pas être optimales, même si elles pourraient quand même être assez rapides.
la source