Quel est le motif de conception «Tout réparer»?


74

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?


4
Je soupçonne que le nom est aussi une référence à l'idée du point fixe d'une fonction, x = f (x). Peu importe le nombre de fois que vous appliquez f à x , le résultat est le même. Une fois que vous avez obtenu le résultat correct, le traitement ultérieur du résultat correct renvoie le même résultat correct.
9000 le

7
Notez que n'importe qui peut donner le nom de son choix, mais cela n'en fait pas un modèle logiciel bien connu. L'idempotence est un concept bien connu à part entière; on dirait que c'est utilisé ici de façon créative.
Robert Harvey

1
Cela me rappelle comment la boucle d'événement principal a été mise en œuvre sous Mac OS. Il s’agissait d’une fonction unique qui répondait à tous les événements et était généralement structurée de manière à tester l’état de tous les contrôles et à mettre à jour toute l’UI au besoin. Idempotent, en effet.
Lucas

3
This sounds quite nice on the face of it. Vraiment? Cela me semble horrible!
Michael

3
@ Michael Vous n'aimez pas les gestionnaires de paquets? Ils fonctionnent selon le même concept, mais à une plus petite échelle: marquez ce que vous voulez que le système ressemble, lancez "réparer tout", il installe / supprime / met à niveau comme il convient, mais n'a rien à faire en cas de modifications.
Izkata

Réponses:


100

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:

  1. 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.

  2. 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.


9
Il me semble que MVC est typique de "Tout réparer": lorsque vous modifiez le modèle, puis redessinez la vue à partir de zéro, la vue est entièrement redessinée, sans chercher à deviner quelles parties l'action pourrait potentiellement avoir affectées.
Matthieu M.

3
Cela ressemble essentiellement au principe de systèmes tels que Saltstack, Ansible et Nix. Étant donné la description d'une configuration, vous pouvez théoriquement amener plusieurs systèmes différents dans le même état final.
Kojiro

1
@MatthieuM. React , qui est très populaire sur le développement front-end, est comme ça, sauf qu'il diffère de manière virtuelle, de sorte qu'il ne fait que mettre à jour le vrai domaine avec les modifications réelles
Izkata

2
@ Izkata Même plus que React, cette réponse m'a fait penser à Redux.
Kevin

2
Il peut être utile de souligner que "tout réparer" et idempotent sont deux choses différentes: "tout réparer" est généralement idempotent (mais pas nécessairement), et les opérations idempotentes n'ont pas besoin de tout réparer ni même de performances. peine - donnez le même résultat une fois exécuté deux fois.
Hans-Peter Störr

15

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.


2
Je suis presque sûr qu'Excel a l'intention de ne recalculer que les cellules dépendantes des modifications. C'est pourquoi il existe un moyen de déclencher le recalcul de toutes les cellules: superuser.com/questions/448376/… (ce qui, je suppose, serait une solution miracle )
Aaron Hall

@AaronHall Si c'est le cas, c'est une très mauvaise implémentation. Je regarde régulièrement qu'il consomme 100% de 7 processeurs pendant 15-30 minutes pour calculer, par exemple, 60 000 cellules. Les calculs ne sont pas compliqués. J'ai souvent écrit des programmes Python pouvant tout faire dans la feuille en quelques secondes, y compris le démarrage de Python. C’était ma meilleure idée sur la façon dont cela pouvait prendre si longtemps. Cela pourrait être quelque chose d'autre je suppose. Il existe également un certain nombre de bugs très anciens dans Excel qui pourraient expliquer cette fonctionnalité.
JimmyJames

1
@AaronHall Il est également possible avec cet utilisateur que le calcul automatique soit désactivé sur la feuille. Je fais souvent cela sur de gros classeurs, car je ne dispose pas de 15 minutes à chaque fois que je tape.
JimmyJames

@AaronHall, j'ai pensé un peu plus et vous avez un point. Mes hypothèses étaient probablement trop larges. J'ai mis à jour la réponse qui m'était plus centrée sur quelque chose qui me
rendait

2
@ JimmyJames: Ce que je voulais dire, c'est que la meilleure approche peut varier considérablement en fonction des circonstances et que "réparer tout" peut être subdivisé en "réparer avec impatience tout changement individuel" et "tout réparer après que tous les changements soient terminés ".
Supercat

4

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.


1

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.


0

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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.