Archive

Archives pour la catégorie ‘Web Services - SOA’

QCon London 2010 – Udi Dahan – Avoid a Failed SOA

“Business & Autonomous Components to the Rescue”

image Malgré un sujet pas très original, avec peu d’idées réellement neuves, probablement la meilleure présentation à laquelle j’ai assisté aux QCon 2010 de Londres. J’y ai été particulièrement sensible, du fait que j’ai moi-même réalisé et animé des séminaires sur des sujets similaires. Et j’ai pris une leçon, sur la forme comme sur le fond.

Sur le fond, finalement, un seul message simple est véhiculé par Udi Dahan : une condition nécessaire à la réussite d’une SOA c’est l’émergence de composants très faiblement couplés. Pas vraiment une surprise. Mais c’est grâce à une forme étudiée que son discours (simple mais pas simpliste) amène à se poser des questions profondes.

Sur la forme donc, un discours extrêmement clair sans utilisation d’aucun buzz, et un enchaînement logique des idées qui mène inexorablement l’auditoire à ses conclusions inéluctables. Quand la vidéo de cette présentation sera en ligne sur InfoQ (malheureusement, ils les distillent pendant six mois), ne la ratez pas.image

Je vais tenter de résumer.

Le sujet c’est le projet d’intégration. Pourquoi ça rate souvent, et comment faire que ça rate moins :-) On a le droit de se tromper plusieurs fois, mais à chaque fois différemment !

La présentation oscille autour de l’architecture entre la vision métier et la vision technologique.

SOA et couplage faible

Un des objectifs de la SOA est d’atteindre un couplage faible entre composants métiers autonomes. Tout le monde est d’accord là-dessus. Mais ce couplage faible doit être une exigence à la fois métier et technique qu’il faut prendre en compte à la conception comme à l’exécution.

imageUdi part d’un SI théorique plutôt bien aligné sur le métier (avec une véritable architecture fonctionnelle explicite) dont on pourrait se dire qu’il est facilement “SOAisable”.

Il montre qu’une intégration des applications par des services (une SOA) peut, en fait, mener facilement à des applications très fortement couplées qui amènent, en production, leur lot de contentions (mémoire, threads, locks base de données…) .

So what ? Qu’est-ce qu’on a loupé ?

On a oublié que pour obtenir le découplage à l’exécution il faut des communications asynchrones (d’un point de vue fonctionnel et pas seulement technique). Et il y a de fortes conséquences sur… la conception.

Il faut donc basculer du requête/réponse à la publication/abonnement (d’une architecture orientée services vers une architecture orientée événements). C’est la succession d’émission d’événements qui matérialise le processus et non l’orchestration d’appel de services. Et c’est l’émetteur qui définit le contrat de service et non le receveur. On parle d’Event Driven Architecture (EDA).

Mon avis

Même si ce qui vient d’être dit est parfaitement logique en terme d’affectation de responsabilités, la plupart des démarches de conception travaillent dans l’autre sens : le contrat de service est défini à partir du besoin du client du service (c’est ce qu’on fait quand on fait de la conception d’application : c’est le scénario d’utilisation qui définit les services publiés par le serveur métier). Il faut donc changer radicalement son mode dimagee conception lorsqu’on fait de la SOA/EDA : les contrats de service doivent être définis uniquement par les changements d’état des objets métier et non par les “clients” de ces changements d’état.

Autre réflexion que m’inspire cette vision (originale) de ce qu’est un processus SI : un enchainement infini d’événements. On ne peut plus définir un Processus avec un début (l’Evénement déclencheur) et une fin (un Produit de sortie) créant de la valeur pour son Client. C’est une révolution conceptuelle (on remet en cause la définition d’un processus selon l’ISO !) et surtout, ça pose un gros problème. Comment appliquer la doctrine millénaire du consultant en processus : “centrer les processus de l’entreprise sur le client”, si le client de l’entreprise n’est plus le client du processus ? Je n’ai pas de réponse pour le moment :-)

Composants métier autonomes

Udi Dahan évoque ensuite une autre question délicate. Comment partitionner les services en composants autonomes ? A nouveau, une réponse évidente est : aligner les composants sur le métier. Un composant métier par bloc fonctionnel. Un rêve d’urbaniste !

Il montre qu’en fait, ce partitionnement “idéal” ne répond pas toujours au besoin et  imageparticulièrement aux exigences non fonctionnelles. Il donne l’exemple des SLA différents en fonction du type de client et propose donc des composants métier autonomes techniquement (potentiellement très différents dans l’implémentation), définissant les mêmes contrats de service mais implémentés différemment.

Mais à nouveau, comment éviter un couplage si, finalement le routage des événement doit se faire en fonction de leur contenu (l’événement contenant un “petit client” doit être routé vers le composant dédié petit client, l’événement “gros client” vers le composant dédié gros client).

Le fonctionnement EDA précédent permet, à nouveau, à chaque composant d’être autonome dans la prise de décision : tous les composants d’un même métier sont abonnés aux mêmes événements et chacun décide de manière autonome de traiter ou non un événement particulier en fonction de son contenu.

A bientôt pour d’autres conférences QCon.

Categories: Web Services - SOA Tags: , , , ,

soapUI : tests de charge de Web Services

Je continue mon tutorial sur soapUI. Voyons cette fois-ci comment utiliser soapUI pour réaliser des tests de charge.

Il faut ajouter un nouveau test de charge sur le TestCase voulu.
Note: il faut savoir que le test de charge va lancer tous les tests en parallèle, donc il ne faut pas qu’il y a de dépendance entre les services du TestCase, car ceci pourrait fausser vos résultats.

clip_image002

Une fenêtre s’ouvre, il est possible de choisir la stratégie de test et de la configurer.
A savoir : la durée du test, le nombre de threads à utiliser, le délai (aléatoire ou non) entre chaque nouvelle requête, etc.

clip_image004

Sur cette image on peut se rendre compte qu’un service qui renvoie une stacktrace d’exception est couteuse en temps et en données.


Le tableau de résultat affiche : le temps de réponse min max moyen, le nombre de requêtes totales lancées lors du test, le total de données transférées, le nombre d’erreur.

De plus, la console de log en dessous permet d’avoir des détails sur les tests déroulés, comme l’heure de début et de fin du test, les éventuelles erreurs, etc …

Charger une association dans WCF RIA Services

Je l’avais annoncé ici : .NET RIA services est devenu WCF RIA Services.

Rappels

L’objectif de ce projet est de simplifier le développement d’applications RIA.

Le principe général est assez simple :
Je développe des services de domaine (CRUD + Queries) en utilisant des conventions de nommage côté serveur.

Par exemple, la méthode Sprint LoadSprint(int sprintId) renvoie un sprint d’une application Scrum à partir de son identifiant.

WCF RIA Services projette ce code côté client dans des classes de type DomainContext.

Dans notre exemple, j’obtiens une classe ScrumDomainContext avec une méthode EntityQuery<Sprint> LoadSprintQuery(int sprintId)

Projection de code

Projection de code

Les associations

La version beta est disponible depuis le mois de Novembre. On trouve sur le Web quelques introductions, notamment celles de Brad Abrams. En revanche, on trouve très peu de choses sur comment charger une association dans notre application cliente Silverlight.

Dans mon exemple, je veux afficher une vue Master/Details qui présente un sprint et la liste de ses tâches.

Le modèle

Sprint association

Sprint association

La déclaration de l’association

Je dois ensuite décrire à WCF Ria services les associations entre mes entités. Pour cela, je décore les propriétés Tasks de la classe Sprint, et Sprint de la classe Task avec l’annotation AssociationAttribute. Il faut indiquer un nom pour cette association, par exemple Sprint_Tasks et préciser les clés étrangères de chacune de ses relations. Dans le sens Sprint -> Task, la clé c’est le champ Id de la classe Sprint et la clé étrangère c’est le champ SprintId de la classe Task.


public class Sprint{
[Key]
public virtual int Id { get; set; }

[Association("Sprint_Task", "Id", "SprintId")]
public virtual ICollection Tasks { get; set; }
}

Quelques remarques :

  1. Les habitués de NHibernate vont déplorer le fait d’avoir à décrire l’association à l’aide des clés étrangères. Cela nécessite par ailleurs d’avoir une propriété SprintId dans la classe Task en plus de la propriété Sprint :(
  2. La décoration est automatique avec l’utilisation de LinqToSql ou d’Entities Framework

Le chargement explicite

Il reste enfin à indiquer explicitement que l’on souhaite sérialiser les tâches avec le sprint. Pour cela, nous devons définir une classe de méta données relative à la classe métier. Dans notre exemple, ce sera une classe SprintMetaData définissant un champ Tasks que l’on décore avec l’annotation IncludeAttribute.


public class SprintMetaData {
[Include]
public EntitySet Tasks;
}

Je vous laisse regarder le blog de Brad Adams ou un ancien billet pour les détails de la classe de méta données.

Personnellement je trouve dommage d’avoir à définir une stratégie de chargement dans un fichier de méta données. L’idée générale n’est pas mauvaise, mais présente un inconvénient majeur : la stratégie est valable pour tous les cas d’utilisation. Or il est probable que l’application ne nécessite à la fois le sprint et ses tâches que dans certains écrans …

Outils de mapping objet/relationnel

Si vous utilisez un ORM, n’oubliez pas de récupérer la collection de tâches dans votre requête.

Avec LinqToEntities, ça donne :


public Sprint LoadSprint(int sprintId){
return this.Context.Sprints
.Include("Tasks")
.Where(sprint=>sprint.Id == sprintId);
}

Avec LinqToNhibernate, ça donne:


public Sprint LoadSprint(int sprintId)
{
var result = this.Session.Linq().Expand("Tasks")
.Where(x => x.Id == sprintId)
.ToList().First();
return result;
}

Conclusion

Nous avons vu en détail comment charger une association entre deux entités dans une application WCF Ria Services. Une partie de ces détails est masquée par l’outillage fourni par Microsoft et nous ferait presque oublier la complexité qui ne manquera pas de ressortir si vous souhaitez utiliser cette pile en association avec des outils tel que NHibernate

soapUI : pré-remplir les champs d’une requête

Suite de mon tutorial sur soapUI, voyons cette fois-ci comment pré-remplir certains champs d’une requête. Par exemple, un login et un password nécessaire pour se connecter.

Si vous avez une série de requêtes dans votre Test case, il est préférable de créer un script qui se chargera de vous pré-remplir ces champs plutôt que de le faire à la main ;-)

Il faut créer un nouveau « step » nommé ‘Groovy Script’.

clip_image002

Voici un exemple de code qui pré-rempli les champs ‘login’ et ‘password’. Ces valeurs doivent être déclarées et initialisées dans l’onglet « Custom Properties » du projet (il s’affiche en cliquant sur le nom du projet).

image

Entrez ensuite le code du script :

image

Un petit Copier-(Réfléchir*)-Coller du code suivant simplifiera le travail !             (* © F.D.)

def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
//variables definitions
def login = '${#Project#login}'
def password = '${#Project#password}'

//Retrieves all TestSteps of the current testCase
log.info("* " + testRunner.testCase.name )
def testStepList = testRunner.testCase.getTestStepList()

testStepList.each{currentTestStep->
    if (currentTestStep.name != "Inits fields") { //ici liste des steps que le script ne doit pas modifier
        log.info(" \\-- " + currentTestStep.name )
        def holder = groovyUtils.getXmlHolder( currentTestStep.name+"#Request" )
        log.info(" " + 'holder' )
        holder.namespaces["ns"] = "http://schemas.xmlsoap.org/soap/envelope/"

        //Inits values of the current testStep
        log.info(" " + 'login' )
        holder.setNodeValue("//ns:Body/*/login", login)
        log.info(" " + 'password' )
        holder.setNodeValue("//ns:Body/*/password", password)

        //Updates the change
        holder.updateProperty()
    }
}
'Script OK'

Voici la requête une fois le script exécuté :

image

Note : pour éviter de faire un copier-coller du code à chaque Test case, il est possible de cloner ce « step » et le déplacer dans un autre Test case :-)

soapUI : tester l’enchainement de Web Services

Dans un précédent article, je vous ai montré comment tester unitairement un Web Service. Cette fois-ci, nous allons aller un peu plus loin en testant l’enchainement de plusieurs Web Services.

Comme nous l’avons vu chacun de nos tests unitaires se trouve dans un arbre. Il est alors possible de lancer l’ensemble des tests de la suite, ou toutes les étapes d’un scénario, simplement en double cliquant sur le nœud correspondant de l’arbre. (Nœuds : TestSuite ou TestCase)

Une fenêtre s’ouvre et permet de voir les résultats

clip_image002[10]

A peine plus compliqué, il est aussi possible de récupérer une valeur dans une réponse et de l’injecter dans le test suivant.

Exemple d’utilisation : Dans nos jeux de tests, on veut réaliser l’enchainement suivant :

  • Créer une commande (createOrder)
  • Annuler la commande qui vient d’être créée (cancelRequestNumber)

sachant que ce dernier service prend en paramètre un « request number » qui est renvoyé dans la réponse du « createOrder ».

Pour récupérer cette valeur et remplir notre requête « cancelRequestNumber », on utilise la fonctionnalité offerte par soapUI : le « Property Transfer ».

La valeur à récupérer (la « Source ») :

image

Le champ à remplacer (la « Target ») :

image

On ajoute un « step » ‘Property Transfer’ à notre Test Case « PropTransfer » :

clip_image006

On donne un nom au remplacement automatique qui sera effectué, à chaque exécution des tests :

clip_image008

On configure les chemins vers les champs qui nous intéressent :

image
Les chemins représentent les nœuds XML, de la requête et de la réponse SOAP, à parcourir pour atteindre les champs voulus

On place maintenant le « step » ‘Property Transfer’ entre les 2 tests (createOrder et cancelRequestNumber), de façon à obtenir un enchainement logique dans notre TestCase ‘PropTransfer’ :

clip_image012

On peut maintenant dérouler l’ensemble du Test Case :-)

soapUI et les tests de Web Services

SoapUI est un outil de test de Web Services développé par Eviware. Il existe en 2 versions dont une entièrement gratuite. Je le trouve très utile pour le debug et les tests unitaires de web services, mais aussi pour les tests automatisés et les tests de charge.

Je vous propose de découvrir dans cet article comment utiliser SoapUI pour réaliser des tests unitaires.

Lire la suite…

Livre: Real World Java EE Patterns

CouvertureTout commence par une présentation des changements et des nouvelles possibilités apportées par Java EE 5 (EJB 3.0, JPA 1.0…) et Java EE 6 (EJB 3.1, JSF 2.0…).

Puis l’auteur reprend un à un les Core J2EE patterns pour les mettre au goût du jour: Façade, Data Access Object, Transfert Object… Certains deviennent inutiles, d’autres sont transformés, d’autres tirent partie des nouveautés pour faire leur apparition. Les patterns concernant la couche présentation sont toutefois éludés.

J2EE 1.4 était synonyme de lourdeur et de développements rébarbatifs. Ici, toute complexité, tout code superflu est traqué, avec en ligne de mire une architecture simple et du code concis donc maintenable.

Le livre fait la part belle à la pratique en proposant une méthode de migration de J2EE 1.4 vers Java EE 5 et de nombreux exemples de code (DAO générique, connecteur JCA générique…).

Categories: Java EE, Web Services - SOA Tags: , , , ,

API REST en .NET

Suite à mon dernier article sur le RIA et la formation en soirée que j’ai animée, j’ai eu quelques questions sur comment exposer un modèle relationnel dans un mode REST en .NET et plus particulièrement pour un client RIA genre Silverlight.

Je vais donc vous proposer une série d’articles sur le sujet.

Le premier présentera ADO.NET Data Services, le framework de Microsoft qui à partir d’un provider LINQ peut exposer votre modèle d’entité sur HTTP dans un mode REST.

A titre d’exemple, je vais utiliser le prototype que j’ai réalisé pour une application traitant de la traçabilité des produits sanguins au CHU de Grenoble. J’ai donc le modèle d’entités suivant:

Modèle d'entités

Modèle d'entités

Depuis Visual Studio, j’ai créé un service ADO.NET Data Services. Je lui ai indiqué mon modèle d’entités et j’ai ajusté les autorisations. La ligne suivante indique que les entités Etat sont accessibles en lecture seule.

config.SetEntitySetAccessRule(« Etat », EntitySetRights.AllRead);

Mon modèle est maintenant accessible sur HTTP. Je peux regarder sa description à l’URI suivante : http://mondomaine.com/DTI.svc/

Le modèle REST exposé par ADO.NET Data Services

Le modèle REST exposé par ADO.NET Data Services

Les connaisseurs noteront que la description de notre API utilise Atom Publishing Protocol et Atom Syndication Format.

Je peux maintenant interroger mon modèle en requêtant directement avec mon navigateur. Par exemple, pour avoir toutes les poches, je vais utiliser l’URI http://localhost:2427/DTI.svc/Poche

Personnellement, pour vérifier mes requêtes j’utilise Fiddler. Par défaut, on obtient un feed Atom contenant une collection de poches. ADO.NET Data Services supporte également le format JSON. Si dans Fiddler, vous modifiez le header HTTP Accept avec application/json vous obtiendrez un flux JSON:

Une collection de poches au format JSON

Une collection de poches au format JSON

ADO.NET Data Services ne se limite pas à récupérer une collection d’entités. On peut filtrer les entités sur certains critères. Par exemple l’URI http://localhost:2427/DTI.svc/Poche?$filter=NumDon%20%eq%20%12345678 me permet de récupérer la/les poches dont le champ NumDon vaut 12345678. On peut également récupérer les entités associées aux poches. L’URI http://localhost:2427/DTI.svc/Poche?$expand=Tracabilite récupère les poches avec leurs traçabilité sachant qu’une poche peut avoir plusieurs traçabilités.

Les principales fonctionnalités de requêtage sont disponibles: filtre, tri, pagination. Le format des URI est décrit ici

Dans les applications de gestion de données, on ne se limite pas à afficher des données. On souhaite aussi ajouter, modifier, supprimer. Dans le monde REST, on utilise pour cela le verbe HTTP. Par défaut, lorsque vous saisissez une URI dans votre navigateur, c’est le verbe GET qui est utilisé. Mais on peut aussi utiliser les verbes POST, PUT ou DELETE si les conditions d’accès que nous avons définies sur le serveur le permettent.

On peut noter que toute cette API repose sur des standards reconnus: HTTP, Atom, JSON. Elle peut donc être interrogée par n’importe quel client qui supporte ces standards.

Dans le prochain article, j’expliquerai comment interroger cette API à partir d’un client Silverlight et de LINQ For ADO.NET Data Services.

Premières impressions avec .NET RIA Services

Chose promise, chose due ! Je vous livre mes premières impressions sur les tests que j’ai réalisés avec .NET RIA Services, maintenant renommé WCF RIA Services. Pour l’instant j’ai beaucoup de bonnes surprises…

J’ai commencé par la validation des formulaires.
Je souhaitais vivement regarder la validation des formulaires. L’infrastructure utilisable en Silverlight 2.0 me plaisait beaucoup mais manquait d’une couche d’industrialisation. Pour rappel, cette validation nécessitait les actions suivantes:

  1. Déclarer une liaison de données en mode TwoWay avec notification d’erreurs de validation (généralement dans le XAML). Pour une TextBox liée à la propriété Commentaire d’un objet source, ça donne: textboxbindee
  2. Lever une exception dans le converter ou dans la méthode set de la propriété de l’objet source si la règle de validation n’est
  3. Récupérer l’évènement BindingValidationError. En général, on utilise alors le VisualStateManager pour passer le contrôle courant dans l’état Erreur qu’il aura fallu définir au préalable.

DataForm

Puisqu’on souhaite systématiquement passer dans l’état Erreur du contrôle, on pourrait avoir un contrôle conteneur écrit une fois pour toute qui supporte ce scénario. C’est le DataForm qui est disponible en Silverlight 3.0.

Méta données et validation

Redéfinir les méthodes set des propriétés des objets sources n’est pas forcément facile lorsqu’on travaille avec des proxies issus d’un WSDL ou d’un service ADO.NET Data Services. Par ailleurs, lorsqu’on a goûté à Hibernate Validator, on aime bien définir les règles de validation avec des annotations. Avec .NET RIA Services, c’est maintenant possible. Il faut définir une méta-classe dans laquelle on définit les règles de validation avec des annotations. En tirant avantage des classes partielles de .NET, on indique la méta classe à utiliser sans risque que le générateur écrase nos modifications. J’entends déjà les puristes se demander pourquoi les annotations ne sont pas directement placées sur les propriétés. C’est justement pour éviter d’avoir des conflits avec le générateur de code. Cette stratégie est très efficace.

La méta classe associée à la classe métier Project

La méta classe associée à la classe métier Project

Ces annotations sont définies coté serveur et projetées coté client pendant la phase de compilation du projet. WCF Ria services peut donc exploiter ces annotations coté client pour gérer la validation de surface sans avoir à réaliser un aller-retour sur le middle tier.

CRUD et méthodes complexes

Autre dilemme lorsqu’on travaille sur une application de gestion de données en RIA : les données doivent-elles être exposées en mode RESTFull ou en mode SOAP (sous-entendu contrat de service). Très clairement, lorsqu’on travaille sur du CRUD, le RESTFull est très pertinent. Inversement, lorsque les règles métiers sont importantes, le contrat de service a toute sa place. C’est notamment le cas lorsqu’il faut implémenter des règles de validation complexes qui ne dépendent pas seulement des données fournies par l’utilisateur. Il faudrait donc pouvoir passer facilement d’un mode à l’autre. Et bien c’est exactement ce que propose .NET RIA Services. Par défaut les services proposent des CRUD pour chaque entité, et on peut rajouter des opérations taggées Custom. Toutes ces opérations sont réunies dans un service de domaine.

Conclusion

Je n’ai pas encore regardé l’ensemble des possibilités, mais pour l’instant, je retrouve une productivité similaire à une architecture de type client lourd (genre WPF) et ORM (genre Hibernate).

Dans le prochain article, je vous présenterai l’intégration de l’authentification et des autorisations entre Silverlight 3, .NET RIA Services et une application ASP.NET

EDA in the Cloud

Je viens de lire un article qui vaut le détour si vous êtes intéressés par les architectures orientées évènements (EDA) et le Cloud Computing.

Simon Davies a réalisé un POC permettant l’intégration et la communication entre :
- une application s’exécutant dans l’App Engine de Google
- une application s’exécutant dans Windows Azure
- une application de type console s’exécutant derrière un firewall

Le middleware a été réalisé avec le composant « Service Bus » de la plateforme .NET Services.

L’article en question.