La démarche agile au service des applications web : deuxième partie

Auteur : Pascal Roques ( pascal.roques@valtech-training.fr )

Introduction

Dans ce deuxième article, nous allons mettre en œuvre sur un petit exemple le processus simplifié que nous préconisons pour la modélisation des applications web, jusqu’à la conception détaillée sur la plateforme .NET.

Pour mémoire, ce processus (décrit dans l’article précédent) se situe à mi-chemin entre UP (Unified Process), un cadre général très complet de processus de développement, et XP (eXtreme Programming), en appliquant les principes de la modélisation agile (AM = Agile Modeling).

Nota : la description détaillée de ce processus ainsi que de sa mise en œuvre complète sur le cas de la librairie en ligne est parue récemment chez Eyrolles, dans la collection intitulée « Les cahiers du Programmeur », sous le titre : « UML 2 - Modéliser une application web ».

Le schéma général de la démarche est rappelé sur la figure ci-après, reprenant l’organisation en chapitres du livre précité.

Présentation simplifiée du cas concret servant d’illustration

Le cas concret servant d’illustration à notre démarche agile consiste en la modélisation d’un site web marchand, en l’occurrence une librairie. La librairie en ligne constitue en effet un exemple facile à comprendre et suffisamment représentatif des projets d’applications web. Nous nous sommes inspirés des fonctionnalités de sites existants, comme www.amazon.fr, www.fnac.com, et bien sûr celui de notre librairie préférée : www.eyrolles.com !

L’objectif fondamental de tels sites est de permettre aux internautes de rechercher des ouvrages par thème, auteur, mot-clef, etc., de se constituer un panier virtuel, puis de pouvoir les commander et les payer directement sur le Web. Dans le cadre de cet article, nous nous restreindrons à la fonctionnalité de gestion du panier virtuel.

Dans un véritable magasin, le client choisit ses articles les uns à la suite des autres, les dépose dans son panier, puis se rend à la caisse pour régler le tout. Les sites marchands tentent de reproduire ces habitudes d'achat le plus fidèlement possible. Ainsi, lorsque l'internaute est intéressé par un ouvrage, il peut l'enregistrer dans un panier virtuel, comme indiqué sur l’exemple de la figure suivante. Il doit pouvoir ensuite à tout moment en ajouter, en supprimer ou encore en modifier les quantités avant de passer commande.

Acteurs et cas d’utilisation

L’acteur le plus important pour un site d’e-commerce est bien sûr l’internaute.

Ses cas d’utilisation principaux ont été mis en évidence par l’expression de besoins préliminaire du paragraphe précédent, à savoir :

  • Rechercher des ouvrages,
  • Gérer son panier
  • Effectuer une commande

Nous nous intéresserons plus particulièrement dans la suite de cet article au cas d’utilisation "Gérer son panier", comme illustré sur le diagramme de cas d’utilisation simplifié ci-après.

Nota : la plupart des diagrammes ont été réalisés soit à la main (c’est aussi cela la modélisation agile !), soit avec l’outil Enterprise Architect (www.sparxsystems.com).

Nous donnons ci-dessous la description textuelle détaillée du cas d’utilisation qui nous concerne (le style utilisé est celui préconisé par A. Cockburn dans son récent ouvrage de référence : « Rédiger des cas d’utilisation efficaces », Eyrolles, 2001).


Scénario nominal :

  1. L’Internaute enregistre les ouvrages qui l’intéressent dans un panier virtuel (voir le cas d’utilisation Rechercher des ouvrages).
  2. Le Système lui affiche l’état de son panier. Chaque ouvrage qui a été préalablement sélectionné est présenté sur une ligne, avec son titre, son auteur et son numéro ISBN. Son prix unitaire est affiché, la quantité est positionnée à « 1 » par défaut, et le prix total de la ligne est calculé. Le total général est calculé par le Système et affiché en bas du panier avec le nombre d’articles.
  3. L’Internaute continue ses achats (voir le cas d’utilisation Rechercher des ouvrages).
Extensions :
  • 2.a : Le panier est vide
    1. Le système affiche un message d’erreur à l’Internaute (« Votre panier est vide ») et lui propose de revenir à une recherche d’ouvrage (voir le cas d’utilisation Chercher des ouvrages).
  • 4.a : L’Internaute modifie les quantités des lignes du panier, ou en supprime.
    1. L’Internaute revalide le panier en demandant la mise à jour du panier
    2. Le cas d’utilisation reprend à l’étape 2 du scénario nominal.
  • 4.b : L’Internaute demande un devis pour commander par courrier.
    1. Le Système fournit un devis imprimable à joindre au règlement récapitulant la commande et le total à payer.
  • 4.c : L’Internaute souhaite commander en ligne.
    • 1. Le Système l’amène sur la page d’identification
    • 2a. L’Internaute s’identifie en tant que client (voir le cas d’utilisation S’authentifier)
    • 2b. L’Internaute visiteur demande à créer un compte client (voir le cas d’utilisation Créer un compte client)


Le diagramme de séquence système d’un scénario représentatif est donné sur la figure suivante, utilisant les fragments d’interaction et les opérateurs UML 2 :

Identification des concepts du domaine

Comment identifier les concepts du domaine ? Plutôt que de partir à l’aveugle et nous heurter à la taille du problème à résoudre, nous allons prendre les cas d’utilisation un par un et nous poser pour chacun la question suivante : quels sont les concepts métier qui participent à ce cas d’utilisation ?

Par exemple, pour le cas qui nous intéresse (« Gérer son panier »), nous identifions facilement les concepts métier « Panier » et « Livre ». Nous allons modéliser ces concepts sous forme de diagrammes de classes contenant uniquement des attributs et des associations.

Le concept de panier est un concept du domaine, car dans les librairies réelles le client remplit également un panier avant de passer à la caisse. Le panier est simplement un conteneur des livres sélectionnés par le client. Cependant, nous devons prendre en compte le fait que le client peut choisir plusieurs exemplaires du même livre et que nous voulons le total du panier. Dans notre cas, le prix du panier est calculable simplement à partir du prix des livres sélectionnés, ce qui donne un attribut dérivé « /total » dans la classe Panier. Pour exprimer le fait que le panier peut contenir plusieurs exemplaires du même livre, nous allons ajouter un concept intermédiaire qui correspond à une ligne du panier et qui concerne donc un seul livre, mais avec un attribut quantité, initialisé à « 1 » par défaut.

Le diagramme de classes du domaine résultant de cette première réflexion est donné ci-après.

Réalisation des cas d’utilisation : analyse

Dans ce paragraphe, nous allons identifier les classes d’analyse qui vont participer à la réalisation des cas d’utilisation.

Nous distinguerons trois types de classes d’analyse (comme proposé par I. Jacobson) :

  • les « dialogues » qui représentent les moyens d’interaction avec le système,
  • les « contrôles » qui contiennent la logique applicative
  • et les « entités » qui sont les objets métier manipulés.

Pour compléter ce travail d’identification, nous allons ajouter des attributs et des opérations dans les classes d’analyse, ainsi que des associations entre elles.

  • Les « entités » vont seulement posséder des attributs. Ces attributs représentent en général des informations persistantes de l’application.
  • Les « contrôles » vont seulement posséder des opérations. Ces opérations montrent la logique de l’application, les règles métier, les comportements du système informatique.
  • Les « dialogues » vont posséder des attributs et des opérations. Les attributs vont représenter des champs de saisie ou des résultats. Les résultats seront distingués en utilisant la notation de l’attribut dérivé. Les opérations représenteront des actions de l’utilisateur sur l’IHM.

Le diagramme de classes participantes du cas d’utilisation « Gérer son panier » est donné ci-après (l’acteur est relié au dialogue qui est relié au contrôle, lui-même relié aux entités).

Navigation IHM

Les IHM modernes, en particulier celles destinées aux internautes via les applications web, cherchent à faciliter la communication avec l’utilisateur. Elles sont de plus en plus riches et puissantes. Mais cela oblige le concepteur du site à réfléchir de façon très précise au comportement attendu de tous ses éléments graphiques et pas seulement d’un point de vue visuel.

UML nous offre la possibilité de représenter formellement la navigation dans le site, au moyen d’un diagramme dynamique appelé diagramme d’états (ou éventuellement d’un diagramme d’activité). Le diagramme de navigation représente ainsi un ajout important dans l’arsenal des outils de modélisation du concepteur de site Web, puisqu’il fournit la possibilité de décrire précisément et exhaustivement les aspects dynamiques de l’interface utilisateur.

Un exemple de diagramme d’états de navigation concernant la gestion du panier est donné ci-dessous.

Remarquez comment nous avons ainsi représenté la règle métier importante consistant à interdire l’accès à la commande dans le cas où le panier est vide.

Réalisation des cas d’utilisation : conception préliminaire

Dans ce paragraphe, nous allons maintenant attribuer des responsabilités précises de comportement aux classes d’analyse identifiées précédemment. Nous représenterons le résultat de cette étude dans des diagrammes de séquence de conception préliminaire. Nous construirons également une vue statique complétée sous forme de diagrammes de classes de conception préliminaire, indépendamment des choix technologiques qui seront effectués au dernier paragraphe.

Diagrammes de séquence de conception préliminaire

L’attribution des bonnes responsabilités aux bonnes classes est l’un des problèmes les plus délicats de la conception orientée-objet. Pour chaque service ou fonction, il faut décider quelle est la classe qui va le contenir. Les diagrammes de séquence sont particulièrement utiles au concepteur pour représenter graphiquement ses décisions d’allocations de responsabilités. Chaque diagramme va ainsi représenter un ensemble d’objets de classes différentes collaborant dans le cadre d’un scénario d’exécution du système. Dans ce genre de diagramme, les objets communiquent en s’envoyant des messages qui invoquent des opérations (ou méthodes) sur les objets récepteurs. Il est ainsi possible de suivre visuellement les interactions dynamiques entre objets, et les traitements réalisés par chacun.

Par rapport aux diagrammes de séquence système, nous allons remplacer le système vu comme une boîte noire par un ensemble d’objets communicants. Pour cela, nous utiliserons dans ce paragraphe les trois types de classes d’analyse, à savoir les « dialogues », les « contrôles » et les « entités ». Le changement de niveau d’abstraction par rapport au diagramme de séquence système peut ainsi se représenter comme sur la figure ci-dessous.

Intéressons-nous au moment où l’internaute met de côté un premier livre dans son panier virtuel. Que se passe-t-il derrière le dialogue concerné ? Celui-ci passe la main à un contrôle spécialisé dans la gestion du panier. Ce contrôle a la responsabilité de créer le panier lors de la première sélection mais aussi toutes les lignes du panier au fur et à mesure. Il est également responsable d’afficher un dialogue particulier récapitulant le panier en cours et permettant à l’internaute de le modifier et de le recalculer.

Tout cela est représenté sur la figure suivante (diagramme de séquence).

Continuons maintenant en considérant un scénario dans lequel l’internaute modifie la quantité d’un ouvrage sélectionné, puis demande un recalcul de son panier.

Le contrôle reçoit une collection de quantités et la passe à l’entité panier. Celui-ci est responsable de la gestion de ses lignes. Il va donc demander à chaque ligne de se recalculer individuellement en lui passant en paramètre la quantité qui la concerne. Si cette quantité a été positionnée à zéro par l’internaute, la ligne est supprimée.

Pour terminer la gestion du panier, considérons enfin un scénario dans lequel l’internaute supprime explicitement une ligne du panier puis le vide totalement.

Diagramme de classes de conception préliminaire

En partant du modèle d’analyse, nous allons affiner et compléter le diagramme de classes participantes. Pour cela nous utiliserons les diagrammes de séquence que nous venons de réaliser pour :

  • Ajouter ou préciser les opérations dans les classes (un message ne peut être reçu par un objet que si sa classe a déclaré l’opération publique correspondante).
  • Ajouter des types aux attributs et aux paramètres et retours des opérations.
  • Affiner les relations entre classes : associations (avec indication de navigabilité), généralisations ou dépendances.

Que pouvons nous ajouter au diagramme de classes participantes d’analyse de notre cas d’utilisation ?

  • Tout d’abord, nous avons détecté deux dialogues supplémentaires : l’un correspondant à l’erreur « Panier vide », l’autre permettant d’afficher le devis pour impression par l’internaute.
  • Ensuite les diagrammes de séquence nous amènent à ajouter un certain nombre d’opérations aux classes existantes, par exemple ajouterLigne(id) à CtrPanier et à l’entité Panier. Nous avons vu que le dialogue ResultatRecherche peut appeler CtrPanier comme d’ailleurs tous les dialogues qui possèdent le bouton « Mettre dans le panier » associé à au moins une référence d’ouvrage. Le contrôle passe toujours par le panier et n’accède pas directement aux lignes.

Le diagramme de classes de conception préliminaire résultant est fourni par la figure ci-après.

Réalisation des cas d’utilisation : conception détaillée sur la plateforme .NET

Nous allons maintenant incorporer dans nos diagrammes le choix d’architecture et les choix technologiques qui vont modifier les classes de conception préliminaire, les préciser, ajouter de nouvelles classes plus techniques, etc.

N’oublions pas que l’objectif principal du modèle de conception détaillée est de pouvoir être traduit directement en code !

Implémentation des 3 types de classes d’analyse

Pour résumer, en .NET :

  • Le "dialogue" est réalisé par les pages ASP.NET : l'idée est également d'insérer des instructions de script dans des pages HTML (le langage peut être C# ou VB.NET). Les pages ASP.NET peuvent contenir des WebForms, espèces de TagLibs qui génèrent des vues en HTML et qui aident également à placer des contraintes (component validators) sur les champs de saisie utilisateur. Ces contraintes sont vérifiées côté serveur par défaut, mais un module JavaScript permet de pré-valider le tout côté client à condition d'utiliser InternetExplorer.
  • le « contrôle » est implémenté soit par des classes associées aux ASP.NET (classes CodeBehind), soit par des classes supplémentaires déployées dans l’application web (dans le "moteur d'ASP" : IIS).
  • les « entités » sont représentées par des classes de l’application web, ou par des Serviced Components (que l'on installe dans le serveur d'applications MTS).

ASP

Comme indiqué précédemment, le dialogue GestionPanier va être implémenté par une page ASP.NET. Celle-ci va contenir du code HTML, des WebForms (pour les lignes du panier), ainsi qu’une référence à une classe C# que l’on qualifie de « CodeBehind ». Cette classe renferme un ensemble de méthodes que la page ASP.NET va invoquer pour simplifier sa tâche (un traitement un peu complexe gagne à être implémenté dans le CodeBehind et appelé par une instruction de script dans la page ASP.NET).

Cette structure de la page ASP.NET est représentée sur le diagramme de classes partiel qui suit.

Voici un exemple de page script qui gère le panier (il faudrait bien sûr peaufiner le graphisme) :

  • affichage de la liste des lignes ;
  • pour chaque ligne, possibilité de modifier la quantité ou de supprimer la ligne ;
  • possibilité à la fin de vider le panier, ou de demander un devis / passer une commande.

Diagrammes de séquence de conception détaillée .NET

Si nous reprenons les mêmes hypothèses de scénario que précédemment, nous obtenons les diagrammes de séquence suivants :

Diagramme de classes de conception détaillée

En extrapolant le travail précédent sur les diagrammes de séquence, le diagramme de classes de conception détaillée autour de la gestion du panier est le suivant.

Exemples de code

Le code C# de la classe « Panier » est donné sur le listing suivant :

namespace LogiqueMetier.Gestion{
	using LogiqueMetier.Catalogue.Livre;
	using System.Collections;
	public class Panier {
		private double tot ;
		public double total {
			get { return tot; }
		}
	 
		private IList lesLignesPanier = new ArrayList();
		
		public Panier() { }
	 
		public void recalculer(IList quantites) {
			total = 0;
			int i = 0;
			foreach (LignePanier ligne in lesLignesPanier){
				ligne.recalculer(quantites[i]);
				total += ligne.prixTotal;
			}
		}
	 
		public void ajouterLigne(Livre l) {
			// Ne pas ajouter de ligne s'il en existe déjà une pour ce livre
			foreach (LignePanier ligne in lesLignesPanier){
				if (ligne.livreConcerne.Equals(l)){ return; }
			}
			lesLignesPanier.Add(new LignePanier(l));
		}
	 
		public void supprimerLigne(Livre l) {
			foreach (LignePanier ligne in lesLignesPanier) {
				if (ligne.livreConcerne.Equals(l)){
					lesLignesPanier.Remove(ligne);
					break;
				}
			}   
		}
	 
		public void viderPanier() {
			lesLignesPanier.Clear();
		}
	}
}
			

Le code de la page ASP.NET qui gère le panier comme sur la figure donnée plus haut est détaillé par le listing ci-après :

<%@ Page language="c#" Codebehind="GestionPanier.aspx.cs"
  AutoEventWireup="false" Inherits="Addition.GestionPanier" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
    <HEAD>
        <title>GestionPanier</title>
    </HEAD>
    <body>
        <form id="GestionPanier" method="post" runat="server">
            <H1>Gestion du panier virtuel</H1>
            <H3>Votre panier contient les produits suivants:</H3>
            <P>
                <asp:Repeater id="Repeater1" runat="server"
                  DataSource='<%# Session["panier"] %>'>
                    <HeaderTemplate>
                        <table border="1">
                            <TR>
                                <TD>Réf. Produit</TD>
                                <TD>Titre</TD>
                                <TD>Editeur</TD>
                                <TD>Quantité</TD>
                                <TD>Prix unitaire</TD>
                                <TD>Prix total</TD>
                                <TD>Modification</TD>
                                <TD>Suppression</TD>
                            </TR>
                    </HeaderTemplate>
                    <FooterTemplate>
                        </table>
                    </FooterTemplate>
                    <ItemTemplate>
                        <TR>
                            <%-- Le client doit pouvoir modifier la
                            quantité aisément, dans le panier --%>
                            <FORM action="/controleur?cmd=modifierQuantité&produit=<%#
                           DataBinder.Eval(Container, "DataItem.Livre.Code")%>"
                                        method="POST">
                                <TD><%# DataBinder.Eval(Container,
                                   "DataItem.Livre.ISBN")%></TD>
                                <TD><%# DataBinder.Eval(Container,
                                   "DataItem.Livre.Titre")%></TD>
                                <TD><%# DataBinder.Eval(Container,
                                   "DataItem.Livre.Editeur")%></TD>
                                <TD>
                                    <INPUT type="text" value="<%#
                                   DataBinder.Eval(Container, "DataItem.Quantite")%>">
                                </TD>
                                <TD><%# DataBinder.Eval(Container,
                                   "DataItem.PrixUnitaire")%></TD>
                                <TD><%# DataBinder.Eval(Container,
                                   "DataItem.PrixTotal")%></TD>
                                <TD><INPUT type="submit" name="Modifier Quantité"></TD>
                                <%-- Le client doit pouvoir supprimer la ligne courante --%>
                                <TD><A href="/controleur?cmd=supprimerLigne&produit=<%#
                                   DataBinder.Eval(Container, "DataItem.Livre.Code")%>">
                                        Supprimer ligne</A></TD>
                            </FORM>
                        </TR>
                    </ItemTemplate>
                </asp:Repeater></P>
        </form>
        <HR>
        <%-- Le client doit pouvoir passer à la phase d'achat ou au devis--%>
        <H3>
            Souhaitez-vous <A href="/controleur?cmd=commander">passer commande</A> ?
            <BR>
            ou tout simplement
             <A href="/controleur?cmd=demandeDevis">demander un devis gratuit</A>?
        </H3>
        <HR>
        <%-- Le client doit pouvoir vider son panier d'un coup --%>
        <H3>
            Souhaitez-vous
             <A href="/controleur?cmd=viderPanier">vider complètement votre panier</A> ?
        </H3>
    </body>
</HTML>
				
				

Conclusion

Nous avons mis en œuvre sur un exemple partiel de librairie en ligne le processus agile que nous préconisons pour la modélisation d’applications web.

A partir de cas d’utilisation UML et de modèles d’analyse du domaine, nous avons progressivement ajouté des informations de plus en plus proches des choix d’implémentation, en prenant comme cible la plateforme .NET. Nous avons pour cela utilisé principalement le diagramme de séquence UML, ainsi bien sûr que le diagramme de classes.

Nous avons ainsi montré qu’il est possible avec une démarche systématique mais simple d’aboutir de façon efficace à du code résultant des différents diagrammes UML précédents dans un environnement .NET et C#. Il est à noter qu’une grande partie du travail pourrait également servir à une implémentation sur une cible technique différente, telle qu’un environnement Java ou PHP, par exemple.

Vous trouverez toutes les explications détaillées concernant les diagrammes UML ainsi que la démarche dans l’ouvrage paru récemment aux éditions Eyrolles.

Ressources

Premier article sur la démarche agile au service des applications web : http://dotnetguru.org/...

"UML2 - Modéliser une site application web", Pascal Roques, Eyrolles 2006 (dans la collection "Les Cahiers du Programmeur").

Auteur :Pascal Roques