Bienvenue sur Développement Agile

Référence sur le développement logiciel Agile. Nous traitons de conception, de programmation, de pratiques de génie logiciel, d'essais et d'autres sujets connexes.

Classique du développement logiciel: Head First Design Patterns

Publié par David Beaumier le mercredi 10 décembre 2014 à 13:06

J’ai remarqué récemment que le livre «Head First Design Patterns » a reçu une mise à jour pour souligner son 10ième anniversaire de publication. Premièrement, il faut savoir que ce n’est en aucun cas le livre le plus avancé sur le sujet, mais comme le dit cet internaute « Si tu ne comprends pas les Design Patterns après cela, c'est alors peine perdue ».

Couverture Head First Design Patterns

Il s’agit donc d’un livre tout indiqué pour le p’tit nouveau de votre équipe ou pour un collègue qui ne connait pas encore les patrons de conception et qui souhaite s’initier au sujet. Présenté dans le format ludique associé à la série Head First (approche néanmoins très sérieuse), c’est une lecture agréable et somme toute légère si on considère le sujet. Le livre propose tout d’abord une introduction au concept de « patrons de conception », sans prendre pour acquis que le lecteur est un programmeur OO ceinture noire. Les principes OO liés aux patrons sont présentés au fur et à mesure, de façon à ce que le lecteur possède les bases requises pour bien comprendre comment mettre en oeuvre le patron.

Un des aspects intéressants de ce livre est l’abondance d’illustrations. Celle qui suit est un exemple typique du style utilisé par l’auteur, qui, il faut l’avouer, est assez différent de celui retrouvé dans la majorité des livres traitant du même sujet.

Exemple Diagramme HFDP

Ce classique propose, pour son édition renouvelée, des exemples basés sur les nouveautés de Java 8. Ceci dit, il est tout aussi pertinent pour ceux qui développent sous d’autres plateformes, telle que .NET. Les exemples sont simples et faciles à comprendre.

 Il est impressionnant de voir que plus de 10 ans après sa parution, il se retrouve au #1 des ventes de sa catégorie (au début de décembre 2014). C’est vraiment ce qu’on appelle un incontournable!

Ranking HFDP

Version française

Une édition française de ce livre a déjà existée, avec le titre « Design patterns : Tête la première », mais elle était basée sur l’édition originale et n’était disponible qu’en e-book (PDF). L’éditeur ayant fermé ses portes depuis, elle ne semble plus disponible pour achat.

D’autres billets qui pourraient vous intéresser

Pour aller plus loin

Si vous souhaitez approfondir le sujet des patrons de conception, je vous recommande la formation Concepts orientés-objet avancés appliqués au développement agile présentée par mon collègue Félix-Antoine Bourbonnais.

Comment rendre vos tests unitaires plus propres grâce aux « Builders »?

Publié par Félix-Antoine Bourbonnais le dimanche 1 avril 2012 à 00:00

Motivations

La vaste majorité des tests unitaires que nous écrivons demandent la création d'un contexte initial préalable (le "given").

Or, l'établissement de ce contexte est souvent long et peut rapidement se transformer en bruit (forme de pollution) qui brouille la raison d'être du test (le "when" et le "then") au travers d'une série de lignes de préparation souvent un peu cryptiques.

Afin de remédier à cela, plusieurs solutions classiques existent: utilisation de la méthode d'initialisation (@Before en Java) ou encore les objets mères (Mother Objects). Mais ces techniques ne sont pas toujours appropriées ou ont des désavantages comme nous le constaterons plus tard.

Une autre technique de plus en plus populaire consiste à utiliser une forme du patron Builder afin de construire des données ou un contexte. Cette technique bénéficie maintenant d'outils (frameworks) simplifiant leur création. Pour la suite de cet article, nous démontrerons cependant l'utilisation manuelle afin de bien en faire ressortir le concept.

Un Builder pour les tests

Afin d'illustrer l'utilisation d'un Builder pour les tests, voici un exemple:

Sans Builder

@Test
public void givenACarWith2DoorsAlreadyUnlockedWhenUnlockThenAllDoorsUnlocked() {
// Given (contexte)
Car aCarWith2DoorsUnloked = new Car(Color.RED)

Door driverDoor = new Door(Size.LARGE, Orientation.FRONT_DRIVER);
driverDoor.unlock();
aCarWith2Doors.addDoor(driverDoor);

Door passengerDoor = new Door(Size.LARGE, Orientation.FRONT_PASSENGER);
passengerDoor.unlock();
aCarWith2Doors.addDoor(passengerDoor);

// When
aCarWith2DoorsUnloked.unlock()

// Then
assertFalse("All doors should be unlocked", aCarWith2DoorsUnloked.allDoorLocked());

}

Le code ci-dessus montre certains problèmes:

  • L'initialisation du contexte compte pour environ 60% des lignes du test. Or, ce n'est pas la partie la plus importante et beaucoup des lignes ne sont que du bruit et ne permettent pas d'identifier rapidement quel est le contexte;
  • L'initialisation étant très longue, on doit ajouter des commentaires afin de diviser les trois grandes parties du test.

Il serait possible d'améliorer ce test en déplaçant ce contexte dans une méthode privée ou encore d'utiliser la méthode d'initialisation (@Before). Mais plusieurs problèmes demeurent:

  • Il est fort probable que les autres tests ne demandent pas exactement la même configuration de voiture. Donc des configurations seront toujours nécessaires et la forme ne changera pas;
  • Cela demanderait de créer plusieurs versions de voitures avec plusieurs configurations différentes. Un bon nombre ne seraient utilisées que par une poignée de tests. Il s'agit d'une pollution de la classe de test, de la méthode d'initialisation et cela rend la compréhension des tests plus difficile;
  • La construction de l'état initial est éloignée de son utilisation. Rendant ainsi le test plus difficile à comprendre, car il faut constamment alterner entre la méthode d'initialisation et la méthode de test pour avoir l'exemple complet (le test).

Avec Builder

@Test
public void givenACarWith2DoorsAlreadyUnlockedWhenUnlockThenAllDoorsUnlocked() {
Car aCarWith2DoorsUnlocked = aCar().withDoors(
aDoor().unlocked().build(),
aDoor().unlocked().build()
).build();

aCarWith2DoorsUnloked.unlock()

assertFalse("All doors should be unlocked", aCarWith2DoorsUnloked.allDoorLocked());

}

Non seulement le nombre de lignes a fondu, mais chacune des lignes devient subitement beaucoup plus explicite. C'est un aspect très important des tests puisque ceux-ci doivent servir idéalement de documentation exécutable. Il est désormais possible de lire le test comme une petite histoire:

  1. Il était une fois une voiture avec deux portes déverrouillées...
  2. Quand, soudain, on demande à la petite voiture de se déverrouiller...
  3. Alors, toutes ses portes se déverrouillent...
  4. Ainsi, le petit chaperon peut embarquer rapidement dans sa voiture sans se faire mouiller par la pluie qui faisait rage par cette journée de printemps... Mais ça, le test ne le dit pas...

Remarquons qu'avec l'utilisation du Builder, la section de configuration (given) a un sens et n'est pas polluée par des bruits inutiles et sans effet pour ce test. Ainsi, la couleur de la voiture n'est pas précisée puisqu'elle n'influence en rien ce cas de test. Par contre, il demeure qu'il s'agit d'une information requise afin d'initialiser la voiture et cet argument doit, en conséquence, rester.

Ainsi, le Builder permet de cacher ce qui n'est pas directement un facteur impliqué dans le cas de test en proposant initialement un modèle "standard" qui sert de base. Ensuite, le Builder offre des "options", à la pièce, pour personnaliser notre voiture afin qu'elle soit dans l'état nécessaire pour un test particulier. Cette configuration sous la forme d'options rend explicite les particularités et l'état initial de notre test tout en ne montrant que l'essentiel pour ce test.

Finalement, notons la disparition des commentaires qui permettaient de séparer les sections du test. Ceux-ci ne sont plus nécessaires, car le Builder permet l'écriture de la section Given en bloc.

  • Plus récents
  • 1
  • Plus anciens

Archive