Un des aspects importants de REST (ou au moins de HTTP) est le concept que certaines opérations (verbes) sont idempotentes. Comme Gregor Roth l'a déclaré il y a quelques années:
La méthode PUT est idempotente. Une méthode idempotente signifie que le résultat d'une requête effectuée avec succès est indépendant du nombre de fois où elle a été exécutée.
L'idempotence est aussi une question débattue dans les Design Patterns SOA. Au fil des années, il a été dit beaucoup de choses sur REST et ses avantages perçus sur les autres approches, avec l'idempotence souvent considéré comme étant un concept compris par tous, mais qui n'a généralement pas été traité de manière exhaustive. Cependant, une récente publication sur la liste de diffusion Service Oriented Architecture a généré beaucoup de discussion autour d'un concept que beaucoup semblaient assumer assez simple. Le post initial commence par :
Actuellement, je m'intéresse à l'idempotence de nos services avec en vue un guide normatif pour l'entreprise dans le cas de la création de services idempotents. La question est de savoir si tous les services doivent être idempotents ? Est-ce réaliste ?
Il fait référence à une autre entrée de blog, où l'auteur affirme ce qui suit :
Bien sûr, la mise en œuvre de services idempotents peut être complexe pour le fournisseur de service. Et la complexité coûte de l'argent. C'est probablement la vraie raison pour laquelle les services idempotents sont si rares. [...] Mais une fois qu'un service est idempotent, il est infaillible et peut garantir la cohérence des données qui y transitent. Les services devraient être idempotent. Cela devrait être un principe de conception architecturale et de conception de services. Particulièrement vrai pour les services qui sont utilisés par de nombreux consommateurs. Vous ne pouvez pas vraiment dire à vos consommateurs de gérer eux-mêmes la complexité inhérente pour la gestion des données cohérentes, n'est-ce pas ? Les consommateurs sont vos clients, vous devez les traiter comme tels. Vous gagnez plus de clients si vous rendez les choses faciles pour eux.
Cette première publication a suscité beaucoup de réactions, y compris de la part de Steve Jones de Cap Gemini qui a ceci à dire :
Idempotent est l'une des grandes phrases poubelles de l'informatique, ce que cela signifie est «idempotent en mémoire». Si vous avez un service de consultation avec une capacité de mise à jour alors clairement dans la perspective de l'invocateur le service doit maintenir et gérer l'état. Ce qui veut dire que l'on peut passer à l'échelle, de manière horizontale, en mémoire. Si vous mettez à jour l'état, y compris au sein d'une base de données, alors vous ne pouvez pas être idempotent. Idempotent est l'endroit où vous appelez la même fonction avec la même valeur et le résultat est exactement le même, c'est la définition mathématique. Si jamais vous mettez à jour l'état, alors vous n'êtes pas idempotent.
Mark Baker, qui a posté beaucoup sur REST dans le passé, répond à Steve:
Il y a des mises à jour d'état non-idempotent, comme votre exemple de commentaire, et il y a des mises à jour idempotentes qui fixent une certaine référence à une valeur spécifique... évidemment, si vous faites cela plusieurs fois avec la même entrée, le résultat sera le même.
Steve est d'accord avec Mark sur un point : une opération est mathématiquement idempotente si le résultat est toujours identique avec la même valeur d'entrée. Toutefois, s'il y a une mise à jour de n'importe quel état causé par l'opération, par exemple, s’il enregistre la dernière date de la demande, alors il n'est pas idempotent.
J'ai été assez "impressionné"" par la façon dont les gens abusent du terme ces temps-ci dans l'informatique, j'ai vu à plusieurs occasions les gens prétendre que quelque chose était "idempotent" parce qu'il n'était pas stateful en mémoire.
Mark est d'accord avec la définition stricte de Steve, mais estime qu'elle ne s'applique pas dans le cadre de la question initiale : idempotence dans les systèmes distribués :
[...] Le mot ne peut réellement se référer qu'à l'interface, et non à l'implémentation. Donc, si je définis une opération, par exemple "set", et la définis pour être idempotent, alors c'est tout ce qui importe aux clients, même si un log est généré dans le cadre d'une implémentation de cette interface.
Un autre intervenant, Ashaf Galal, fait l'affirmation selon laquelle tous les «services de lecture» sont idempotents puisque le service retourne uniquement des données. Cependant, comme le souligne Steve, c'est une vision trop simpliste et tandis qu'une opération peut apparaître idempotente son implémentation peut être tout sauf idempotente (soulevant à nouveau la question de savoir si cette distinction est importante) :
[...] Les capacités de lecture ne doivent pas être idempotent. 'getNextIterator()' est une fonction de lecture qui n'est pas idempotente car elle incrémente l'itérateur. Une demande de solde sur un service bancaire n'est pas idempotente car la demande crée un log d'audit. Le résultat renvoyé est peut-être le même pour deux appels consécutifs (si aucun changement n'a eu lieu), mais l'entrée de log serait différente.
Ashaf répond à Steve en affirmant que idempotence est une propriété du service et non de son interface.
Le client a besoin d'obtenir une réponse correcte du service et il ne se soucie pas si le service est idempotent ou non, log ou pas log.
Alors, que pensent les autres ? Y-a-t-il encore un malentendu sur ce que signifie idempotence ? Est-ce que cela importe si une opération qui est censée être idempotente fait en réalité des changements à l'état du système, tel que la mise à jour des logs comme Steve le mentionne ?