Bien Tester une application Asp.net MVC

Janvier 21st, 2010

Lien: http://docs.google.com/View?id=dhp3ggmx_168c5md3p52

 

Bien Tester ASP.Net MVC 1.0

Genèse

ASP.Net MVC est né avec plein de bonnes résolutions, et notament celle d' enfin permettre du test unitaire sur les applications Web programmées avec le framework.Net .

Je dis "enfin" car le Test ne passionne pas les foules, et pas vraiment les développeurs, encore moins les responsables ou les clients qui voient en lui une perte de temps ou source de coûts supplémentaires!

Evidemment - et paradoxalement- nos clients (ou parfois chefs de projets) aimeraient bien voir leurs applications garanties exempte de tout défaut, et donc testées, mais bien souvent n'imaginent pas que cela est possible à faire à moindre coût et par un automate.

Comme ils croient surtout que cela coûte trop cher (ou trop de temps) ils font donc passer à la trappe cette étape, qu'ils rejettent d'ailleurs -à tort- en fin de planning alors qu'elle devrait prendre place dès le tout début du projet en se fondant dans les spécifications (pour en diluer le coût).

Pour ce qui est des technologies .Net, on ne peut pas dire que le test ait été placé au coeur de la plateforme. Il a fallu tout de même attendre la version 4 du framework pour réaliser la notion de "code contract", notion omni-présente dans des langages comme Eiffel dont s'inspire pourtant largement C#.

Pour ce qui est de la programmation Web sur la plateforme Microsoft, les WebForms (ASP.Net classique) étant intestables dans leur coeur, il fallait introduire soi-même le pattern MVC, celui par qui le test est possible, ou utiliser un framework additionnel (Monorail par exemple, donc j'avais parlé ici il y a quelques années http://www.castleproject.org/monorail/index.html )

Heureusement, et presque 10 ans après l'apparition d'ASP.Net, Microsoft rend officiel l'utilisation du pattern MVC. Il était temps! Mais que de retard accumulé par rapport aux autres plateformes!

Aidé par un puissant site de présentation et d'aide aux développeurs ( http://www.asp.net/mvc/ ), les développeurs vont enfin pouvoir sortir du modèle "dictatorial" des Webforms et retrouver des façons de programmer le web plus "dans les normes", ou du moins, plus proches des autres frameworks (JSF, RubyOnRails, PHP, etc...)... et pouvoir enfin envisager de tester facilement et sereinement!

Pourtant, trouver des bons exemples de code de tests (TDD) pour ASP.Net MVC, relève du parcours du combattant: code obsolète, différentes releases de ASP.Net MVC, examples incomplets, y compris dans la doc officielle (et quand ca compile, on peut s'estimer heureux), informations contradictoires, besoin d'utiliser à la fois des Mock-ups et de de l'injection de dépendance.... de quoi décourager le plus motivés des adeptes du TDD comme moi.

Quasiment tous les articles qui datent de 2008 sont obsolètes (par exemple http://dotnetslackers.com/articles/aspnet/ASPNETMVCFrameworkPart2.aspx ) mais ils contiennent des idées qu'il faut assimiler.

Indispensable, la classe utilitaire donnée par Scott H. mais qui compile pas :((( http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx

... que d'embuches!

Quand on sait que l'approche TDD (et BDD) [Test Driven Development et Behavior Driven Development ] est la seule qui permette de GARANTIR qu'un logiciel est conforme à ce qu'on attend de lui (via l'écriture de spécification formelles), on a besoin d'y voir clair dans les tests.

Alors voici un article en français qui explique tout, simplement (j'espère), et dont les exemples compilent!

1 - Que faut-il pour tester?

un framework de test est indispensable. Mais lequel choisir? il y en a tellement....

pour comparer d'un point de vue pratique, vous pouvez consulter cette page:

http://xunit.codeplex.com/wikipage?title=Comparisons

mais chacun a ses préférences... difficille de faire un classement objectif et trouver des critères de notations entièrement acceptés par la communauté.

Pour ma part, j'ai choisi xUnit, uniquement pour sa simplicité

http://jamesnewkirk.typepad.com/posts/2007/09/announcing-xuni.html

voici quelques unes de ses caractéristiques:

· Single Object Instance per Test Method.

· No [SetUp] or [TearDown].

· Aspect-Like Functionality.

· Reducing the Number of Custom Attributes.

· [TestFixture] was removed entirely, so tests can be anywhere.

· [Ignore] is expressed using the Skip= parameter on [Test]

· [ExpectedException] was replaced with Assert.Throws.

· [TestFixtureSetup] and [TestFixtureTearDown] are instead expressed as implementations of an interface (ITestFixture).

· Support for IDisposable was added for tests.

2 - Tester, tester.... oui mais tester quoi?


Une application, qu'elle soit Web ou pas, est un ensemble composite.

Il y a multitude de choses qui s'y passe.

Quand on n'utilise pas de pattern et qu'on ne se pré-occupe pas d'architecture logicielle, tout est mêlé dans un code "spaghetti", souvent dans peu de fichiers qui font chacun des milliers de lignes. Dans ce cas, on va avoir beaucoup de mal d'effectuer des tests clairs.

Une Séparation des Responsabilités dans le code (SoC: Separation of Concerns), une architecture N-tiers, une approche Domain Driven, un couplage lâche, une architecture bien pensée, sont évidemment les pré-requis d'un bon projet guidé par les tests (Tests Driven Development).

Le pattern MVC va beaucoup nous aider, puisqu'il sépare le code de la vue, de celui du contrôleur, et du modèle.

Tester la vue en elle même

Pour ce qui est de tester le contenu d'une page HTML, qu'une zone de texte soit bien remplie par la bonne valeur, que la bonne CSS s'applique ou que le nombre d'éléments dans une boite déroulante soit conforme à ce que l'on attend, le Unit Testing n'est pas vraiment l'outil idéal.

Quoiqu'il existe des frameworks qui ont tenté de le faire : http://nunitasp.sourceforge.net/ projet abandonné, ou http://htmlunit.sourceforge.net/ mais pas de portage .Net à ma connaissance.

Il existe malgré tout des outils de tests qui agissent directement sur l'IHM et donc dans notre cas sur le navigateur Web , avec des capacités de comprendre ce qui se passe sur la page HTML (à l’aide de notre ami JQuery) comme le très puissant Selenium IDE ( http://seleniumhq.org/ ) qui va vous générer le code NUnit de test des pages Html à intégrer dans votre solution .Net.  Malheureusement vous serez dépendant d’un serveur Web pour effectuer vos tests, et le principe d’isolation des tests unitaires n’est pas respecté.

En attendant la solution qui comble la brèche…

Tester qu'une vue s'affiche bien

C’est assez trivial mais c'est un début :

[Fact]

public void ReturnsViewResultWithDefaultViewName()

{

// Arrange

var controller = new HomeController();

// Act

var result = controller.Index();

// Assert

var viewResult = Assert.IsType<ViewResult>(result);

Assert.Empty(viewResult.ViewName);

}

Cela permet de vérifier que vous n'avez pas fait de grosses erreurs dans le montage de votre solution Asp.Net MVC. Malheureusement ca ne teste pas des erreurs éventuelles dans le fichier de vue (.aspx)

Notez au passage le tryptique classique d'une méthode de test 1)Arrange 2)Act 3)Assert.

Si votre contrôleur fait passer des bouts de données à la vue par l'intermédiaire du dictionnaire ViewData , il vous suffira de rajouter une ligne:

Assert.Equal("Welcome to ASP.NET MVC!", viewResult.ViewData["Message"]);

Toujours trivial. Et relativement peu utile.

La bonne pratique est d'utiliser une vue fortement typée, ce qui donne quelque chose comme ca dans l'entête de la déclaration de votre vue:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"

Inherits="System.Web.Mvc.ViewPage<ManagePassword.Domain.OperationResult>" %>

ManagePassword.Domain est la librairie de domaine de notre application, et OperationResult est l'objet Modèle (au sens MVC) qui va transiter entre la vue et le contrôleur.

Notre test pourra déjà s'assurer que le contrôleur renvoie bien un objet de ce type là.

// ASSERT

Assert.NotNull(results);

Assert.NotNull(results.ViewData.Model);

var res = Assert.IsAssignableFrom<OperationResult>(results.ViewData.Model);

L'idée d'avoir un modèle déterminé (et donc fortement typé) afin de pouvoir passer de multiples valeurs et tester ce que le contrôleur va retourner à la vue.

Par exemple, on a souvent besoin d'une page qui fait le résumé de l'opération qui vient d'être demandé, et un modèle simple (mais récurrent) pourrait être:

public class OperationResult

{

public bool isOk;

public string errorMessage;

}

Notre test va pouvoir porter maintenant sur les membres du Model, et donc faire plus de vérifications.

// ASSERT

Assert.NotNull(results);

Assert.NotNull( results.ViewData.Model);

var res = Assert.IsAssignableFrom<OperationResult>(results.ViewData.Model);

Assert.Equal(false, res.IsOk);

Tester les redirections

Une redirection peut avoir lieu dans votre contrôleur, la tester permet de savoir par quel point ^de code le contrôleur a terminé son exécution. Pour cela le code de test ressemblera à ceci :

///ACT

var results = controler.ChangePassword(userInfo) as RedirectToRouteResult;

// ASSERT

Assert.True(controler.ViewData.ModelState.IsValid);

// permet de tester que c'est bien un RedirectToRouteResult qui a été retourné (à cause du AS plus haut)

Assert.NotNull(results);

La ligne 1) ne plantera pas au cas où le code du contrôleur ne renvoi pas un objet de redirection ( ). Par contre Assert.NotNull(results); génèrera un échec du test car en cas d’echec du cast par AS, la variable contient le pointeur vers Null.

Pour rappel, une méthode de test ne doit attendre qu’un seul comportement possible.

Si vous voulez tester le cas où le contrôleur ne fait pas d’indirection (et renvoi des valeurs via le modèle), écrivez alors une autre méthode de test pour ce cas là. Attention à ne pas mettre de logique  IF… ELSE…  dans une méthode de test. Car cela est banni.

Dans la vraie vie, le but du programme est de faire en sorte que le Contrôleur appelle un (ou plusieurs) objets du domaine avec un minimum de logique (car la logique doit être dans le domaine). Le contrôleur s’occupe de la logique nécessaire pour préparer l'affichage (et donc le Modèle pour alimenter la vue), et c'est de cela dont il va falloir maintenant s’occuper.

Tester le contrôleur tout seul

Comme je le disais plus haut, la meilleure pratique nous conseille de déporter la logique du domaine (que l'on appelle souvent Métier en France) de l'application.

Hors, dans une démarche de test, la meilleure pratique est de ne tester d’une seule chose à la fois (isolation du test).

Si nous testons le contrôleur, nous devons ne tester que les appels de code dans son corps et non pas tous les objets dont il dépend et/ou auxquels il fait appel.

Il va donc falloir « débrancher » le Contrôleur de tout ce qui pourrait parasiter le test.

Comment faire sans écrire du code compliqué, et surtout sans toucher au code du contrôleur qui doit être transparent au test ? On ne doit pas changer le code de ce qui doit être testé pour le rendre testable ! Sinon le test est biaisé.

Les 2 choses typiques à débrancher sont : le ou les objets de domaine (ou système d’accès aux données), et le contexte sous-jacent au contrôleur (routage, requête http, contexte session, etc.).

Pour ce dernier, ASP.Net MVC est assez bien fait et les dépendances en place n’empêchent pas les tests de fonctionner en isolation, c'est-à-dire sans la présence d’un serveur HTTP.

Ceci dit, si on a besoin de tester le comportement d’un contrôleur en fonction de ce qui peut se passer au niveau Requête HTTP par exemple, on a la possibilité de fournir un faux contexte HTTP.

Vous trouverez de quoi réaliser ceci avec une classe d’aide aux tests, que vous devrez intégrer dans le projet de test : MvcMockHelpers

Vous en trouvez le code ici : http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx

Elle vous propose (entre autres) un FakeHttpContext que vous brancherez à votre contrôleur avec une méthode d’extension, comme celle ci :

controler.SetFakeControllerContext();

Cette classe repose sur un  framework de Mock-up. Le code donné fonctionne avec différentes librairies : RhinoMocks, TypeMock ou Moq.

Personnellement j’ai choisi Moq, car c’est le plus « fluent » au niveau API, sans être abscon, et celui qui a la syntaxe la plus claire pour spécifier le comportement des bouchons, mais nous allons le voir plus loin.

Le seul (petit) problème c’est que cela peut ne pas compiler. Il vous faudra chercher un certain moment sur le net avant de trouver ce « hack » :

http://stackoverflow.com/questions/205644/error-when-using-extension-methods-in-c

et qui vous conseille d’ajouter ces quelques lignes de code au fichier dans lequel vous aurez mis le MvcMockHelpers:

namespace System.Runtime.CompilerServices

{

/// <summary>/// to avoid the following error: Missing compiler required member 'System.Runtime.CompilerServices.ExtensionAttribute..ctor'

/// </summary>

public class ExtensionAttribute : Attribute { }

}

Les méthodes d’extension SetHttpMethodResult et SetupRequestUrl vous seront bien utiles pour tester le comportement de votre contrôleur quand l’invocation se fait par une méthode HTTP GET ou HTTP POST, ou si son code vérifie l’URL demandée.

Bouchons à la rescousse

Mais une bonne partie du comportement d'un contrôleur repose sur l'appel à (et sur les réponses fournies par) un ou plusieurs objets de domaine.

Personnellement je mets toute la logique de mon application dans ces objets et je ne fais pas d'appel aux données directement. Pour ceux qui font le contraire,  la logique de tests est de toute façon la même. Pour que le test puisse tourner indépendamment (sur un serveur de Build ou dans Gallio Icarus par exemple), il ne faut pas de liaison à une base de données ou à tout autre système externe.

C'est aussi pour cela que passer par des objets de domaine, même s'ils ne font que du CRUD, va simplifier le code dans le contrôleur et donc faciliter les tests.

L'avantage majeure résidant dans ces objets de domaine, puisque c'est nous qui les écrivons "à la main", c'est d'avoir une interface que les bouchons vont exploiter.

Je ne vous fais pas l'affront d'expliquer pourquoi une interface est bonne pour votre architecture.

Tout ce qui est à l'extérieur de notre  contrôleur à tester devrait avoir une interface. C'est le cas par exemple d'un Web Service. Quand vous allez vous brancher à une Web Reference, Visual Studio va avant tout construire une Interface (au sens C#) et vous allez pouvoir travailler avec celle-ci.

De toutes façons, il est aisé d’admettre (ou de constater) que tous les frameworks de bouchonnage (mockup) vont exiger une interface afin de pouvoir travailler, donc vous n'avez pas le choix.

Partons du cas où nous avons été de bons élèves et où nous disposons d'une IquelqueChose pour nos objets de domaine (Si ce n'est pas le cas, un petit coup de refactoring et en 3 secondes nous auront ce précieux fichier).

Armé de cette précieuse Interface, donc, vous la passerez en carburant au constructeur du Mock. Avec Moq, cela ressemble à ceci :

//Arrange

// create the mock

var mockRepository = new Mock<IDomainManagingPasswords>();

L’idée est ensuite de faire passer au contrôleur, un objet factice fabriqué par le mockRepository, qui va répondre à l’interface voulue.

Donc vous aurez à modifier le code du contrôleur pour qu'il travaille non plus avec une instance interne du (ou des) objet de domaine, mais avec une référence sur l'Interface, et fourni à l'extérieur du contrôler.  C’est la seule chose que vous devez modifier dans votre contrôleur pour le rendre testable, mais à bien y réfléchir, c’est plus une façon de programmer qu’une contrainte donnée par la démarche de test. Je m’en expliquerai dans un prochain article sur la qualité du code et les enjeux du test dans l’optique de la programmabilité et de la maintenabilité du code.

Cette différente façon de faire consiste à très fortement découpler les objets entre eux. A bien y réfléchir, un objet (ici le contrôleur) a toujours besoin d’un (ou plusieurs) autre objet pour réaliser le comportement attendu. Ne serait-ce que parce que nous avons à notre disposition foultitude d’objets prêt à être réutilisés.

Pour ce faire, nous avions souvent l’habitude d’instancier ces objets tiers, au moment où nous en avions besoin. Parfois, au mieux, nous procédions à leur instanciation/initialisation dans le constructeur de l’objet qui en fait usage.

Ce n’est pas une bonne pratique, car cela ne laisse aucun contrôle sur ces objets (comment ils doivent être initialisés, etc). Il est donc plus profitable (et pas que pour des besoins de tests) de passer des pointeurs sur ces objets au moins au constructeur de celui qui en fait usage, et voir même à chaque méthode dans certains cas.

Pour notre contrôleur cela donne ceci :

private readonly IDomainManagingPasswords _domainObject;

/// <summary>

/// constructeur avec parametre pour accepter le Mocking...

/// </summary>

/// <param name="domainObj">The domain object.</param>

public ManageController(IDomainManagingPasswords domainObj)

{

_domainObject = domainObj;

}

Ensuite à l’intérieur des méthodes du contrôleur, on utilise librement la variable _domainObject comme si de rien n’était.

Cette variable sera occupée par l’objet bouchon lors du test, et cela nous permettra d’ordonner au bouchon d’avoir un comportement A ou B, selon les besoins du test.

Les possibilités donc de « jouer » avec le test sont maintenant très nombreuses.

Par contre, il faut que le contrôleur continue de fonctionner dans son environnement initial, à savoir lorsque le site Web fonctionne dans IIS ou Cassini (ou Apache). Et dans ce cas, le framework Asp.Net MVC s’occupe d’initialiser les contrôleurs, et pour cela il appelle le constructeur sans paramètre de chacun ; ce qui est bien normal, car il n’est pas capable de décider quelle instance d’objet tiers lui passer.

Et évidement, dans ce contexte, on ne travaille plus avec les bouchons mais avec les implémentations « qui marchent » !

Alors comment faire ?

Inversons le contrôle

Il faudrait avoir un mécanisme qui de manière transparente à tout mécanisme (je pense en particulier au mécanisme d’initialisation de Asp.Net MVC, puisse instancier lui-même les objets « qui marchent » et les donner à ceux qui s’en serve.

Dans notre cas, il s’agit de faire passer des objets de domaine correctement instanciés et initialisés, aux constructeurs des contrôleurs lorsque ceux-ci sont mis en route par l’infrastructure de Asp.Net MVC, sur laquelle bien sur nous ne pouvons pas opérer de modification de comportement, puisque le code ne nous appartient pas et qu’il est déjà compilé.

C’est là où l’Inversion Of Control (IoC, tellement plus chic) entre en scène et trouve une de ses nombreuses utilités.

L’idée initiale de l’AOP (qui a inspiré l’Injection de Dépendance) était de permettre au développeur de supprimer la plomberie dans son code, c'est-à-dire sortir toutes les lignes de code qui n’avaient pas vraiment attrait à son algorithme mais qui étaient nécessaires ; sans quoi, justement, les objets dont il dépendait (accès aux données ou à une information tierce) ne pouvaient pas opérer comme il le souhaitait.

Dans le cas du test d’un projet Asp.Net MVC avec de l’injection de dépendance, vous trouverez foison d’exemples et de frameworks.

Quelques points d’entrées :

http://www.mikesdotnetting.com/Article/117/Dependency-Injection-and-Inversion-of-Control-with-ASP.NET-MVC

http://www.rickardnilsson.net/post/2009/12/25/Dependency-injection-in-ASPNET-MVC-with-Unity-IoC-Container.aspx

http://scottfindlater.blogspot.com/2009/11/tdd-mvc-12-inversion-of-control-ioc.html

http://codeclimber.net.nz/archive/2009/02/05/how-to-use-ninject-with-asp.net-mvc.aspx

Mais nous voulons rester pragmatiques, et le problème qui nous intéresse ici est « comment faire en sorte que le contrôleur obtienne un objet de domaine correctement instancié et initialisé quand le projet tourne en mode non-test, c'est-à-dire avec un constructeur sans paramètre ? ».

Mon critère est assez simple : j’ai retenu la solution qui m’oblige à écrire le moins de code possible, qui soit la moins intrusive dans le code existant, et qui m’épargne des lignes de configuration XML qu’on ne sait jamais comment écrire correctement (et auxquelles ont préfère une API fluente, qui permette à l’Intellisense de nous guider intuitivement dans l’usage des objets exposés).

StructureMap est l’un d’entre eux.

Nous avons écrit plus haut un contrôleur MVC doté d’un constructeur avec paramètre qui permet de faire passer une instance d’un objet de domaine.

Hors la fabrique de contrôleurs que Asp.Net MVC utilise en interne ne sait instancier les contrôleurs qu’en utilisant un constructeur sans paramètre. Il faut donc fournir une autre fabrique plus souple.

Heureusement que Scott et son équipe ont tout prévu, et que nous pouvons surcharger la fabrique de contrôleurs par défaut (DefaultControllerFactory) en préparent une autre comme ceci :

using System;

using System.Web.Mvc;

using StructureMap;

namespace yourProject

{

public class DependencyControllerFactory : DefaultControllerFactory

{

protected override IController GetControllerInstance(Type controllerType)

{

return ObjectFactory.GetInstance(controllerType) as Controller;

}

}

}

L’ObjectFactory permettra à StructureMap de résoudre les dépendances et trouver la bonne implémentation concrète de tous ce qui présente une interface remplaçable à la volée par un objet concret.

Ce nouveau Controllerfactory sera enregistré dans la logique Asp.Net MVC en ajoutant une petite ligne dans Global.asax.cs, dans Application_Start() plus précisément :

ControllerBuilder.Current.SetControllerFactory(new DependencyControllerFactory());


Et   juste ensuite (toujours dans Application_Start) nous préciserons à  StructureMap quel mapping opérer entre les interfaces et les implémentations concrètes, comme ici :

ObjectFactory.Initialize(registry => registry

.ForRequestedType<IDomainManagingPasswords>() .TheDefaultIsConcreteType<DomainManagingPasswords>());

Et voila!

C’est assez simple, notez juste que dans cet exemple, mon classe d’implémentation concrète DomainManagingPasswords disposerait d’un constructeur sans paramètre. Pour les cas plus complexes, lire la documentation ici : http://codebetter.com/blogs/jeremy.miller/archive/2008/08/20/smartinstance-in-structuremap-2-5.aspx

Il y a des frameworks IoC qui sont plus explicites encore, et qui vous laissent choisir quelle implémentation viendra s’injecter selon telle ou telle condition.

Cela peut être aussi en intéressant à utiliser si vous voulez par exemple, changer un fournisseur de données par un autre, à la volée dans votre programme.

http://www.iridescence.no/post/Inversion-of-Control-ASPNET-MVC-and-Unit-Testing.aspx

Mais y-a-t-il plus simple ?

Sortir les patterns qui vous font passer pour le roi de la programmation est parfois superflu.

Le crédo est d’être économe, de n’utiliser que ce dont on a besoin. Pourquoi lancer toute la machine d’un IoC, sinon à passer pour un érudit ?

Dans notre cas, nous avions simplement besoin de fournir à la factory par défaut de construction des Contrôleur Asp.Net MVC, un constructeur sans paramètre (tout en gardant celui avec paramètre qui sert aux tests).

Il suffisait d’écrire ce constructeur, et c’est lui qui se chargeait d’instancier l’objet de domaine concret répondant à l’interface IDomainManagingPasswords :

public ManageController()

{

_domainObject = new DomainManagingPasswords();

}

Un bien pour un mal. En faisant cela nous économisons toute la coûteuse introspection qu’opère un Injecteur de Dépendances, mais nous introduisons avant compilation du couplage très fort entre nos classes…

Retour au test, comment pousser le bouchon plus loin ?

Maintenant que nous savons comment faire pour préparer notre objet testé (le contrôleur) pour pouvoir fonctionner de manière identique dans un cas de test ou dans un cas de non-test, voyons comment spécifier le comportement des bouchons pendant le test.

C’est la que notre ami Moq refait surface, et nous permet de piloter le comportement de l’objet « bouchon ».

// create the mock

var mockRepository = new Mock<IDomainManagingPasswords>();

Je veux que lorsque la méthode X mon contrôleur fera appel à la méthode FindUserInAdam de l’objet de domaine qu’elle emploie, et quelque soit la valeur des paramètres, il me retourne une valeur de mon cru, rien de plus simple :

mockRepository.Setup(cr => cr.FindUserInAdam (It.IsAny<string>()))

.Returns(new resultOfSearchingUser

{

errorMessage = "test error",

codeResult = codeResult.NotFound

});

Ce qui se lit (donc se programme) aisément :

Permet de poster les choses.  La lambda expression permet d’exprimer ce qui se passera en cas d’appel à la méthode voulue. Les arguments sont gérés aussi par Moq. It est un objet pratique qui permet de dire « Ceci » est une valeur « peu importe » de type string : It.IsAny<string>().
Ou d’autres formules (une regex par exemple).
Lexpression qui s’en suit dit quoi faire quand la méthode sera réellement invoquée. Ici c’est un retour (Returns) d’une valeur assemblée de toute pièce pour les besoins du test (new resultOfSearchingUser).

N’oubliez pas que les Mocks sont des objets creux, ils répondent à une interface mais ne font rien. Donc à vous de programmer leur comportement.

On pourrait vouloir tester comment le contrôleur réagit si l’objet Bouchon de domaine renvoit une exception. Là aussi, c’est assez simple à exprimer :

mockRepository.Setup(cr => cr.FindUserInAdam (It.IsAny<string>()))

.Throws(new System.OverflowException("test error"));

Pour terminer, on n’oubliera pas de donner en carburant cet objet bouchon au contrôleur avant de lancer (ACT) l’opération à tester:

//bind the mocked object to the controller

var controler = new ManageController(mockRepository.Object);

///ACT

var results = controler.DoFindUser() as ViewResult;


A partir de là, vous avez toutes les billes en main pour tester tout ce que vous pouvez imaginer.
C’est d’ailleurs cette trop grand liberté qui peut être désarmante, et on cherche une méthode pour savoir quoi écrire comme cas de test. La réponse est 2 paragraphes plus loin.

Tester le Modèle

le "Modèle" en tant que structure de données que l'on passe du contrôleur à la vue ne se teste pas en lui-même. Par contre c'est le "fournisseur du modèle" c'est à dire l'objet que vous devez invoquer (et que nous avons substitué par un Mock) qui doit être testé pour lui-même.

A ce moment là c'est un projet de test autour des classes de domaine (classes métier pour ceux qui préfèrent ce terme) aux quelles il faut ajouter une batterie de Tests Unitaires "classiques" pour vérifier leur comportement.

Tout ce que je viens de dire sur les contrôleurs s’applique évidement aux classes de domaines. Elles doivent elles-aussi être fournie avec un jeu de test « en isolation complète ».

3 - Plaidoyer pour une approche Comportementaliste (BDD)

Si vous êtes en mal d’inspiration pour écrire vos tests, voici une idée qui pourra faire son chemin…

Le Behavior Driven Development (ou développement conduit par le comportement et donc les spécifications) devrait être LA façon de programmer universelle.

Affirmer aujourd'hui que la programmation d'un logiciel ne peut se faire qu'en fonction des spécifications passe pour une vérité des plus banales.

Or, jusque là, personne ne s'était occupé de rendre vérifiable, "prouvable" une telle démarche. Le développeur écrivait donc son programme, bon an, mal an. Et vérifiait une fois déployé (en général lors de la préparation de la recette ou de lors de la recette elle même) si le logiciel produit était bien conforme aux spécifications.

Entre écriture des spécifications (en majorité sous forme littéraire) et code (forme "machine", c'est à dire langage de développement) il y a un certain écart, pour ne pas dire un gouffre.

Ce que propose l'approche BDD c'est d'éliminer purement et simplement tout écart.

Et d'écrire les spécifications de manière formelle (donc dans une langue compréhensible par l'ordinateur) et reliée au langage du développement.

Ainsi un automate (un framework de tests unitaires est préposé à cela) peut relier la vérification des spécifications ainsi décrites au code réellement produit.

Le tout, de manière systématique, automatique, constante et répétée (dans le cadre d'une usine logicielle bien construite).

Ce ne sont pas les ressources qui manquent sur le net pour vous expliquer que faire du BDD c'est bon pour vous, essayez par exemple http://behaviour-driven.org/

Ou lisez Dan North, qui est celui qui a posé l'article fondateur : http://dannorth.net/introducing-bdd

Pour ma part, je vous proposerai bientôt un article entièrement consacré au sujet, autour d'une exemple concret bien entendu.

Le BDD est présenté par beaucoup d'éminent spécialiste comme l'aboutissement des méthodes SCRUM et XP

http://www.code-magazine.com/Article.aspx?quickid=0805061

Cette approche est également la plus fidèle à la notion d'Agilité, puisqu'elle permet d'exploiter à 100% les efforts faits en matière de spécification par UserStories et Scenarios.

Mais si elle est légion en Ruby et Python, si on la trouve beaucoup en Java, il faut dire que .Net est à la traine. Et c'est quelque peu frustrant voir même insultant (n'avons nous pas le droit de faire de meilleurs logiciels?)

Cela me rend plutôt inquiet, .Net est-il une plateforme laissée aux seuls Geeks et bricoleur de l'informatique? ou aux sociétés de service pressées de faire du chiffre et ne mettant pas vraiment l'accent sur la qualité logicielle?

Toujours est-il qu'il faut se lever tôt pour trouver un framework prêt à l'emploi, qui fonctionne (sic), et simple à prendre en main (re-sic) pour la plateforme .Net

Beaucoup de projets sont abandonnés en phase initiale (BDD Extensions project on Google Code.)

J'ai essayé de tester tout ce qui était compilable et seul NBehave semble tenir ses promesses; mais comme vous pouvez le voir dans cet article, l'écriture reste peu lisible hélas http://pebblesteps.com/post/Behavior-Driven-Development-with-NBehave.aspx

les BDD extensions de xUnit semblait offrir une forme plus sympathique à lire, mais bon.

Il y avait des initiatives très prometteuses comme  MisBehave, basé sur M et Oslo... mais là encore aucun engouement, ni de la part de la communauté ou des têtes pensantes chez Microsoft (d'ailleurs, que devient M à part un textual DSL pour de la modélisation de données).

Il faudra attendre que la communauté .Net se (re)mobilise et trouve enfin de l'intérêt à faire du BDD pour voir naître un framework nous donnant vraiment envie de faire du comportementalisme et que cette pratique n'apparaisse plus comme une perte de temps, alors que justement c'est le contraire qui devrait en résulter.

4 - D’autres exemples ?

Un projet complet TDD avec MVC plus NHibernate est à découvrir (avec des pages Wiki complètes) sur http://sharparchitecture.net/

Allez voir aussi sur http://scottfindlater.blogspot.com/2009/10/tdd-mvc-adventures.html

Enjoy!


 

pour les brèves, préférez Twitter

Janvier 21st, 2010

Lien: https://twitter.com/guillaume_agile

finalement, Tweeter s'avère parfait pour les reflexions instantannées, je vous invite donc à me suivre aussi là bas

https://twitter.com/guillaume_agile

 

et ici, toujours des articles de fond et/ou pratiques ; comme le prochain sur le Test avec Asp.Net MVC

de la réalisation à la production

Décembre 7th, 2009

je m'amuse souvent (et pas forcement innocement)  à faire le parralèle entre mon métier actuel de "faiseur de logiciel" et mon passé d'étudiant en cinéma et audio-visuel  (passé trop court, mais les contraintes matérielles de ce bas monde et quelques autres paramètres en ont décidé autrement).

Déjà, j'ai beaucoup de mal à répondre à la question "quel est ton métier?"... j'avoue que je déteste répondre "ingénieur informaticien" ou autres "ingénieur en développement informatique" car cela met une trop grande distance entre mon interlocuteur et moi.
Et puis le pauvre bougre n'en est pas moins renseigné sur la nature même de mon travail. J'obtiens au mieux l'étiquette de "Geek" au pire celle de l'ingénieur intello qui a fait de longues études, ou carrément la moquerie traditionnelle relayée par la fameuse video Youtube que je pense tout le monde connait ici (au cas où: http://www.youtube.com/watch?v=ZdEcyk5G80s ).
Et si la question qui s'en suit est: "tu travailles pour Microsoft?" alors j'ai vraiment tout faux.
C'est pour cela que je contourne un peu la question, et je change ma version....  "je fabrique du logiciel", et déjà cela attire un peu plus la curiosité de mon interlocuteur. "tu fais des sites Web " me demande-t-on parfois, et évidement cela me fait plaisir, car je peux me lancer dans l'explication qu'il n'y a plus de frontière entre logiciel et sites Web.
"fabriquer" est pourtant un terme vague et je lui préfère celui de "réaliser" qui me met en position de réalisateur. On comprend assez bien toute la portée du mot "réalisateur", qui parfois renvoie à "créateur".
Mais créateur a cette notion un peu supérieure de "création", qui pourrait faire paraitre quelque peu présomptueux, bien que j'aime assez souligner que nous faisons un métier qui n'est pas dépourvu de dimension "créative".
Réalisateur, c'est pourtant un terme qui fait de suite penser au monde du cinéma et de l'audiovisuel. Et je m'y retrouve assez bien finalement. Un réalisateur est amené à réaliser différents projets, du film de commande à l'oeuvre plus personnelle, du film publicitaire au long métrage blockbuster, en passant par le film d'entreprise... ou de mariage ;)
Un bon réalisateur de films est celui qui a appris tous les métiers intermédiaires: cadreur, monteur, preneur de son, mixeur, directeur d'acteur, constructeur de décors, inventeur d'effets spéciaux, scénariste. Il peut d'ailleurs sur certains projets cumuler certains (voir la totalité) de ces rôles.
Il est en de même pour le logiciel: codeur, testeur, analyste, architecte, documenteur (documentaliste?)...
Le réalisateur peut travailler seul sur des petits projets ou , et surtout, en équipe dès que le projet le demande.
Il devient donc un pilote d'hommes. Le terme chef de projet n'est pourtant pas très communément admis dans le monde audiovisuel (en France du moins).
D'ailleurs ce rôle ressemblerait plus à celui du producteur: l'homme qui orchestre le projet de film, qui met les hommes aux services des hommes et du projet.
Et qui assume tout ou partie de la responsabilité financière aussi.
Mais vous aurez tous remarqué que dans toute production audiovisuelle (cinema et tv), il n'y a jamais un seul producteur. Il se fait entourer d'une palanquée de producteurs exécutifs, associés, délégues, généraux, sous producteurs, etc... Ce sont des équipes entières de production qui s'occupent d'un projet.
Là dessus, nous, pauvres faiseurs de logiciels, avons peut être quelques leçons à prendre...
Intéressant de voir divers points de vue sur le métier de producteur: http://www.youtube.com/watch?v=r2v2dht1teI
très étonnant comment le dernier lien va parler à tous ceux qui se sont frottés au rôle de chef de projet informatique, mais cela va vraiment au delà (et c'est surement plus intéressant en cela)
Et il apparait qu'une bonne traduction du stakeholder des méthodes agiles, serait le producteur.
Le Producteur représente le Produit (même racine), et derrière le produit viennent ceux qui vont l'utiliser. Le producteur comme ambassadeur à la fois d'un besoin exprimé mais aussi d'une émergence, d'envies implicites, de besoins sous-jacents. Il va jauger du marché, des attentes, des potentialités.
Idéalement son rôle ne s'arrêterait pas à la sortie du produit mais va aussi essayer ensuite de vendre le produit et de le faire se diffuser, d'aider ceux qui vont l'utiliser à vraiment le posséder, à s'investir dans le logiciel livré (accompagnement au changement).
Bref un rôle d'accompagnement indispensable et qui ne peut retomber sur les épaules d'une seule personne mais sur une équipe.
Et un tandem: le réalisateur et le producteur devraient être les 2 piliers d'un projet logiciel comme ils le sont depuis de nombreuses décennies dans le monde audio-visuel, qui possède lui aussi cette dualité "industrie-artisanat";
2 monde professionnels qui se rejoignent sur bien des points...

 

parlons du futur un peu....

Novembre 20th, 2009

Comme ils nous cassent tous les oreilles avec ChromeOS (ok, j'aime Android et j'assume), n’oublions pas que MS va aller beaucoup plus loin qu’un simple Linux revampé et des WebApps (même si c’est l’avenir) tournant sur un omni-navigateur (Chrome+Gears)

 

Un article de référence pour soutenir mes propos:

http://www.sdtimes.com/MICROSOFT_S_PLANS_FOR_POST_WINDOWS_OS_REVEALED/About_CLOUDCOMPUTING_and_MOBILEDEVELOPMENT_and_NET_and_SOASAAS_and_SOFTWAREDEVELOPMENT_and_WINDOWS_and_MICROSOFT/32627

Peut être vous saviez déjà que ca s’appelle Midori, mais le modèle de programmation va changer :

 

The Midori programming model will tackle state management, which Microsoft admits in its documentation is a challenge in Windows, by migrating APIs, applications and developers to a constrained model.

Là où ca devient palpitant (pour les développeurs):

Other objectives are eliminating dynamic loading and in-process extensions; developing a failure model based on reliable transactions, so the system understands exactly which processes are impacted by a cascading failure and how to restart the computation; and having a standard way of dealing with latency, asynchronous behavior and cancellation, throughout the stack.

Un OS intelligent qui se protégé tout seul des plantages et qui arrête de faire confiance aux programmes qu’il execute ? comme par hasard, c’est aussi l’idée de Google dans ChromeOS

 

Mais, plus de protection, et donc plus de contrôle = moins de souplesse

restricting dynamism at the OS level will not impact dynamism at the programming level.”
ouf, on est sauvés!

 

Et OSLO pourrait revennir sur le devant de la scène :)

 

In a possible link to Microsoft’s Oslo composite application initiative, the programming model will have a dependence on metadata, with the aim of allowing the system to more reliably manage applications.


the proposed OS would have a non-blocking object-oriented framework API. This would have strong notions of immutability—in the sense of objects that cannot be modified once created—and strive to foster application correctness through deep verifiability by using .NET programming languages.

Un OS orienté objet et transactions? On en rêvait….

Mais la concurrence est là:

“A lot of these problems are being solved, at least partially, by the ideas of store-and-forward and message synchronization,” Hammond noted. “Google Gears, Adobe AIR, even the mobile OSes with things like SMS can handle occasional connectivity. Why shouldn’t this be built into core OS communication protocols, especially if they are asynchronous by default?” he asked.

Qui sera le vainqueur des OS de demain ? non pas de savoir quel éditeur car il s’agit d’une guerre commerciale… mais quelle technique ?

Y-a-t-il un futur pour la recherche sur les OS tels que nous les connaissons aujourd’hui, et donc pour les suites de Windows… (ou MacOs)

Ou bien l’OS va-t-il devenir le grand perdant de cette bataille, et toutes les nouveautés ne seront-elles pas reportées sur les omni-navigateurs (ou plateforme applicatives virtualisées comme pourra le devenir Air ou même Eclipse), sur les interpréteurs et sur les petits moteurs de synchronisations comme Gears. Mais qui laisseront l’OS à une place dérisoire, et qui n’intéressera plus aucun développeur…

A lire : Une très intéressante présentation des principes de Singularity (mais vieille de 2006 !) :

http://research.microsoft.com/en-us/um/redmond/events/fs2006/presentations/23_Hunt_071706.ppt

http://research.microsoft.com/en-us/projects/singularity/

 

la guerre continue: http://blogs.zdnet.com/microsoft/?p=4650&utm_source=feedburner&utm_medium=feed&utm_campaign=Feed:+zdnet/microsoft+(ZDNet+All+About+Microsoft)&utm_content=Google+Reader

mais Microsoft fait toujours office de suiveur... dommage

 

Agile Development From A Developers Perspective

October 14th, 2009

je ne saurais trop vous recommander de jouer cette brillante (et agile) présentation, pour vous développeurs, pour un chef de projet, pour un architecte...

Tout est excellement condensé. Le MUST de l'application des bonnes pratiques de conduite d'un projet de développement logiciel, et de méthode de réalisation (TDD, intégration continue, code quality metrics,  acceptance tests, etc...)

http://www.slideshare.net/rbanks54/agile-development-from-a-developers-perspective

 

faites le savoir!

Agile Tour 2009: c'est parti! ... et aussi à Toulouse

October 8th, 2009

pour tous ceux impliqués de près ou de loin dans l'adoption de démarches Agiles, et surtout pour ceux qui se demandent quel est cet oiseau bizarre, et qui voudraient bien en savoir plus, il n'y a qu'un rendez vous:

c'est l'Agile Tour 2009 partout en France!

et en particulier à Toulouse où pas moins de 20 sessions vous attendent:  retours d'expériences, conférences, ateliers, présentation d'outils, débats!

les échanges seront riches et nombreux.

Une journée que vous ne serez pas près d'oublier ...

le programme et les inscriptions Toulousaines se font ici: http://www.agiletour.org/fr/at2009_toulouse_programmation.html

http://www.agiletour.org/fr/at2009_toulouse_inscription.html

affichage agile tour toulouse

appels aux orateurs

September 4th, 2009

l'Agile Tour 2009 se dessine et nous recherchons des orateurs sur le sujet

Je fait partie de l'équipe d'organisation de Toulouse et c'est aux sudistes que je m'adresse en particulier.

L'édition de cette année est orientée sur les retours d'expériences, n'hésitez donc pas à venir partager les votres!

Tous les détails pour s'inscrire (en orateur ou auditeur) sur le site http://www.agiletour.org/

Ou si vous cherchez à mettre au point un sujet à plusieurs, n'hésitez pas à me contacter.

 

Bonne rentrée agile à tous.

les conseils beauté de vos présentations (slides, keynotes, prez)

Août 21st, 2009

Pour finir vos devoirs de vacances, je vous propose des petits idées pour améliorer les présentations PPT que vous êtes parfois amenés à faire.

Les règles d’une présentation PPT réussie :

Le texte à l’écran ne doit JAMAIS être le texte récité par le présentateur.
Le slide est un support à la narration, il doit présenter des éléments visuels qui NE SONT LA QUE POUR soutenir ce que dit le présentateur.
Il ne faut pas endormir l’auditoire.
DONC
• Des textes très courts et écrits gros
• Des belles images qui marquent ! (ne pas hésiter à aller sur Flickr pour prendre des jolis clichés, ils sont souvent en Creative Common Licence, par ex http://www.flickr.com/photos/lucas3d/3794517546/ )
• Il vaut mieux 100 slides avec 3 mots dans chaque, que 3 slides avec 100 mots.
• Utiliser une charte graphique
• Utiliser un police agréable à lire en gros
• Utiliser HABILEMENT les couleurs pour mettre en évidence un mot en particulier dans une slide, tout en gardant une charte de couleurs cohérente et sobre
• Une SEULE phrase et un SEUL concept par slide
• Un concept compliqué s’explique sur PLUSIEURS slides
• Pas d’animation dans les slides
• Si vous voulez faire apparaitre ou disparaitre des éléments, dupliquez le slide autant de fois que nécessaire pour faire l’effet
• Votre présentation doit faire entre 60 et 100 slides, en passant au max 10 à 20 secondes par slide

Une excellente prez sur le TDD
http://www.slideshare.net/bencarey/beyond-tdd

ma préférée (graphiquement) sur les CSS
http://www.slideshare.net/stubbornella/object-oriented-css

une très bonne sur l’agilité
http://www.slideshare.net/eig/agile-software-development

plus de texte, mais quand meme des bonnes idées gfx
http://www.slideshare.net/jurgenappelo/what-else-can-agile-learn-from-complexity
un rapide tour de méthodes agiles avec des images qui parlent
http://www.slideshare.net/Siddhi/introduction-to-agile-methods

le bout du tunnel?

Juin 11th, 2009

enfin, on sort des ténèbres... après presque 10 ans de règne sans partager sur l'accès aux données depuis la création du Framework .Net, les DataSets rendent les armes.

C'est une vision personnelle, mais je ne peux me rappeler que mes soirées de debuggage intenses avec les DataSet... absence de typage, requêtes SQL construites sur des concaténations de chaînes de caractère... en tout cas au début, on était obligé de commencer comme ca.

Même s'ils ont mûri, les DataSets sont synonymes de lignes et lignes de codes de plomberie techniques, lourdes, fastidieuses, inutiles... et à mon sens une vision tordue de l'accès aux données.
Tout cela m'avait vite poussé à regarder NHibernate et ses confrères. Vive le Mapping Objet Relationnel!

Pour moi Linq et surtout Ado.Net Entity Framework allait enterrer définitivement les odieux DataSets... il n'en a rien été.

Et cette nouvelle m'apparaît comme une sortie du tunnel: "here are no plans to add DataSet into future releases of Silverlight"
Un signe? Un espoir?
Une promesse d'une aube nouvelle???? ;)

Si une technologie qui a le vent en poupe ne soutient plus cet ancêtre, peut être est-ce l'annonce du début de la fin?
Allez, il faut croire au progrès.

http://blogs.msdn.com/adonet/archive/2009/05/26/dataset-and-silverlight.aspx
http://www.sheysrebellion.net/blog/2008/07/31/datasets-are-evil/
http://jelle.druyts.net/PermaLink.aspx?guid=61676665-06a7-443a-9462-71dae713539e (DataSets Are Not Evil)

une excellent présentation des méthodes agiles

Juin 4th, 2009

http://www.slideshare.net/mcottmeyer/adopting-agile-1521562

exactement le genre de présentation que je fais
rapide, concis, une idée par slide, des idées claires & simples
des diapositives compréhensibles par tous et d'elles-même!

a MUST HAVE and a MUST FOLLOW

Une journée extra-ordinaire

Janvier 29th, 2009

Pour changer de .Net, un petit billet d'humeur sur... le travail.

Voila donc cette grande journée de grève avec une paralysie quasi-totale annoncée.
Et qu'est ce que je remarque ce matin au boulot: 2 fois moins de mes collègues sont venus travailler, les autres sont restés travailler chez eux.
C'est un des avantages à bosser dans les domaines de l'IT ou du service. Nous n'avons pas *vraiment* besoin de nous déplacer sur notre lieux de travail tous les jours, dans l'absolu.

Résultat de cette journée: l'ambiance était particulièrement décontractée voire joviale. Travaillant dans un OpenSpace, voila que -tout d'un coup- une quiétude et un calme nécessaire à la concentration régnaient autour de nous. Le travail allait en être plus efficace.

Les gens étant restés, pour bon nombre, chez eux, la circulation fut plus fluide que d'habitude (source Europe 1) et la qualité de l'air était bonne ( http://www.airparif.asso.fr ).
L'analyse de la courbe de cumul de bouchon en IdF fait ressortir une étrangeté ( http://www.sytadin.fr/ ): l'intensité des bouchons était exactement égale à la courbe des moyennes (donc aucun effet de sur-bouchon) mais elle était décalée dans le temps; c'est à dire que les bouchons se sont produits beaucoup plus tôt dans la matinée puis résorbés, pour avoir retrouvé à 9h30 une valeur quasi nulle... du jamais vu pour Paris et sa banlieue!

75% des métros ont fonctionné mais comme il y avait beaucoup moins de monde, les voyageurs étaient détendus.

Et de réfléchir, en ces temps de crise, à la nécessité de repenser nos modes de travail. Avons nous besoin de dépenser autant de CO2 pour transporter autant de monde à des distances parfois incroyables (plus de 3h de transport par journée pour certains). Et tous en même temps (ne pouvons nous pas imaginer des horaires mieux adaptés?).

Selon le WWF, 50% des émissions de CO2 des entreprises sont liées aux déplacements professionnels : voyages d’affaires, trajets domicile-bureau, etc. L’ONG vient donc de lancer le challenge One in five pour pousser les entreprises à réduire leurs déplacements professionnels de 20% d’ici 5 ans. (source: http://www.greenit.fr/article/acteurs/50-des-emissions-de-co2-liees-aux-voyages-daffaires )

En bon provincial (et Occitan de surcroît) je suis convaincu qu'il y a trop de monde en Ile de France, et que concentrer 1/5eme de la population sur 1,7% de la surface du territoire est une aberration environnementale (et idéologique).

Les instances territoriales font toutes les études qui démontrent que les trajets domicile-travail coûtent trop cher en CO2 ( http://www.hauts-de-seine.equipement.gouv.fr/IMG/pdf/p6_pda_covoiturage_vf_cle636a11.pdf ).
Le gouvernement et la CEE s'y mettent aussi ( http://www.bougezautrement.gouv.fr/ ).

Je saluerai donc toutes les initiatives qui vont dans le sens du télétravail et de la dématérialisation, tel que http://www.cyberworkers.com/
et de suivre les actualités de sites "IT durable" tels que http://www.greenit.fr/

Il est temps de vivre au 21e siècle et de laisser loin derrière nous la révolution industrielle. L'ère a changé!

la Modélisation Métier est elle soluble dans le CRUD (et inversement)?

Janvier 28th, 2009

http://docs.google.com/Doc?id=dhp3ggmx_115g524prcq

je vais lever une veille taupe, peut être un débat sans fin, mais il me parait important d'essayer de remettre les cartes sur table.

Plus les années avancent, et plus je me questionne sur où vont les technologies et les éditeurs ou les projets Open Source?

Et je me demande si on ne frôle parfois pas la schizophrénie...
Par exemple chez Microsoft, on nous dit : "CRUD, Only When You Can Afford It" ( http://msdn.microsoft.com/en-us/library/ms978509.aspx )
et après on met en avant ASP.NET Dynamic Data, qui permet de faire des applications 100% orientées CRUD.

Au début était l'informatique, les carte perforées, puis les disques durs. Et tout cela stockait des données, des données, des données.
Puis vint Merise en grand éclaireur de la pensée informatique industrielle (pendant que les scientifiques n'en avaient cure, et persistait dans une voie fonctionnelle).

Ce que faisaient alors les logiciels se résumait en 4 verbes: Créer, Lire, Modifier, Effacer des données (Create Read Update Delete, CRUD en anglais).

Et après de nombreux logiciels produits sur ce modèle, on s'est rendu compte que:
1) cela ne faisait que produire des logiciels d'informaticiens, c'est à dire pas du tout "User Friendly";
2) la complexité de la réalité dépasse le stade de ces 4 opérations basiques.

On a commencé à réfléchir du point de vue de l'utilisateur. On s'est aperçu qu'il avait un besoin de logiciel dans le but de l'assister dans l'exécution de son métier (et accessoirement que l'utilisateur était livré avec des yeux).

On a donc sorti une artillerie lourde pour décrire - MODELISER - les processus métier, issus du besoin réel de l'utilisateur, représentés bien souvent par des Scénarios Utilisateurs (merci UML).

Des paradigmes tels que le "Model Driven Design" ou le "Domain Driven Design" sont venus consolider cette nouvelle façon de faire du logiciel.

Pourtant le CRUD n'avait pas pour autant disparu...

On a l'habitude de dire qu'il ne faut pas exposer les données directement au dessus d'une couche métier, tels que ce que l'on peut trouver exposé par un Web Service, et pourtant nombre d'applications le font.
et Microsoft qui va droit dedans avec SdS et ASP.NET Dynamic Data.

"Data-driven application" redevient un mot que l'on peut prononcer sans honte.

Microsoft n'est pas le seul, avec la lame de fond qu'est REST, tout est orienté ressource, donc données, et les opérations permises sont encore au nombre de... 4!
Question légitime: comment exprimer du métier avec ce genre d'outils?

Comment faire dans cet incessant aller-retour entre une paroisse et une autre? Est-ce un éternel recommencement? (et piétinement?)

la suite sur http://docs.google.com/Doc?id=dhp3ggmx_115g524prcq

la Recette du Gâteau Logiciel selon Microsoft

Janvier 15th, 2009

article intégral sur http://docs.google.com/Doc?id=dhp3ggmx_113fv4x6tr7

the Microsoft's Application Architecture Guide 2.0
ou la Recette du Gâteau Logiciel selon Microsoft
commentée par votre serviteur

l'équipe P&P (Practices & Patterns) de Microsoft vient de sortir un bouquin en ligne (donc gratuit) à l'usage des architectes logiciels que je vous recommande chaudement: http://www.codeplex.com/AppArchGuide

Même si de larges pans de ce livre sont exclusivement tournés vers les technologies développées par MS, il y a de très bons passage très généralistes et utile au travail de n'importe quel architecte.
Je me propose de vous livrer et condenser ici 380 pages de précieux conseils.

A la lecture de cet ouvrage, il m'a semblé toujours judicieux de rappeler ce qui sont pour moi les fondements de l'art et la technique du développement logiciel en 2009:

Principes Clefs
(ou Grands Principes Métaphysiques, Tablettes de la Loi, Trucs de Grand Chef... comme vous voudrez)

on pourrait les voir comme une espèce de 6 commandements bibliques, quelque chose à inscrire dans les gènes de toute personne qui veut se lancer dans le développement d'un programme, qu'il s'agisse d'une application industrielle destinée à des milliers de personnes ou d'un programme pour machine à calculer, en passant par une RIA Web2.0 très à la mode.

• Divisez en plus petites unités fonctionnelles (Separate the areas of concern / SOC).
Diviser votre application en "features" ou "lots fonctionnels" de telle sorte que les fonctionnalités se recouvrent le moins possible (voire pas du tout).
Chaque "feature" (fonction) sera ainsi optimisée de manière indépendante des autres.
De même si une fonction ne rempli par complètement son rôle, ou bien si sa livraison est en echec, les autres fonctions en seront moins impactées.

Cette approche vous garanti que votre projet logiciel est facile à COMPRENDRE, puis à modéliser et à gérer durant tout son cycle de vie (et surtout sur les phases de maintenance et évolution)

Pour résumer: diviser, simplifier, découper. Discrétiser comme dirait mon prof de maths.
Prendre un problème complexe et le sub-diviser jusqu'à obtenir une somme de petits problèmes, chacun séparément étant évidement plus simples à résoudre que l'ensemble.

• Un composant/objet = Une responsabilité (et vice-versa).

Sachant qu'une responsabilité est soit technique, soit liée à une fonctionnalité (feature) décrite dans une spec (dans un monde idéal).
Les composants deviennent alors plus clair.
Bien sûr la notion même de ré-utilisabilité vient parfois rendre opaque une telle lecture. Car dès lors qu'un composant devient générique, son rôle peut s'opacifier. Il convient alors de bien prendre garde justement à ne pas aller vers une modélisation trop abstraite au risque de perdre ses collègues (et soi même) dans des méandres de réflexion trop personnelle. Toujours garder en tête l'utilisateur (ou l'utilisation) de la chose programmée.

"Un grand pouvoir implique de grandes responsabilités" lisait-on dans le comics Spider Man. C'est aussi vrai dans la fabrication d'un logiciel qui n'est pas une affaire à prendre à la légère.
Toute ligne de code à des effets. Et surtout l'effet de produire potentiellement un bug.
En limitant la responsabilité d'un module logiciel (j'appelle ici "module": une unité, une partie identifiable, interprétable, compilable ou encore une ressource) vous limiterez les sources d'erreurs.
Mais plus encore, il vous sera aisé de maintenir une "cartographie" de votre construction logicielle, c'est à dire savoir qu'est ce qui est responsable de quoi.

• Principe des boites noires (ou de moindre connaissance)
connu en Anglais sous les termes de: Principle of least knowledge. A component or an object should not know about internal
details of other components or objects. Also known as the Law of Demeter (LoD).

Chaque objet/composant/service est comme une boite noire (ou blanche). Il ne doit rien laisser transparaître de son fonctionnement interne.

Cette position est intéressante du point de vue extérieur à l'objet (ou au composant): un minimum de connaissance (voir aucune dans l'idéal) devrait être requis pour faire fonctionner un objet (ou le ré-utiliser).
En clair: celui-ci doit être tellement simple (et pas simpliste) à utiliser, tellement ER-GO-NO-MI-QUE, que il n'y a (presque) pas besoin de mode d'emploi.
Son usage doit tomber sous le sens.
Il doit être programmé en pensant à ceux qui vont s'en servir pour que toute manipulation en soit dramatiquement aisée.
S'il ne répond pas à ce critère, vous pouvez alors purement supprimer le composant en question.

* Ne ré-inventez pas la roue (ou tout autre chose) et ne vous répétez pas

en Anglais ça donne:
Don’t Repeat Yourself (DRY). Do not duplicate functionality within an application.

Dans le cadre de la séparation des responsabilité, il ne doit pas y avoir 2 objets/composants/services qui aient la même responsabilité.
En clair, veillez à ce que jamais une fonctionnalité ne soit dupliquée quelque part dans votre édifice final (ou solution ou même votre ensemble urbanisé d'informatique d'entreprise).

Ceci est un exercice délicat. Sans parler des problèmes complexes qui se posent dès que l'on veut partager des fonctionnalités avec d'autres équipes ou d'autres systèmes (problème de représentation, de vision, d'échange et de politiques - et ces politiques ne s'arrêtent pas à des histoires de sécurité mais revêtent bien des fois des apparences de politique civile - voir guerrière dans certaines organisation ... bref!).

Un exercice délicat, disais-je, ne serait-ce que tenter de l'appliquer à soi-même.

Il est difficile de donner un recette pour être sûr que ce précepte soit constamment appliqué.
Mais j'ai appris récemment une bonne approche: supprimer du code.
Oui, oui, vous avez bien lu. L'idée est de considérer que toute ligne de code écrite est mauvaise.
Elle l'est par définition, car derrière une ligne se cache un bug.
Ensuite, relisez (ou faites relire) votre code en vous disant "est-ce que cette fonction (ou feature) n'existe pas déjà ailleurs"?

Pour arriver à faire une telle lecture de votre solution logicielle (code ou intégration de composants/service), il est indispensable d'en posseder une cartographie particulièrement claire et bien documentée.

Dans les effets positifs, on sait bien qu'une telle mesure rend les changements plus simples à gérer ainsi que la maintenance corrective de l'application ou la solution.

* Ne passez pas votre vie à faire du Design / Modélisation

"Avoid doing all your design upfront (BDUF). "

Modéliser c'est bien. Agir c'est mieux. Mais difficile de trouver le juste équilibre. On ne va pas non plus revenir au RAD des années 80.
Combinez les approches. MDA ? le Modèle avant tout? TDD? les tests et rien que les tests?
Peut être un peu de tout ça.
En tout cas, ne vous laissez pas bloquer.
Un Design genre "Draft" (brouillon) ou "squetch" (exquisse) peut parfois être suffisant dans nombre de projets.
Si les spécifications sont peu claires ou très glissantes, alors partez sur du code dirigé par les tests.
Mais n'oubliez pas de tenir un modèle à jour pour avoir une bonne cartographie du projet.

Les modèles évoluent, et parfois aussi vite que le code. L'art est de garder le tout synchronisé!

(Re)Mettez-en des couches!

Différence entre un Tiers et une Couche (Tiers/Layer)
Une couche est un regroupement logique de "composants" logiciels.
Une bonne analogie est le modèle en couche OSI que j'ai déjà mentionné dans les colonnes.
La séparation de communication entre N et N+1 est complètement vérifiée (ou doit l'être).

La suite de l'article intégral sur http://docs.google.com/Doc?id=dhp3ggmx_113fv4x6tr7

le jour où les développeurs disparurent

Décembre 11th, 2008

j'ai vu ce jour arriver, grâce à cette vidéo:
http://wm.microsoft.com/ms/msdn/oslo/mwindowexample.wmv

Bien sur, ce que vous voyez n'est qu'une petite démo ultra-triviale et mon titre est un petit effet de manche.

Le génération de code à partir de spécifications ce n'est pas nouveau. CAML fait cela depuis longtemps.
Mais ça se rapproche. Ça se démocratise.

On est bien loin des langages B ou Z (cauchemar de mes dernières années de fac). Avec 'M' (justement appelé ainsi en références aux "vieux" langages formels) on arrive à un niveau de manipulation bien plus sympathique pour créer son propre générateur de langage.

Ecrire sa propre grammaire devient plus abordable. Cette video le démontre.
Nous voyons un "ex-développeur" écrire un programme juste en déclarant les spécifications du résultat attendu.

Il dicte en anglais la description du résultat qui est attendu. En français on pourrait faire la même chose avec une grammaire du style: "Donne moi une fenêtre qui soit avec un fond rouge, qui contienne un bloc de texte appelé BT. BT contient le texte 'salut les gars!' avec une couleur verte." (bon, d'accord, le français est une sale langue pour nous informaticiens, avec toutes ses règles d'accords, de conjugaison et surtout l'ambiguïté introduite par les relatives)

Voila qui stigmatise bien le futur du processus de développement de logiciels.
A mon humble avis, dans 5 à 10 ans, nous n'aurons plus à écrire une ligne de code.

Cela tiendra à plusieurs facteurs:

1) l'enrichissement des Framework de développement:
quelque soit la plateforme choisie (.Net ou J2EE), ce n'est que lorsque les API seront suffisament riche, que le niveau d'abstraction présenté sera suffisant pour brancher un outil de génération de code.
On a presque atteint ce stade. La video montre que WPF par exemple est assez haut niveau pour pouvoir être ciblé directement par un modèle qui peut sembler assez naturel. Il faudrait tout de même critiquer le fait que cette syntaxe reste assez lourde et figée et donc qui s'éloigne d'une grammaire context-sensitive (donc moins "permissive" que le langage naturel mais du coup qui élimine tout risque d'ambiguïté)

2) le Framework "programmatoriel" (+) ne pourra pas tout faire, car il est par nature orienté sur du non-fonctionnel, et sur des opérations somme-toute "techniques". Aidé par des annexes qui règlent des problématiques particulières telles que l'accès aux données, le monitoring, la gestion des défauts, la programmation concurrente, et tout autre sujet à la mode, ces Frameworks font beaucoup , vraiment beaucoup mais ne savent pas traiter les cas métiers.

3) A ce moment là, il faudra établir des frameworks métiers très bien pensés pour être à leur tour la cible de spécifications fonctionnelles écrite en M (ou en Z pour les récalcitrants). La stabilisation de ces frameworks sera longue et douloureuse.
D'abord parce que chaque métier à sa façon de faire, d'écrire des procédures (si tant est il a pu arriver à un niveau de maturité qui permet de les coucher sur papier sans ambiguïté, ce qui n'est pas gagné);
Ensuite parce que chaque entreprise est tentée d'écrire le sien (selon sa propre vision de son métier) et que pour un même métier on aura des centaines ou des milliers de frameworks différents. Problèmes de normalisation (on a l'habitude) en vue!

4) et dernier obstacle: le langage "sur-fonctionnel" lui-même (c'est à dire le langage source computé par M)
il faudra plus que des grammaires formelles pour arriver à exprimer librement le comportement d'un logiciel et pondre en quelques ordres vocaux une suite logicielle complète.

Pourtant le travail du développeur ne cesse d'évoluer. Moins technique, plus formel.

M va nous faire progresser dans ce sens, car il rend juste ce vieux rêve (celui de Turing) plus "proche".

Des blocs entier de lignes de code pourront être générées par simple description, mais pas l'intégralité du logiciel.
Mais la notion de ré-utilisabilité et de frameworks métiers va devenir toujours plus pressante.

La qualité du design sera fondamentale puisque les logiciels seront fabriqués réellement à partir du modèle. Mais l'on ne peut se soustraire aux obligations de qualité et de fiabilité.
L'on doit donc se poser la question de la testabilité des modèles.
Et de s'assurer que les briques sous-jacentes et invoquées par nos générateurs de code depuis le modèle sont également exemptes de tout défauts... faute de quoi, on aura fait que déplacer les problèmes.

(+) ne me demandez pas d'où je le sors celui là, c'est venu comme ca.

Éléments de réflexion pour une architecture SaaS distribuée

Septembre 30th, 2008

Introduction

Pour une solution logicielle basée sur une interface Web, les Défis technologiques à venir sont majeurs.

Le modèle économique naturel d’une telle solution est l’application louée.

C’est aujourd’hui sur le marché une grande tendance, affublée de différents acronymes ;

SaaS (Software As A Service), Application OnDemand, S+S (Software Plus Services), etc…

Les applications louées sont un excellent modèle financier mais requiert de grandes capacités techniques :

disponibilité, monté en charge, configurabilité, résilience, surveillabilité …

L’idée est de penser comment relever ces défis en intégrant ces problématiques au cœur du logiciel, c'est-à-dire dans le code.

Cas fréquemment rencontrés

Beaucoup s’imaginent que faire du SaaS c’est mettre un serveur Web à disposition de chaque locataire de l’application, ou plutôt une instance de Serveur Web . Dans IIS la chose est simple à réaliser. Créer un site virtuel pour chaque applicatif et faites pointer sur un répertoire différent (ou mutualisez la partie BIN pour avoir le même code exécuté partout).

Changez la ConnectionString et voila une nouvelle application prête à accueillir un locataire de plus.

Ce genre d’architecture physique (de déploiement) n’est pas sans poser de problèmes. Regardons comment ca marche dans IIS :

image sur le document: http://docs.google.com/Doc?id=dhp3ggmx_98f642cnvj

Chaque site Web de client à son processus dédié et donc un espace mémoire isolé ( x Mo de footprint par site Web).

Viennent ensuite les serveurs Back qui font tourner SQL Server.

Problèmes posés

Cette architecture présente l’inconvénient d’un certain monolithisme. Certes la base de données est dé-corrélée des autres traitements. Mais justement tous les traitements autres que Base de Données sont massivement imposés au serveur IIS qui doit tout faire dans un espace mémoire qui devient vite saturé.

Pour augmenter la capacité d’accueil de l’application, il n’y a guère d’autres moyens que d’ajouter des serveurs Web avec IIS et/ou de la RAM pour monter en capacité charge (interventions physiques ou sur machines virtuelles).

Il est impossible d’effectuer de la répartition de charge logique entre les différents briques applicatives inter-clients. On ne peut répartir la charge que par client (locataire) de la plateforme.

C’est sans parler des problèmes de mise à jour de la partie applicative (code) sur chaque serveur applicatif. On peut aussi avoir besoin de centraliser certaines parties.

Pourquoi y répondre ?

* Pour offrir plus de souplesse

* Pour simplifier l’exploitation

* Pour augmenter la capacité d’accueil

* Pour encaisser les pics de charge

* Pour s’aligner sur un modèle de programmation issu des meilleurs pratiques

* Pour exploiter enfin les capacités du framework .Net et de IIS

Pistes de réflexion

L’idée directrice est de tirer parti de la puissance que le Framework .Net peut apporter.

Avec ses évolutions, et notamment la version 3.5, .Net s’est doté de WCF, l’implémentation concrète d’un nouveau paradigme de programmation orienté services (SOA).

Avec WCF, on programme des services encore plus simplement qu’on programmait des composants avant (je pense à COM/COM+/DCOM).

Ce qui est important de garder en mémoire ici, c’est qu’ à partir du moment où on a des composants qui s’exposent en services WCF, toute la partie déploiement est complètement découplée et donc re-paramétrable à souhait.

On peut choisir librement les scénarios de transport, protocole, sécurité, fiabilité que l’on souhaite sans redévelopper une seule ligne de code.

Les applicatifs Web programmés en .Net fonctionnent avec ce que Microsoft appelle maintenant son « serveur applicatif », c'est-à-dire IIS.

S’il est présenté comme un vrai serveur applicatif, pourquoi n’en offre-t-il pas toutes les fonctionnalités ? Car si on s’en tient à la console de gestion IIS on peut rester sur sa faim…

La réponse à cette question est : Utilisez WAS !

la suite est ici: http://docs.google.com/Doc?id=dhp3ggmx_98f642cnvj