Notes de Lecture: The Art of Unit Testing

J’ai lu ce livre il y a un an ou deux, mais il est toujours d’actualité et je trouvais important de vous en parler. D’une certaine manière c’est toujours bon de revoir ses bases de temps à autre. Ce livre est en quelque sorte un « must » pour tout développeur, notamment ceux qui font du .Net. Il existe aussi une version inspirée de ce livre chez le même éditeur avec les exemples en Java intitulé « Unit Testing in Java » qui sera publié cette année.

Premièrement, pour bien situer ce livre, ce dernier se concentre surtout sur l’aspect « Test unitaire » et non le TDD (Développement piloté par les tests). Ce dernier y est mentionné un peu, mais l’accent de ce livre n’est pas tout simplement pas sur cet aspect.

L’auteur, Roy Osherove,  nous fait découvrir de manière pédagogique plusieurs notions essentielles lorsque l’on veut progresser dans les tests unitaires, notamment vers des cas plus complexes. Et ce, dans l’environnement de développement .Net, malgré que la plupart des notions peuvent être adaptées pour un autre environnement de développement orienté-objet.

Le TDD avec des cas simples c’est bien beau et facile, mais cela peut se corser assez vite merci. On y voit alors dans ce livre plusieurs trucs, notions et techniques tels que:

  • Les techniques de base
    • Les Stubs
    • Les Mocks
    • Les différents frameworks d’isolation
  • Le code de test
    • L’organisation et la hiérarchie des tests…
    • Les bonnes pratiques pour les tests
  • Processus et conception
    • Intégrer les tests dans l’organisation
    • Travailler avec du « Legacy Code »

J’aime le fait que l’auteur dans les premiers chapitres s’occupe de bien définir les termes essentiels qui seront utilisés tout au long du livre tel que:

  • Test Unitaire
  • Test d’intégration
  • State-based testing / vérification d’état
  • Interaction testing / vérification de l’interaction avec d’autres objets
  • Système sous test
  • La régression
  • C’est quoi du « Legacy Code » ? (en fait c’est du code sans tests unitaires)
  • Refactoring
  • Seams
  • Fake
  • Dynamic Fake

Point que je trouve important et qui est aussi abordé dans ce livre, c’est comment nommer nos méthodes de tests. J’aime bien la formule que l’auteur suggère, soit de nommer en trois parties séparées par le caractère « _ »:

  • Nom de la Méthode
  • État du test
  • Comportement prévu

Ex.: IsValidFileName_ValideFile_ReturnsTrue()

Si vous avez beaucoup de tests dans votre projet, vous allez voir que ce type de nommage aidera le classement et permettra de facilement déduire le test d’après son nom.

Le Pattern AAA est aussi abordé dans le livrer et c’est un de mes préférés. Donc, je vais vous en parler un peu. Il s’agit en fait de faire notre méthode de test en trois « sections » fonctionnelles qui sont les suivantes:

  1. Arrange: On prépare les variables nécessaires et autres préalables.
  2. Act: Action sur l’objet ou la méthode que l’on teste
  3. Assert: On compare le résultat attendu versus celui obtenu.

Exemple:

[Test]
 public void CalculateSalesBonus_VendorWithSalesBonus_BonusMade()
 {
 // Arrange
 int salesNovember = 10000;
 var calculator = new BonusCalculator();

 // Act
 var result = calculator.CheckBonus(salesNovember);

 //Assert
 result.ShouldEqual(100);
 }

Un aspect important quand on établit notre code de test, c’est de commencer par l’assertion (et oui, on commence par la fin !). Cela rend plus clair par la suite la réalisation des étapes d’Arrange et d’Act. Ce conseil me vient de JR Rainsberger que j’ai eu l’occasion de rencontrer au Code Retreat à Québec en 2011.

Personnellement, je trouve que faire des mocks peut parfois être utile, mais il faut faire attention car cela peut nous amener à faire beaucoup de code. J’aime bien dans ces cas appliquer la règle de Pareto, ou celle du 80/20, c’est-à-dire qu’on ne fera pas du code 80% plus gros pour tester un 20% de notre application. Il faut y aller alors de manière pragmatique.

L’auteur parle aussi au chapitre 8 des manières d’introduire les tests unitaires automatisés dans une organisation, encore là, une bonne section du livre. Le facteur humain n’est pas à négliger ici, car le TDD et les tests unitaires, qui introduisent une nouvelle manière de concevoir notre code, peuvent provoquer des bouleversements au passage.

Bref, si vous faites du développement avec .Net ou Java, et que particulièrement vous trouvez que c’est dur de faire des tests unitaires (et vous avez raison, car ce n’est pas une mince tâche), ce livre peut vous aider.

J’ai fait un résumé des idées de ce livre (avec une certaine adaptation) dans le mind map suivant (cliquer pour l’agrandir) :

 

 

 

 

 

 

 

Mes points clefs:

  • C’est important de bien connaître les techniques de base (stub, mock et framework) afin de progresser dans la programmation des tests unitaires
  • Organiser les tests (nomenclature, projets), n’est pas à négliger pour établir un standard dans l’équipe de programmeurs
  • Pour implanter le TDD et les tests unitaires dans une organisation, il faut être prêt. Ex.: répondre aux questions, identifier les champions, gérer avec les « bloqueurs, avoir des buts spécifiques, etc.

 

Références:

Publicité

Comment se déroulent vos revues de code ?

En lisant l’excellent article « What should a good code review look and feel like? » de l’auteur Roy Osherove, j’ai fait une réflexion sur la manière dont j’effectue des revues de code.

 Mon côté « Exteme Programming (XP) » irait de manière pragmatique avec seulement de la programmation en paire, ou « Pair Programming » pour la revue de code. Par contre, dans mon entreprise qui est dans le domaine de la finance, des audits de vérifications de qualité sont nécessaires. Donc, nous utilisons régulièrement une liste de vérifications de conformité que les programmeurs et analystes organiques remplissent lors de la revue de code.

Bien que ceci officialise cette validation, ce n’est pas complet comme exercice selon moi. J’aime bien, en plus de compléter notre liste de vérification, m’assoir quelques minutes avec le programmeur et regarder le code ensemble. Surtout si on parle d’un développement d’un nouveau composant. C’est plus « humain » et je constate qu’il se produit alors un meilleur transfert de connaissance et qu’il s’en suit de bonnes discussions au sujet de code.

Je me demande un peu comment ailleurs on procède lors d’une revue de code, en particulier dans les entreprises où la preuve de la vérification de la qualité du logiciel est requise. Des exemples  ?

Référence:

Est-ce que vous tenez à votre équipe ?

J’ai assisté mercredi soir dernier à la conférence de François Beauregard intitulé « De l’individu à l’organisation en passant par l’équipe« . C’était dans le cadre des conférences mensuelles organisées par Agile Québec.

J’ai été particulièrement interpellé lors du sujet de la structure d’équipe. François a cité ceci (sans les mots exacts toutefois):

Il arrive parfois qu’on saborde les bonnes équipes à la fin des projets. C’est comme si au hockey, on prenait l’équipe qui a gagné la coupe Stanley, et on la divisait en donnant un joueur à chaque autre équipe.

J’ai vécu cela souvent dans le passé lorsque j’étais consultant et je le vois malheureusement encore dans mon travail actuel en tant qu’employé permanent dans une entreprise privé.

Je me rappelle, lors d’un de mes anciens projets il y a quelques années, que l’on avait une des meilleures équipes. Elle était d’ailleurs qui était composé ainsi:

  • 3 Programmeurs
  • 1 Analyste fonctionnelle
  • 1 Architecte Logiciel /  Scrum Master
  • 1 Chargé de projet

Au besoin, on pouvait avoir accès à d’autres personnes pour nous aider dans un aspect où l’on était moins expérimenté. Par exemple avec les bases de données, on se débrouillait bien. Mais, si on avait quelque chose de plus corés à faire, on pouvait avoir accès à un DBA pour nous aider. Notre équipe se complétait bien ainsi.

Après plusieurs sprints où l’équipe a vécu des hauts et des bas, des rétrospectives, des apprentissages, des démos aux clients, l’équipe était rendue très unie et pouvait pratiquement affronter n’importe quel défi selon moi. Elle était devenue un peu comme une « super-équipe ». Mais le projet fut terminé, les personnes séparées dans différents projets selon les affectations et avec pour résultat: plus de super-équipe !

Je suis certain que si on avait fait des efforts pour la garder intacte et la déplacer de mandat ou de client, elle aurait été très performante, car plusieurs aspects étaient maintenant acquis. Les gens se connaissent bien, il y avait une chimie qui s’était créée. Mais pourquoi on ne veut pas tenir à ce genre d’équipe au sein de certaines entreprises ?

Je travaille maintenant pour une entreprise privée et je vis parfois la même chose. Avec le mélange de personnels permanents et de consultants, dont les contrats qui se termine à différents moments, c’est une belle jonglerie que de garder une bonne équipe intacte.

Comment régler ce problème ?

Je ne crois pas au « responsable unique » en général dans la vie et c’est le cas ici je crois. Les gestionnaires et directeurs ont des contraintes de budget et de ressources à gérer. Ils font de leur mieux en dépit des circonstances. Toutefois, si ce n’est pas le cas, ils ont peut-être à se à se rapprocher des équipes de temps en temps pour mieux comprendre ce qui se passe.

Du côté des équipes de projets, il faut qu’ils sensibilisent les gestionnaires au fait que l’équipe est très bien comme cela et qu’il faut la garder intacte autant que possible.

En bref, le facteur humain étant ce qu’il est, il ne doit pas être géré comme une ressource, mais plutôt de manière organique. J’aime bien la métaphore que Francçois Beauregard a utilisée pour illustré ceci:

La gestion d’une équipe, c’est comme faire grandir un beau jardin.

Ceux qui vivent parfois cette problématique, est-ce que vous voyez d’autres solutions ? N’hésitez-pas à laisser vos commentaires sur ce billet.

Références :

Sondage Développeurs Québec 2012

Quoi de mieux que de commencer l’année avec un petit sondage pour les programmeurs afin d’en savoir davantage sur le profil de notre profession !

L’idée de ce sondage m’est venue lors de la conférence principale de l’Agile Tour Québec 2011 par Robert C. Martin. Ce dernier, au début de sa présentation, avait fait un sondage éclair à main levée parmi les participants afin d’en savoir plus sur les technologies utilisées et les pratiques connues. La foule n’était pas composée à 100% de développeurs et donc les résultats peut-être un peu faux à ce moment.

Histoire d’en avoir le cœur net, j’ai préparé le court et simple sondage suivant:

Remplissez mon sondage !
Merci d’avance de participer à ce sondage, en particulier si vous avez un des profils suivants ou que vous programmer à l’occasion:

  • Développeur/Programmeur
  • Chef d’équipe
  • Architecte Logiciel
  • Testeur
  • Coach
  • Formateur
  • Entrepreneur

Les résultats du sondage seront publiés sur ce blogue dans quelques semaines. Merci d’y participer.

Agile Tour 2011: Un beau défi réalisé !

IMG_0282

Pour une troisième année consécutive, l’Agile Tour était de retour à Québec mercredi dernier, le 26 octobre. Je m’étonne toujours de la qualité du travail que l’on peut faire pour organiser cette conférence en dépit des circonstances. Par exemple, le fait que personne ne travaille à temps plein là-dessus. Tous les organisateurs ont déjà un premier travail.

Aussi, cette année c’est un peu spécial, car un de mes auteurs préférés de livre, Robert “Uncle Bob” C. Martin, était notre conférencier principal.

J’ai adoré sa présentation, “Clean Architecture”, qui était instructive et divertissante, comme d’habitude dans son cas.

En passant, voici les nouveautés que nous avons amenées cette année:

  • La conférence a lieu dans un hôtel au lieu de l’université Laval
  • Nous avons quatre de salles de conférences + une grande salle pour la conférence principale et les repas.
  • Les conférences sont divisées par thème et par salle afin d’en avoir pour tous les goûts chez nos participants.
  • Un comité de programme a été établi afin d’évaluer et de choisir les soumissions de conférences.
  • 18 sessions différentes, en plus de la conférence principale, étaient offertes aux participants.

Aussi, en tant qu’OSBL (organisme sans buts lucratifs), nous nous efforçons de rendre accessible cet événement au plus grand nombre possible de personnes. Nous avons eu aussi un nombre record de participants (400) et nous avons dû en refuser plusieurs pour cause de logistiques et d’espace dans les salles. L’engouement pour le développement Agile est vraiment en hausse à Québec cette année !

Certaines petites choses sont encore à améliorer, mais ce fut selon moi un très bon événement de grande qualité et pour un prix modique (50$). Ce qui concorde parfaitement avec la mission de la communauté Agile de Québec.

Un gros merci particulier à mes collègues pour qui la plupart c’était la première fois qu’ils organisaient un « Agile Tour » :

  • David Beaumier
  • Félix-Antoine Bourbonnais
  • Patrice Caron
  • Louis-Joseph Foujieu
  • Dave Jacques
  • Amélie Turgeon

Au plaisir de vous retrouver à l’Agile Tour 2012 !

Introduction à un Code Retreat par Corey Haines

Voici l’introduction d’un Code Retreat de Corey Haines que j’ai filmé lors de son passage au Code Retreat Québec 2011 en mai dernier.

J’ai téléchargé le tout sur YouTube en 3 parties pour ne pas perdre la qualité HD.:

Partie 1
Partie 2
Partie 3

Références :

Est-ce que votre code est S.O.L.I.D. ?

CrackDans ce billet, je vais vous décrire brièvement les principes SOLID pour la programmation orientée-objet avec quelques commentaires et vous suggérer quelques ressources pour approfondir ce sujet qui devrait être connu de tous les programmeurs sérieux et professionnels.

Je suis toujours surpris lorsque, la plupart du temps, à chaque fois que je parle de ces principes à de nouveaux collègues, mon interlocuteur hausse les épaules et ne sait pas de quoi je parle.

 

S.O.L.I.D. est acronyme regroupant les principes suivants:

  • Single Responsability Principle (SRP): Une classe devrait avoir une et une seul raison (responsabilité) d’être modifiée.
  • Open Closed Principle (OCP) : Chaque classe devrait être ouverte pour des extensions et fermé autant que possible pour des modifications.
  • Liskov Substitution Principle (LSK) : Les classes dérivées peuvent être substitué de leur classe de base
  • Interface Segregation Principle (ISP) : Nos classes ne doivent pas hériter, via une interface, de méthodes qu’elles n’utilisent pas.
  • Dependency Injection Principle (DIP) : On doit dépendre de classes abstraites et non de classes concrètes

De tous ces principes, le plus important à suivre selon moi est le Single Responsability Principle (SRP). Ne pas respecter ce principe peut apporter plusieurs maux, notamment lorsque l’on fait évoluer le code.  Dans mon équipe actuelle, nous avons fait du SRP le principe de base et le plus important à suivre. De cette manière nous l’avons toujours en tête et il nous sert en quelque sorte de règle de base lorsque l’on se questionne sur la grosseur de classes et de méthodes ou autre.

C’est important aussi de connaitre les autres, mais on y fait référence un peu moins souvent à mon avis.

Pour en savoir plus, sur SOLID, vous pouvez commencer par les deux références suivantes sur Internet :

Pour approfondir SOLID, je recommande fortement le livre suivant (Liens Amazon.ca commandités) de Bob Martin qui se décrit en deux versions, tout dépendant si vous êtes de type Java/C++ ou .Net:

Agile Software Development, Principles, Patterns, and Practices

Type .Net (C#/VB)

Type Java/C++

Dans ce livre, l’oncle Bob nous explique les pratiques agiles, on y voit un peu de modélisation et aussi de nombreux chapitres sont dédiés aux principes orientés-objet. Ce livre d’environ 700 pages fait un très beau livre de référence à mettre sur son bureau pour le lire au complet ou le consulter à l’occasion.

En passant, nous aurons la chance de recevoir Bob Martin en tant que conférencier principal lors de l’Agile Tour Québec 2011. Les inscriptions devraient commencer en septembre. Pour info sur l’Agile Tour : http://at2011.agiletour.org/fr/at2011_Quebec.html

Autres articles intéressants avec exemples d’application de SOLID:

Référence pour l’image utilisée:

http://www.sxc.hu/photo/954598

C’est quoi un Lean Startup ?

En gros, c’est un mélange de développement Lean et Agile avec une bonne dose d’entrepreneurship. Le but est d’éviter le plus possible de faire du gaspillage  et de livrer un produit innovateur avec succès. On y dénote les principes suivants:

  • Les entrepreneurs sont partout (Entrepreneurs are Everywhere)
  • L’entrepreneurship c’est aussi de la gestion (Entrepeneurship is Management)
  • L’Apprentissage est validé (Validated Learning)
  • L’innovation doit être comptabilisée (Innovation Accounting)
  • Construire-Mesurer-Apprendre (Build-Mesure-Learn)

Eric Ries est à l’origine de ce terme et il en parle depuis quelque temps. Je trouve sa démarche forte intéressante et cela m’a incité à me tenir informer sur ce sujet. En passant, le concept de Lean Startup peut aussi bien être appliqué à l’intérieur d’une compagnie existante que pour une entreprise en démarrage. Pour en savoir davantage sur Eric Ries, je vous recommande le vidéo suivant d’une de ses conférences qu’il a données récemment :

 

D’ailleurs, son livre sur le Lean Startup sera publié en septembre. J’aime beaucoup le graphique suivant qui montre le cycle de développement dans un Lean Startup:

25255_387440405880_387431575880_4176788_6681867_n (1)

On peut aussi se poser la question suivante, en quoi le Lean Startup est différent du développement Agile ? Le tableau suivant  de Joshua Kerievsky résume fort bien les différences et les similitudes entre le développement Agile et le Lean Startup:

Agile Lean Startup
Product Roadmap Business Model Canvas
Product Vision Product Market Fit
Release Plan Minimal Viable Product
Sprint Kanban
Sprint Review Pivot or Persevere Decision
On-Site Customer « Get Out Of The Building »
User Story Hypothesis
Backlog « To Learn » List
Definition of Done Validated Learning
Red-Green-Refactor Learn-Measure-Build
Customer Feedback Customer Validation
Acceptance Test Split Test
Velocity AARRR
Mock Object Feature Fake
Continuous Integration Continuous Deployment
Certified Scrum Master Customer Success Manager

 

Est-ce que vous pensez que ce genre de modèle peut réussir ici au Québec ?

Est-ce qu’il y a vraiment des entrepreneurs un peu partout ici ou c’est seulement réservé à nos voisins du sud ?

Est-ce que vous connaissez des exemples de compagnies d’ici qui ont appliqué ce modèle ?

 

Références:

La place des Business Objects dans le MVP

Où doit-on placer nos composants d’affaires (i.e Business Objects) lorsque l’on utilise les designs patterns du genre Model-View-Presenter (MVP) ou Model-View-Controller (MVC) ?

C’est une bonne question et  je la retrouve régulièrement dans les projets auxquels j’ai travaillé.

Mais avant de poursuivre, voici une conversation forte intéressante que j’ai observée sur twitter il y a quelque temps entre Robert « Uncle Bob » Martin et Martin Fowler à ce sujet:

Image@unclebobmartin Views should have no knowledge of business objects. Presenters should create data structures from business objects & views should use them.
Image@martinfowler @unclebobmartin disgree. It’s both traditional and effective for views to see domain objects
Image(1)@RonJeffries @unclebobmartin i’d wanna see one or more examples showing why views shouldn’t see domain objects but instead … what, « views « of them?
Image@unclebobmartin @martinfowler The problem is that views become coupled to business logic. Changes to BOs imply changes to views.
Image@martinfowler @unclebobmartin I think the relationships between view, model and other elements is too context-specific for a general rule
Image(2)@GBGames @unclebobmartin @martinfowler To be clear, I know MVC, but it seems there’s debate about what the V knows about the M?
Image[4]@martinfowler @GBGames @unclebobmartin There are many forms of MVC with different trade-offs. I said more at http://martinfowler.com/eaaDev/uiArchs.html
Image@unclebobmartin @peter_bugge BOs change for reasons of business logic. Views need not be affected.
Image@unclebobmartin @sebasmonia A change to the BO will often cause change to presentation logic, but hopefully not to the views.
Image@unclebobmartin An object has private state and public methods. A data structure has public data and no methods. Getters and setters make data public.
Image@unclebobmartin @MahasenBandara Views are concrete. Models are abstract. Views should depend on Models.
Image@unclebobmartin Business interactions are also business objects. Controllers should invoke interactions not _be_ interactions.

En résumé, Uncle Bob mentionne que pour éviter le couplage, le presenter devrait se refaire de nouveaux objets et les passer à la vue. Martin Fowler nuance un peu le tout en mentionnant que ce n’est pas vrai tout le temps et que cela dépend du contexte.

Le fait de se refaire de nouveaux objets pour la vue peut amener certains problèmes. Exemple, j’ai vu très souvent ce genre de code qui, pour moi, est un beau cas de duplication:

 public ViewObject ConvertObject(BusinessObject objectFromModel)
        {
            var viewObject = new ViewObject() ;
            viewObject.Name = objectFromModel.Name;
            viewObject.Adress = objectFromModel.Adress;
            viewObject.PhoneNumber = objectFromModel.PhoneNumber;
            viewObject.City = objectFromModel.City;

            return viewObject;
        }
    }

Hmm, redondant n’est-ca pas ?

Si les objets sont pratiquement semblables, je suis d’accord avec le point de Martin Fowler et que ce genre d’objets peut être visible au niveau de la vue.

Par contre, s’il y a quelques différences ou des champs non utiles qui sont tout de même transférés à la vue, je crois qu’il vaut mieux y aller avec de nouveaux objets comme le mentionne Uncle Bob.

Bref, la règle à suivre selon moi est de toujours voir selon les besoins du contexte.

Et vous, qu’est-ce que vous faites dans ce cas avec les Business Objects ?

Mon expérience au Code Retreat

IMG_0040

Le 21 mai dernier, moi et deux autres collègues (Félix-Antoine Bourbonnais et Amélie Turgeon) avons organisé le premier Code Retreat à Québec. Tout cela a commencé en début février lorsque le nouveau conseil d’administration de la communauté Agile de Québec s’est réuni.

Lors d’un tour de table, il a été suggéré de tenter d’organiser cet événement. Je trouvais qu’il n’y avait pas assez d’événements de ce genre pour les programmeurs. En particulier des événements qui ne parlent pas de produit d’un vendeur ni d’une technologie particulière. Juste du code orienté-objet sans égards à un langage particulier.

Comme nous n’avions jamais fait ce genre d’événement, il nous fallait un facilitateur de calibre et qui en avait fait beaucoup auparavant: Corey Haines. Ce dernier habite Chicago  et le faire venir ici comporte certains frais, mais rien de trop astronomique. Donc, on s’est rendu compte que c’était possible de le faire venir. Dans notre planification, l’aide des commanditaires serait aussi importante et permettrait de définir le prix d’entrée, le lieu et la nourriture et les rafraichissements servis aux participants durant la journée.

Donc, au fil des mois tout s’est tranquillement mis en place pour réaliser l’événement qui fut un bon succès selon moi. Une grande majorité des participants ont apprécié. On a aussi pu noter certains aspects qui seront à améliorer la prochaine fois que l’on réalisera cet événement. Car nous avons bien l’attention d’en refaire un. Mais avec l’Agile Tour 2011 qui s’en vient cet automne, c’est bien possible que cela ait lieu qu’en 2012.

Aussi, organiser tout cela nous a permis de tester ou d’approfondir certaines technologies qui pourraient nous être utiles dans le futur :

  • WordPress: Nous avons fait un blogue pour contenir toute l’info de l’événement.
  • Eventbrite: Pour la gestion des inscriptions
  • Google Documents: Pour l’échange de documents entre les organisateurs
  • Survey Monkey: Définition et compilation des sondages d’appréciation de l’événement.

Au niveau du contenu de l’événement, j’ai aussi bien adoré. J’ai été surpris du nombre de personnes qui n’avaient jamais vraiment pratiqué le TDD avant. Mais c’est le but de ce genre d’événement, donner du temps pour pratiquer des techniques et langages qu’on n’a pas l’occasion de pratiquer au travail.  L’apport de Corey Haines a aussi été excellent. Cela nous guidera lors des prochains Code Retreat.  Car ce sera nous de jouer le rôle de facilitateurs la prochaine fois. J’ai bien aimé aussi mes différentes sessions de pairage. J’ai pu me remettre au C# (car je fais du VB.Net habituellement), voir un peu de Ruby à l’œuvre et appris quelques trucs ici et là. J’ai aussi montré l’outil Resharper à quelques-uns et du C# à un gars de Java. Bref, it was a blast !

En résumé, je suis bien content de voir qu’à partir d’une idée, et entouré de bonnes personnes, on peut voir un projet se réaliser. Il ne faut pas toujours avoir peur de commencer des choses, mais il faut plutôt oser le faire. On y découvre alors plein de choses…

Références :