BodySplash.fr

Aller au contenu | Aller au menu | Aller à la recherche

Tag - test driven development

Fil des billets - Fil des commentaires

mercredi 9 juin 2010

Le secret de la productivité

Je vais peut être enfoncer une porte ouverte pour certains, mais j'ai envi de parler du secret si bien gardé par les grands professionnels pour être productif avec un IDE : les raccourcis clavier! Oui, c'est ironique, mais l'année dernière lors de la session TDD, et plus récemment suite à d'autres retours, j'ai été assez étonné des remarques du genre "ah je ne savais pas qu'on pouvait faire tout ça avec Eclipse". Un des intérêts premiers d'un IDE est tout de même de nous aider à faire les tâches de base du développement :

  • autocomplétion
  • refactoring
  • exécution des tests
  • navigation facile dans les sources
  • assistance contextuelle

Oui, je ne met pas sciemment tout ce qui est éditeurs WYSISYG, car leur utilité est finalement assez anecdotique et bien souvent alourdissent les IDE pour rien tout en étant pas si productif que ça. Ils sont d'ailleurs peut être la cause majeure qui fait que pas mal de gens n'aiment pas les IDE. Ceci dit étant dit, même si la plupart des fonctionnalités citées plus haut sont accessibles par la souris, leur usage ne devient systématique et efficace à mon avis que si on les associe à des raccourcis claviers.

Prenons un petit cas d'exemple. Imaginons que j'ai écrit un test ressemblant à ça (désolé, je ne me suis toujours pas motivé pour mettre en place une coloration syntaxique sur ce blog):

@test
public void peutRécupérerNomComplet() {
    Client client = new Client();

    assertThat(client.nomComplet(), is("prenom nom");
}

au plus simple, le code pour faire passer ce test est le suivant :


public String nomComplet() {
   return "prenom nom";
}

Cette méthode est un appel au refactoring, car il y a duplication entre la méthode de test et la méthode de production (la constante est répétée). Je vais peut être vite en besogne, mais nous devons alors faire apparaître du coup le nom et le prénom. Pour éviter d'être verbeux plus longtemps, voici une petite vidéo pour montrer comment je m'y prend en m'appuyant sur les capacités d'Eclipse:

(Si jamais la vidéo ne s'affiche pas, vous pouvez toujours allez directement ici)

Il y a bien sûr plusieurs chemins pour arriver au même résultat, mais j'espère que si vous n'utilisez pas souvent les raccourcis clavier, les refactorings ou les aides à la génération alors cette vidéo vous aura convaincu d'essayer de vous y mettre un peu plus. Beaucoup de développeurs reprochent aussi aux IDE leur lourdeur. C'est parfois justifié (je ne citerai personne), mais dans cette vidéo, avez-vous vous eu l'impression qu'Eclipse était lent et se mettait sur mon chemin?

samedi 6 mars 2010

Redécouvrir JavaScript

Comme beaucoup de monde, j'avais une certaine aversion pour JavaScript. Ces derniers mois m'ont permis de remettre un peu en perspective pas mal de mes anciennes croyances. Vous allez sans doute me demandez comment la magie à-t-elle opérer (ou pas)? Et bien en fait assez simplement à partir du moment qu'on décide de lui donner sa chance, et d'arrêter de se contenter de hacker quelques bouts copiés/collés à droite à gauche. Voici en tout cas pour moi les grands points qui m'ont permis non pas de devenir un expert, mais de pouvoir m'en servir sans hurler à la mort :

  • Le plus gros manque finalement au départ de javascript, c'est un framework de base livré avec l'engin. Sans ça, on a l'impression de réinventer 100 fois la roue, et de perdre pas mal de temps à faire la même chose. Le premier conseil est donc d'utiliser une des fantastiques librairies qui vivent dans le coin. Leur philosophie peut varier, donc méfiance, mais je préfère personnellement m'appuyer sur jQuery, car je le qualifierai bien de plus simple qui fonctionne. Il est malgré tout à la fois très puissant et extensible à souhait. Je dois avouer que du coup je n'ai pas trop essayé la concurrence qui en comparaison semblait bien plus complexe.
  • Il faut se rendre compte que JavaScript est un vrai langage, avec son propre paradigme, et qu'il ne sert donc à rien de tenter de ramener toutes ses habitudes de nos langages favoris (java, c#, python ruby, choisissez celui qui vous fait plaisir). Comprendre ce qui se passe et les quelques concepts de base qui animent le langage fait déjà beaucoup pour commencer à l'apprécier. C'est pour cette raison par exemple que encore une fois je préfére jQuery à prototype, car il n'essaye pas d'ajouter un support "classique" de l'orienté objet au langage, il lui demande juste d'être lui même, naturellement. J'aimerais bien vous conseiller un bon tutorial sur le sujet, mais hélas j'ai appris tout ça dans deux bouquins.
  • Le conseil bateau maintenant, il faut s'abstraire le plus possible du navigateur en utilisant une bonne librairie : ça recoupe en grande partie le premier point, mais c'est surement le soucis qui retient beaucoup de monde à apprendre Javascript. jQuery fait un boulot fantastique pour faire oublier là plupart des soucis de compatibilité, même s'il reste bien entendu quelques problèmes à droite à gauche.
  • Enfin, mais sans doute le point plus important, les bonnes pratiques de programmation ne sont pas à jeter tout simplement car on se trouve côté navigateur. Il n'y a pas de secret, le seul moyen de vraiment tirer partie de javascript est d'appliquer les bonnes pratiques, DRY et TDD en tête de liste. Il existe quelques frameworks de tests unitaires en javascript, même si rien n'est parfait bien entendu pour le moment dans ce domaine, surtout lorsqu'il s'agit de les faire tourner automatiquement pendant l'intégration. TDD fonctionne bien en javascript encore une fois du moment qu'on essaye de pas de tordre le langage dans un orienté objet "classique". Pour reparler, encore, de jQuery, développer ses fonctionnalités sous la forme de plugin pour ce dernier les rend incroyablement plus testable et réutilisable.

Ma conclusion finalement serait qu'il y a encore quelques mois, je lorgnais beaucoup du côté GWT pour les mauvaises raisons : la peur de javascript. Paradoxalement, avoir adopté ces derniers mois Restlet, freemarker et jQuery a beaucoup simplifié le développement que les quelques essais avortés avec GWT. Le plaisir des choses simples il faut croire :) Ces framework sont solubles dans une approche ROA là ou GWT l'est beaucoup moins.

Pour aller plus loin, javascript commence même à envahir la programmation côté serveur grâce aux deux initiatives CommonJs et Node.js. Il y a un bon article sur le sujet dans le pragpub de ce mois-ci

mardi 8 décembre 2009

AppEngine

Aujourd'hui, je vais essayer de parler un peu d'AppEngine.

Rapidement

Commençons par un peu de présentation. Pour ceux du fond qui ne le savent pas, AppEngine, c'est le système d'hébergement mutualisé made in google pour des applications développées soit en Python, soit en Java. L'idée est donc de développer tranquillement son application, et de laisser à google la responsabilité de l'infrastructure et de la montée en charge. Niveau facturation, on ne paie que ce qu'on consomme à partir d'un certain quota.

Déjà, le premier point que j'aimerais souligner, c'est que nous disposons enfin d'une offre solide et abordable d'hébergement mutualisé pour Java (pour python, on pouvait déjà trouver son bonheur en fouillant un peu). Ça n'a l'air de rien comme ça, mais j'ai envie de dire c'est pas trop tôt. Voilà près de 10 ans qu'il est très facile de trouver un hébergement mutualisé pour Php, mais qu'il est très difficile voir impossible de trouver une offre équivalente pour d'autres technologies. Du coup, PHP est presque devenu un standard sur le net, alors qu'il est sans doute difficile de trouver pire environnement de dev (support des TU lacunaire, pas de refactoring, un style très procédural, une communauté globalement très mal formée et sensibilisée aux bonnes pratiques de développement, pas de framework unifié de base, etc. etc.). Alors bien sûr, je ne pense pas qu'AppEngine va réussir à inverser la tendance, mais j'espère juste qu'à l'avenir, des offres d'hébergement pour des technologies/langages plus "agréables" comme Python ou Ruby vont fleurir sur le net. Bref, après un paragraphe qui je suis sûr, va me faire lapider par tous les aficionados de php, passons aux choses sérieuses (vous pouvez m'envoyer vos cailloux par email).

Un peu (beaucoup) de technique

Parlons un peu technique. Je vais me contenter de parler de la partie java d'AppEngine, car je ne suis pas du tout un expert python, et je n'utilise que des langages pour lequel il existe un IDE avec un bon support du refactoring (et ceux qui disent que ces outils ne servent juste qu'à palier les manques d'un langage n'ont juste rien compris à ce qu'est fondamentalement le refactoring).

En terme de développement et de déploiement, si vous utilisez le plugin eclipse de google, tout est excessivement simple, et mérite à peine d'en parler : vous codez, vous testez, et vous déployez en un seul clique. Un serveur de développement AppEngine est fourni pour vous permettre de faire des tests d'intégration, et TDD peut s'utiliser sans aucune contrainte, en fakant rapidement l'accès aux données. IntelliJ IDea dans sa version complète je crois fournit également un support pour tout ça. Là où ça commence à être compliqué, c'est si vous voulez utiliser maven pour automatiser votre build et votre intégration. Clairement, ce n'est pas au point, et j'ai laissé tomber l'idée pour le moment.

Ceci étant dit, abordons les limitaions d'AppEngines. Pour garantir la scalabilité et la mutualisation de votre application, Google a dû imposer des contraintes de taille.

Première contrainte, toutes les fonctionnalités de l'API java ne sont pas à votre disposition. Les deux restrictions qui sautent aux yeux mais qui sont assez logiques sont l'impossibilité bien sûr d'écrire sur le FileSystem, ainsi que l'interdiction de créer des threads. Il y en a d'autres, mais je vous laisse la surprise, je ne veux pas trop spoiler.

Deuxième contrainte très importante, et c'est celle qui va le plus nous intéresser : le stockage de vos données. Et oui, vous ne pouvez pas utiliser votre cher SGBD. C'est assez logique en fait. Pour garantir la scalabilité et la vitesse d'accès à vos données, google fournit son propre système, BigTable, pas du tout relationnel. Bon si cette base n'est pas relationnelle, qu'est-elle donc? Elle est hiérarchique. Ce genre d'approche permet de répartir bien mieux vos données sur N cluster, là ou les SGBD eux ont beaucoup plus de mal. Ce miracle est dû au fait que ces approches ne se concentrent par sur la cohérence des données, mai sur leur accessibilité et leur distribution, là où un sgbd se concentre sur l'accessibilité et la cohérence. Le bémol est donc que vous n'avez pas la garantie qu'à un instant T, une entité donnée est cohérente sur l'ensemble des noeuds. Ok, une base hiérarchique, c'est quoi donc? Vos données sont organisées en entités, contenant des propriétés clef/valeur de types supportés. Ces valeurs peuvent être d'autres entités. Le DataStore regroupe les entités par groupe, chaque groupe ayant une racine. Et là, normalement, si comme moi vous aimez Domain Driven Design, ça doit faire tilt dans votre tête. Entités? Groupe? Racine? Pouvons-nous réécrire ça en Agrégat, racine d'Agrégat et entité? Et bien oui, nous le pouvons. Nous avons face à nous un système de stockage mimant les grands concepts de DDD, et ça, c'est la classe. Nous pourrions normalement sauter de joie, mais hélas non, pas encore. Pour nous permettre de décrire la persistence, Google nous fournit une implémentation partielle de JDO ou JPA. Voilà déjà un premier point noir à mes yeux : pas d'ignorance de la persistance pour nos objets du domaine, vu que le mapping se fait donc nécessairement par annotations. Deuxième gros point noir, pour modélier une relation entre deux racines d'agrégats, nous devons nécessairement passer par la clef. Et oui, pas de mapping transparent entre deux racines : l'un ou l'autre contient la clef qui va nous permettre de faire la requête adaptée.

Dernière contrainte que je vais aborder : le développement itératif. Si vous suivez un modèle de développement agile correctement implémenté (ok disons que vous utilisez XP, ça ira plus vite), vous êtes incrémental et itératif. Itératif veut donc dire que votre modèle évolue au fur et à mesure des besoins et de votre compréhension. Si le modèle évolue, nécessairement sa persistance aussi. Le DataStore n'a pas du tout besoin que toutes les entités d'un même type possèdent les mêmes propriétés, donc on pourrait croire qu'en théorie pas de soucis. Oui mais si vous devez tout de même faire une mise à jour des vielles entités pour une raison X ou Y (notamment si vous avez ajouté un type valeur comme un boolean), comment faire? Voilà tout le soucis, actuellement, même si Google planche sur le sujet, vous ne pouvez pas facilement. Vous avez une limite de 1000 entités par requête, et une requête a un temps de vie très court accordé par le système avant d'être tuée. Il existe bien sûr des solutions de contournement, mais rien de bien simple et de pleinement satisfaisant.

Et pour conclure

Bien voici venu le temps d'une grosse conclusion. Ce que j'aime, voir ce que j'adore chez AppEngine, c'est enfin l'accès à un hébergement abordable et de qualité pour Java. Vous pouvez utilisez si vous développez avec AppEngine en tête dès le début vos frameworks et techos préférés (Groovy, Restlet, Spring, Guice <ajoutez ici votre techo>). J'adore également, et ce n'est pas seulement dû à AppEngine, l'attaque qui est faite aux SGBD traditionnelles. Des technologies solides de remplacement voient enfin le jour grâce à ces nouveaux services, et on peut espérer voir la fin de notre vivant des ces applications codées en procédures stockées, soit disant pour être performantes. Là vous n'avez pas le choix : votre métier est dans votre application, pas dans la base. Bien sûr, ce n'est pas encore complètement au point à mes yeux tant que l'ignorance de la persistance n'est pas atteinte, mais c'est sur une très bonne voie. Si vous ne voulez pas dépendre, à juste titre, de sociétés comme Google et Amazon pour stocker vos données, des implémentations solides et open source de ces nouvelles bases de données sont disponibles.

Enfin, je m'excuse si ma vulgarisation des théories derrière BigTable est vraiment lapidaire, mais je vous laisse bien entendu l'opportunité de me fustiger dans les commentaires :)

vendredi 13 novembre 2009

Vidéos de l'agile tour

Choses promises, choses dues, quelques vidéos de l'Agile tour Bordeaux 2009 sont d'ores et déjà en ligne. 
Voici, en deux parties, la session que nous avons animée avec Charles sur TDD.
Pour voir le reste des vidéos déjà en ligne, ça se passe par là

lundi 2 novembre 2009

Les deux écoles de TDD

Je ne sais pas pourquoi ces derniers temps, j'entend pas mal de retours comme quoi le refactoring serait ralenti par les tests unitaires. L'explication derrière cette affirmation douteuse est qu'il faut bien souvent modifier les tests en même temps que le code de production.

J'ai tendance à croire que cette idée bizarre est née d'une des deux écoles de TDD. Ces deux approches ont été bien décrites par Martin Fowler dans son article sur les mocks et les stubs.

Je vais me permettre de le paraphraser ici :

  • L'approche classique essaye d'utiliser le plus possible de vrais objets, et un "double" s'il est difficile ou gênant d'utiliser l'implémentation réelle (par exemple, l'envoie d'un mail)
  • L'approche par Mock va utiliser dans tous les cas des doubles de test pour tout objet ayant un comportement intéressant.

Pour qualifier ces deux méthodes, Mister Fabien parle de tests Boîte Noire et de tests Boîte Blanche.

Appliquer systématiquement une approche par mock implique une chose : on teste plus la chorégraphie de notre objet que ses résultats. Nous allons vérifier que tel méthode de tel mock a été appelé avec tel paramètre, et que si nous retournons tel valeur, alors notre objet va se comporter de telle manière. Ce faisant, nous liions inexorablement notre test avec l'implémentation sous-jacente, rendant par la même plus douloureux le refactoring, car il nous faudra effectivement changer les tests en même temps que le code de production. L'écriture des tests peut être fastidieux en plus, vu la quantité d'éléments à doubler (constat fait par exemple lors du JUG Bordelais sur le sujet

Dans une approche classique, comme nous testons la plupart du temps le comportement extérieur, nous nous moquons éperdument de l'implémentation, pour vu que le résultat soit bon, et nous passons également moins de temps à écrire nos doubles.

vendredi 15 mai 2009

Retour sur Bordeaux JUG TDD

Que d'acronymes dans ce titre. Hier soir, je suis donc allé pour la première fois à une réunion du JUG Bordelais car et d'une, je ne connaissais pas avant, et de deux, le sujet était TDD, et si vous me suivez un peu vous devez savoir que j'y accorde une certaine importance.

Pour mettre les choses au clair, le TDD est pour moi un point critique pour l'avenir de notre profession (oui carrément). Comme aime à le répéter l'oncle Bob, nous devons devenir des professionnels, et cela passe essentiellement par écrire du code propre. Hors comment écrire du code propre? Et bien pour le moment je n'ai pas trouvé mieux, et apparemment je ne suis pas le seul, que d'écrire les tests avant de coder.

Donc voilà le cadre posé, qui va me permettre maintenant de décrire ma déception. C'était un retour d'expérience sur un forfait mené normalement par les tests. Déjà, premier signe d'alarme, l'équipe s'est mise à tdd contrainte et forcée, car c'était une exigence du client. Deuxième point noir, personne dans l'équipe ne connaissait l'approche, du coup bien entendu, ils ont eut d'énormes difficultés à s'y mettre sans quelqu'un d'expérimenté pour montrer l'approche. Suite à cette présentation du contexte, on enchaine donc par une présentation un poil trop succincte de ce qu'est TDD. Ouf on a eu droit au moins un cycle test, code, refactor, mais le refactoring est à mon avis trop passé à la trappe. Disons plutôt qu'il était considéré comme acquis pour le public ou l'orateur, ce qui à mon avis n'était pas du tout le cas. Le plus gros défaut finalement et que cette introduction n'a montré tdd que comme une pratique de qualité, et pas d'architecture. Pire encore, cette présentation a été faite dans l'esprit que la qualité s'oppose à la productivité, ce qui est une des pires idées reçues de notre métier. La productivité passe par la qualité, inévitablement; j'y reviendrai plus loin.

Ensuite, s'en est suivi une partie bien trop longue à mon avis sur les problèmes que l'équipe avait rencontrés, et leurs solutions. Je pense que pour quelqu'un ne connaissant pas le sujet, toute cette partie a eu plutôt tendance à convaincre que tester, c'est long, cher et compliqué.

On finit ensuite par une métrique qui m'a obligée à réagir, encore une fois sur la productivité, à base de "regardez, l'application fait 3000 lignes, mais on a du faire 12000 de lignes de tests . Bouh la productivité de merde". Ok, alors premier point, je crois que l'on s'est bien rendu compte que productivité et nombre de ligne de code n'avait juste rien à voir. Piloter son code par les tests permet d'écrire du code plus concis et mieux structurer, et par la même moins gros qu'un code écrit sans les tests. Donc ces fameuses ligne de code que prennent les tests qui sont soit disant le mal absolu (on est pas payé à tester voyons), combien de lignes de code de production ont-elle économisées? Et à votre avis, entre un code qui fait juste ce qui est attendu, et un code qui en fait trop car il est parti dans les peut-être, lequel a le plus de chance de contenir des bugs? De plus, si on suit le cycle tdd: code de test qui suffit à être au rouge, code minimum pour faire passer, refacto; combien de temps passe-t-on dans le debugger? Oui ces grandes sessions de debugging, où l'environnement met plusieurs minutes à démarrer, où on pose des points d'arrêt à l'aveugle, où on rate son passage donc on doit recommencer; oui elles disparaissent pratiquement intégralement quand on mène correctement le développement par les tests. Pas un mot là dessus hier soir (enfin si, là j'ai pas pu m'empêcher de dire quelque chose). Autre gain de temps par tdd: on reste concentré. Plus de temps perdu car on papillonne sur trop de tâches en même temps: on reste concentré sur le test en cours, ce qui peut le faire passer au rouge ou au vert, et rien d'autre. Le fameux "turnaround" est ainsi réduit. Bien entendu, le gain final évident est qu'il est excessivement plus facile de découvrir et corriger les bugs quand on a produit l'application avec les tests qu'autrement.

Ah ce stade là, je tiens à féliciter la brillante intervention d'un des auditeurs, qui a tout de même sorti que comme les bugs, c'est de la maintenance, et que nous notre travail, c'est le développement, alors on en a rien à foutre de produire une application de qualité. Dixit le bonhomme, le client ne testant pas tout, il va accepter la livraison, nous donner le chèque, et ça nous suffit. Cette attitude à un nom: c'est de l'escroquerie, comme vendre une voiture d'occasion avec des freins prêts à céder. On a fait la vente, mais on a des chances de tuer le client. Cette vision est à mes yeux incroyablement limitée et pourrait presque s'apparenter à l'économie de la Camorra: un profit à très court terme sans considération pour les externalités négatives. Non seulement, le client ne reviendra sans doute pas, (je le sais, j'en récupère des déçus en ce moment), mais en plus, on donne une image de garagiste aux informaticiens. Vous avez déjà eu ce sentiment, en allant faire réparer votre voiture que vous allez vous faire truander? Et bien c'est exactement ce qu'est en train de devenir notre profession avec des attitudes pareils. Je crois que Michael a d'ailleurs bien répondu hier soir à cette remarque :) Je pourrai ajouter que je ne crois pas de toute manière en cette opposition développement/maintenance, et que la maintenant débute dès le premier commit, mais ce serait un peu hors sujet.

Une question également est passée à laquelle je n'ai pas eu le temps de répondre, c'était l'éternel "le client doit être mature pour accepter les tests". Ah ça je répond, que nous n'avons pas à vendre les tests. Nous n'avons pas à vendre au client que nous allons utiliser de l'intégration continue ou du refactoring. Nous n'avons pas à lui demander s'il préfère qu'on laisse un swicth à la place d'un polymorphisme, s'il préfère qu'on utilise eclipse ou netbeans Ce que je veux dire, ce que nous n'avons pas à lui vendre notre manière de travailler pour qui l'accepte. Il faut arrêter un peu de se plaindre tout le temps car on a pas l'autorisation de faire les choses comme on le voudrait. En tant que professionnels, nous sommes seuls en charge de notre manière de travailler. Nous sommes grands et responsables, et devons assumer pleinement le fait que nous avons un métier. La manière dont on l'accomplit techniquement regarde peu le client du moment que nous maximisons son investissement.

Pour conclure, j'ai tendance à penser que toute initiative pour faire découvrir TDD est bonne à prendre, mais la présentation d'hier soir animée par quelqu'un de très peu expérimenté dans l'approche, et qui apparemment du coup n'était pas du tout convaincu, à fait plus de mal que de bien à mon avis. J'ai conscience bien entendu que je ne prend pas de gants dans ce billet, et si je choque certaines personnes je m'en excuse, mais les commentaires sont ouverts, et puis si des gens du JUG me lisent, pourquoi ne pas organiser un contre débat?

P.S: toutes ces questions sont finalement des classiques, et Fabien avait déjà produit un billet sur le sujet il y a quelques temps pour répondre aux mêmes interrogations.

mercredi 6 février 2008

TDD

Au détour d'un coin de web, je suis tombé sur un article intéressant de Patrick Smacchia

Lire la suite...