24 juillet 2007
Imprimer ce billet

Service Stateful vs. Service Stateless

Lors de la réalisation d’un service pour une architecture SOA, il arrive de devoir introduire, dans certaines situations, les notions de contexte ou de session. Nous allons voir quels sont les impacts de tels mécanismes et qu’il suffit d’appliquer la célèbre méthode KISS (Keep It Simple, Stupid) pour s’en sortir.

Définitions

Que signifient les termes « contexte » et « session »? :

  • le contexte d’un service est l’environnement fonctionnel (par exemple un cas d’utilisation) ou technique (par exemple une application web J2EE) dans lequel celui-ci est invoqué.
  • la session permet de conserver des informations au travers de plusieurs invocations d’un même service jusqu’à la libération de cette session.

Le contexte et la session nuisent à la compréhension et à la maintenabilité

Il arrive bien souvent de rencontrer des services qui effectuent des traitements différents suivant les cas d’utilisation, le canal (web, intranet, batch, etc.) ou autres contextes métiers. Ces conditions sont souvent basées sur ce que l’on appelle des nombres magiques (ou des chaînes de caractères) qui doivent être passés en paramètre par l’appelant. Ceci peut totalement nuire à la lecture du code et à sa maintenance.

En effet, un des critères des analyseurs de code qui détermine la qualité d’un code source est la complexité cyclomatique (nombre de chemins indépendants d’un programme). Ce critère augmente avec le nombre de conditions existant dans le code. Plus le traitement est linéaire, plus il est facile à lire, à débugger, et à maintenir (par quelqu’un qui n’a pas travaillé dessus).

Dans le même esprit, utiliser dans le traitement d’un service le résultat, les données ou l’état d’un traitement effectué précédemment et stocké dans la session contribue à obscurcir le code. Ceci implique parfois de lire deux services en même temps pour réussir à comprendre dans quel cas on passe par tel ou tel morceau de code. Si un service a besoin d’une donnée particulière pour effectuer son traitement, il doit simplement être passé en paramètre de manière explicite.

Que faire quand l’envie nous prend de changer le comportement du service en fonction du contexte ?

Surtout ne paniquez pas !
La solution la plus simple (qui est souvent la meilleure) consiste tout simplement à créer deux services puisqu’il y a deux besoins différents. Si les deux services ont une partie de leur traitement en commun, nous sommes capables avec la plupart des langages d’appliquer des préceptes objets pour éviter la duplication. L’important est que les interfaces externes de ces deux services soit distinctes et clairement documentées.

Le contexte et la session nuisent à la réutilisation

Il arrive aussi que le contexte de l’appelant soit implicitement utilisé pour réaliser un traitement spécifique : « Ce service est appelé (pour l’instant !) exclusivement par notre IHM de gestion des clients alors … ». Ce genre de raisonnement va empêcher la réutilisation de ce service en l’état. Il faudra repasser par une phase de développement pour lui faire adopter le bon comportement. Il est donc très important de développer des services qui répondent à un besoin métier et non pas au besoin d’une application. La phase de définition du service est ici primordiale.

La session nuit aussi à la réutilisation. Utiliser des données de la session implique qu’un appel à un autre service a été effectué auparavant. Prenons un exemple :

  • Imaginons qu’un service B utilise des données de la session. Il suppose donc qu’un appel vers le service A a déjà été effectué pour mettre les données en session. Ceci convient probablement aux services actuels.
  • Imaginons maintenant qu’un nouveau service C a besoin d’appeler, lui aussi, le service B, mais que le traitement ou les données renvoyés par le service A ne l’intéressent pas.

Dans cette situation, le service C doit malgré tout effectuer un appel au service A avant l’appel au service B. Le service B n’est donc pas pleinement réutilisable. De plus, forcer cet appel peut avoir un impact en terme de performances et de temps de développement. Ce genre de situation conduit bien souvent à la duplication du service B pour satisfaire les besoins du nouvel appelant.

Remarque: Le cas présenté ci dessus (Service A, B et C) est simple, imaginez cette combinaison pour plusieurs dizaines de services, vous obtiendrez un vrai spaghetti et un taux de réutilisation des services extrêmement faible.

Pour éviter ce genre de cas, il faut privilégier le passage d’informations par paramètre. Les services sont ainsi moins contraignants et plus faciles à réutiliser, ce qui est un des objectifs de la SOA. Il faut donc être très vigilant sur la qualité et la réutilisabilité des services exposés.

La session nuit aux performances

Bien évidemment, maintenir une session requiert des ressources machines. Tant que la session n’est pas terminée, celle-ci doit être sauvegardée, ce qui peut impliquer une occupation mémoire importante. Il arrive aussi que ces données soient sauvegardées non pas en mémoire mais sur un support physique (ce qui a aussi un coût en performance). Dans un environnement clusterisé avec réplication de session, les serveurs s’échangent en permanence des informations pour synchroniser les sessions. Dans toutes ces situations, la gestion et la sauvegarde de la session entraînent des traitements supplémentaires, coûteux en performance.

Où gérer le contexte ou la notion de session ?

Qui mieux que l’appelant sait dans quel contexte il se trouve ? L’appelé ne devrait jamais être influencé par le contexte ou les données de la session.

La notion de session ne devrait être implémentée que dans les zones qui sont déjà spécifiques à un besoin particulier. L’endroit classique où apparaîssent les notions de contexte et de session est l’IHM. Une autre possibilité existe dans une architecture SOA : un orchestrateur de processus (BPM) peut être amené à maintenir un contexte ou une session entre plusieurs appels de services quand il intègre dans ses traitements des activités humaines.

Introduire des services contextuels (ou stateful) dans une architecture SOA ne doit pas se faire à la légère et peut grièvement impacter la réutilisabilité, la maintenance et les performances des services.

En résumé, il faut donc :

  • définir des services simples qui répondent à un seul besoin,
  • utiliser le passage d’informations explicite par paramètres

Bien que la mise en place d’une SOA nous donne de l’agilité, il faut garder en tête qu’une bonne définition des services est importante. En définissant des services réutilisables, nous évitons de passer notre temps à faire, défaire et refaire les mêmes services. On peut ainsi se concentrer sur les services qui répondent aux nouveaux besoins métiers et apporte une réelle valeur ajoutée.

Mots-clefs :,