Voici un exemple d’application web que l’on va utiliser selon toutes les possibilités d’un navigateur classique pour expliquer en quelques instants l’intérêt des continuations concernant le clonage de pages, l’utilisation de l’URL ou la navigation par les boutons « précédent » et « suivant ».
Il s’agit d’une application web très simple où le client soumet un premier nombre et le valide, puis un second et enfin obtient leur somme. Le schéma suivant illustre l’utilisation normale de l’application. On imagine aisément comment pourrait être construite cette mini application sous forme de servlets agissant pour chaque bouton « submit ».
Lors de la création d’une application web, aussi simple soit-elle, on constatera bien vite que nombreux sont les cas qu’il faut prévoir et catalyser concernant toutes les actions et rétroactions de l’utilisateur. Prenons quelques exemples de problèmes qu’il faudrait avoir à gérer à l’avance concernant l’application décrite ci-dessus :
Il faut dans ce cas gérer les erreurs possibles dues au fait que la première valeur n’a pas été enregistrée. Plusieurs solutions sont possibles, qu’il s’agisse de renvoi automatique à la page de démarrage de l’application, d’affichage de l’erreur ou d’empêcher à la page « SumServlet II » d’être appelée par requête URL directe, le choix de la manière est dédié au programmeur.
Il est évident que la valeur enregistrée ne le sera pas dans une variable distincte de la première. Donc la première variable sera écrasée par la nouvelle valeur soumise.
Cette situation est un peu plus complexe à gérer car on peut distinguer plusieurs possibilités :
Prenons l’exemple illustré par le schéma ci-dessous :
A : la première page est clonée. Nous nommerons par la suite les deux applications « initiale » et « clonée ».
B : l’utilisateur valide une première valeur (ici 123) sur l’application initiale…
C et D : puis il revient sur l’application clonée et valide pour celle-ci une première valeur, différente de celle de l’application initiale (ici 100).
E et F : s’il décide de revenir à présent sur l’application initiale, et d’y valider une seconde valeur (ici 201), on peut remarquer que la première valeur (à l’origine 123) a été écrasée par le fait d’enregistrer la première valeur de l’application clonée (100). Le résultat fourni par l’additionneur est alors erroné car il ne correspond plus à la somme des valeurs auxquels s’attend l’utilisateur (123 + 201).
Le grand problème d’une application web est que rien ne permet de faire le lien entre elle et le navigateur utilisé pour la lancer. En effet, les navigateurs offrent certains services, sous forme d’actions généralisées, sur les pages visitées (comme celles déjà citées tels le retour arrière/avant, la navigation directe par l’URL ou le clonage de page). Pour gérer les différents désagréments que ces actions de l’utilisateur pourraient engendrer au niveau de l’application, les continuations se posent comme une solution simple et efficace de gestion d’états, d’évènements et aussi d’erreurs.
Si l’on reprend les différents exemples de problèmes décrits précédemment pour la petite application d’additionneur, les continuations offriraient les avantages suivants :
Une grande particularité de l’utilisation des continuations est de permettre l’affichage de plusieurs pages différentes à partir d’une seule et même portion de code (voir explication plus loin). Il n’existera donc, s’il est nécessaire, qu’une seule et unique URL permettant d’appeler l’application, ce qui évite tout problème d’action inappropriée concernant l’arborescence de l’application.
Les continuations, comme sa définition l’indique, permet de garder la trace de toutes les actions effectuées et d’y revenir à tout moment. En fait, il s’agit tout simplement de revenir sur les actions faites lors du déroulement du thread (donc sur les instanciations de variables, paramètres etc.). Il existe des exemples sur le net expliquant que les continuations peuvent être gérées comme une sorte d’arborescence d’états, ce qui présenterait des avantages bien plus fonctionnels pour revenir sur ses pasque les simples retours précédent/suivant d’un navigateur. Néanmoins, il est assez difficile de trouver des exemples clairs et précis du fonctionnement et surtout des relations entre continuations sur le net. Peut-on par exemple appeler un état antérieur de façon direct ? Il semblerait que la réponse à cette question ne dépende non pas des continuations dans leur définition, mais plutôt des langages ou frameworks utilisés pour les développer, car si l’idée de départ reste la même, le moyen d’utiliser le système de continuation est parfois bien différent.
Il existe, comme expliqué ci-dessous, plusieurs solutions pour un même problème, qu’elles dépendent de l’environnement (langage ou framework utilisé, quelles possibilités offertes et à quel coût au niveau programmation) ou même du problème en lui-même. Partons ici de l’exemple de l’additionneur, qui comme nous l’avons vu précédemment, ne supportait pas une utilisation en décalé de deux clones de l’application. Deux solutions principales s’offrent à nous, qui utiliseraient très facilement les avantages des continuations :
Il existe bien d’autres solutions, cela dépend bien sûr du problème à éviter et de l’application en elle-même. Par exemple, il est aussi possible de faire en sorte que chaque valeur entrée, quelle que soit la page (SumServlet I ou SumServlet II), clonée ou non, soit comprise par l’application comme la valeur attendue à l’état présent (si une « première valeur » existe déjà, une seconde « première valeur » soumise sera comprise par la servlet comme l’équivalent de la « deuxième valeur » attendue. C’est pourquoi on parle dans la notion même des continuations de « program-level manageable value representing the rest of the computation of the program ».
Tout cela met bien en évidence que les continuations sont en fait un palliatif au manque, au niveau programmation, qui existe concernant la gestion d’états et la résolution d’action de navigation. Ces exemples avaient pour but principal de mettre en évidence que chaque application web nécessite des besoins particuliers en ce qui concerne la navigation, la gestion d’états et d’évènements, et ne peut se contenter de laisser tout navigateur le gérer de façon impersonnelle.