Accueil /  Blog / Symfony / Retour sur le SymfonyLive Online French Edition 2021

Retour sur le SymfonyLive Online French Edition 2021

Publié le jeudi 15 avril 2021

Croissant virtuel et chacun son café ! C'est ainsi que démarre l'édition 2021 du Symfony Live Online.

Précisons le pour la postérité mais le contexte sanitaire actuel empêchant les rassemblements physiques nous sommes cette année conviés à suivre cette édition en ligne. Chacun aura son ressenti mais à priori chacun chez soi c'est moins festif. Nous sommes toutefois très reconnaissant aux organisateurs et aux speakers de s'adapter à la situation pour maintenir cet événement.

Je vous propose maintenant de suivre la review de cette journée. Bien entendu vous trouverez ci-dessous un résumé non exhaustif du contenu des conférences. Il va de soi que pour en profiter pleinement il est conseillé de visionner le replay de ces dernières si vous le pouvez.

Matinée

On commence la journée par une courte introduction d'Anne-Sophie Bachelard qui revient sur le format, le planning et les outils à disposition pour permettre les échanges et rencontres entre participants mais aussi exposants et conférenciers. Elle sera par ailleurs l'hôte du track SensioLabs tout au long de la journée.

Keynote d'ouverture - Boring is the new hype (Fabien Potencier)

On ne présente plus Fabien Potencier, mais il nous rappelle cependant qu'il est avant tout un développeur. Il nous propose un retour d'expérience et fait l'analogie entre nos outils et les instruments que l'on peut trouver dans une cuisine.

En effet, la cuisine d'un père de famille ne répond pas aux mêmes besoins que celle d'un grand chef étoilé. Le choix de ces outils dépend de plusieurs critères permettant de définir le contexte du projet tel que le besoin, ses objectifs, les compétences de l'équipe, le client, etc...

Il nous propose donc quelques conseils basés sur son expérience pour choisir ces outils.

Rapidement, je reviendrais sur le fait de ne pas succomber aveuglément à la hype et la nouveauté qui bien qu'attrayantes et stimulantes peuvent manquer de maturité. Les risques étant de se retrouver avec une application difficile à maintenir que ce soit par manque de compétences, manque de documentation. On génère rapidement une grosse dette technique qui nous imposera de réécrire régulièrement le code au fur et à mesure de l'évolution rapide de la technologie. De plus, on trouvera toujours une nouvelle technologie plus attrayante que la précédente. Et pourtant, il n'est pas réaliste de réécrire l'intégralité de son projet tous les 6 mois.

Autre point, les typologies de projet se ressemblent souvent. On pourra donc dans la majorité des cas trouver dans notre bagage technique ou au sein de la communauté des outils répondant à ces besoins. Il ne faut cependant pas se fermer à la nouveauté, mais rester pragmatique.

Dans l'absolu, Fabien conseille donc d'adopter pour des technologies déjà éprouvées, ce qu'il appelle la "philosophie du choix raisonnable". "Une stack limitée et capitalisée" que l'équipe maîtrise sera peut-être moins stimulante mais bien souvent plus productive. Le "risque" étant que nos outils de prédilection tel que Symfony deviennent ennuyeux même si cela reste relatif notamment dans la mesure où le projet aura plus de chance de bien se dérouler et donc d'être plus attrayant qu'un projet accumulant de la dette technique.

La production sera mieux maîtrisée et on gagnera en sérénité. Pour autant, on ne va pas se tourner les pouces. La vie d'une application ne se résume pas qu'à son développement. Une fois en production il faudra continuer de la maintenir.

On en vient donc au dernier point base sur l'expérience acquise avec symfony.com. Fabien conseille de suivre les montées de version et de mettre Symfony à jour tous les 6 mois. Les évolutions seront moins importantes qu'entre deux LTS. La montée de version sera moins impactante donc plus simple et moins chronophage.

Il recommande également de ne pas prendre un bundle ou un package complet quand on a besoin d'une toute petite partie de ce qu'il propose. Il vaut mieux implémenter nous-même ce dont on a besoin, qu'intégrer une dépendance supplémentaire à un outil qu'on ne va pas exploiter.

Fabien définit un boring projet de la manière suivante :

  • PHP/Symfony
  • un minimum de JavaScript
  • PostgreSQL (intégration native d'un système de listener/notifier pour des messages asynchrones avec le composant symfony/messenger)

Il conclut en disant : "Boring is about making safe choices"

Retour rapide : j'adhère complètement à cette philosophie, je nuancerais cependant le fait que toute technologie avant d'être éprouvée a dû faire ses preuves. Bien entendu, le choix de ces dernières devra être mesuré en fonction de la prise de risque qu'elle engage. Il m'est par ailleurs arrivé de démarrer un projet (avec silex par exemple) qui finira en production avant que la librairie ne soit finalement abandonnée et finir par migrer l'application sous Symfony.

Sérialisation adaptée avec API Platform et Symfony (Mathias Arlaud)

Deuxième conférence de la journée, technique cette fois. Présentée par Mathias Arlaud, anciennement développeur chez Sensio et récemment arrivé à Les-Tilleuls‧coop.

Après un rappel du concept de sérialisation à base de normalisation et d'encodage, on prend le cas pratique d'une API de robot Martien. La conférence s'oriente autour de la création d'une API et principalement de la sérialisation des données à l'aide du composant dédié de Symfony et d'API Platform. Nous allons enchaîner les cas pratiques, en suivant le schéma : présentation d'une problématique concrète ainsi que la solution adéquate et l'apport d'API Platform au processus (bien souvent pour simplifier la vie du développeur).

Parmi les cas rencontrés :

  • cas de sérialisation basique
  • comment moduler la donnée sérialisée en fonction du contexte
  • contexte qui peut être déterminé dynamiquement en fonction de la request (ex: rôle d'un utilisateur)
  • l'utilisation des DTO

En résumé, "comment modifier la sérialisation de la ressource en fonction du contexte de restitution et de l'instance de la ressource".

Retour rapide : ayant eu l'occasion de développer plusieurs API avec et sans API Platform, les solutions proposées et certaines nouveautés méritent de s'y intéresser. De plus, si on se réfère aux conseils prodigués par Fabien lors de la keynote, on pourra noter qu'API Platform a déjà quelques heures de vol à son actif.

Comment nous avons tiré parti de symfony/http-client pour construire un nouveau SDK AWS (Jérémy DERUSSÉ)

Pour la conférence suivante, Jérémy DERUSSÉ nous parle du SDK AWS. Son constat est que la Developer eXperience (DX) est désastreuse avec ce SDK pourtant très complet :

  • pas d'autocomplétion
  • code illisible (usage abusif de la méthode __call())
  • méthodes exposant toutes un input de type array $arguments et retournant toutes un output de type array
  • interfaces différenciantes entre le synchrone (sendEmail()) et l'asynchrone (sendEmailAsync())
  • pas d'intégration possible avec la debug bar de Symfony car très peu de points d'accroche disponibles

Pour toutes ces raisons, Symfony ne s'appuyait donc pas sur ce SDK pour ses bridges pourtant nombreux vers les services d'Amazon. À la place, le framework tapait directement sur les endpoints de l'API. L'inconvénient principal étant que cela n'offrait qu'un support basique des services d'Amazon.

Voilà pourquoi la décision a été prise de développer un nouveau SDK fournissant à la fois des fonctionnalités avancées et une DX satisfaisante.

Pour interagir avec les différents services, le choix s'est naturellement porté vers un autre composant développé par Symfony : le symfony/http-client. Ce client HTTP bénéficie de 2 avantages majeurs :

  • il est simple d'utilisation avec une interface fluide
  • il dispose d'une interface unique pour la gestion de l'asynchrone (comportement par défaut) et du synchrone

C'est donc une autre problématique qui a causé des maux de tête aux concepteurs de ce SDK : Amazon propose une foultitude de services, chacun proposant encore plus d'opérations. Ces services et ces opérations sont de plus très régulièrement mis à jour, et de nouveaux services ou opérations sont ajoutés presque quotidiennement. La question s'est donc posée de comment allait-il être possible de maintenir un SDK à jour ?

Heureusement, Amazon fournit dans son SDK un énorme fichier JSON recensant tous les services et leurs opérations, tous les inputs et les outputs, leurs types, les exceptions attendues... Une sorte de Swagger donc. L'équipe a donc développé un transformer prenant ce fichier en entrée et générant en sortie un ensemble de classes propres constituant le SDK.

Ce SDK est donc :

  • compatible avec les services Amazon puisque basé sur un Single Point of Thruth fourni par Amazon et utilisé par leur propre SDK
  • constitué d'un code lisible par un humain et par un IDE (autocomplétion)
  • constitué d'un code généré quotidiennement par un robot (GitHub action) à partir du fichier JSON et qui pousse les modifications automatiquement dans les repositories du SDK

Outre ces avantages, le SDK améliore la DX en proposant des interfaces simples (une seule méthode sendEmail() plutôt qu'une méthode sendEmail() et une autre sendEmailAsync() par exemple). La compatibilité avec tous les services d'Amazon permet également un usage bien plus avancé que ce qui était jusqu'alors proposé par les bridges Symfony.

Enfin, l'utilisation du client HTTP de Symfony permet comme évoqué précédemment de passer très facilement du mode asynchrone au mode synchrone. Par défaut, les requêtes (et les réponses) sont exécutées (et reçues) de manière asynchrone. Cela permet donc de reprendre la main et d'éviter d'avoir des appels bloquants potentiellement longs. Pour autant, dès qu'on demande un élément de la réponse, le client repasse en mode synchrone (bloquant) et retourne l'élément dès que possible. Le client HTTP de Symfony permet également d'exécuter des requêtes en parallèle (grâce à son caractère asynchrone), ou de rejouer automatiquement des requêtes en cas d'échec selon une stratégie définie, et ce de manière simple et transparente à travers la même interface unifiée que précédemment.

Comment éviter les écueils les plus classique en équipe Agile (Marianne Joseph-Gehannin)

Dernière conférence de la matinée. Marianne a pour défi de nous garder concentrés alors que nos estomacs commencent à crier famine. Les croissants virtuels n'étaient pas assez nourrissants ^^' Pour ce faire, elle se propose de nous partager son expérience sur des difficultés que nombre d'entre nous ont sûrement rencontrées lors de l'adoption de méthode Agile.

On va parler des tensions au sein de l'équipe (lors des premières code review par exemple), des difficultés à sizer. Des échanges avec le client notamment lors de la lecture des US parfois incomplètes avec le PO, parfois soumises à débat, ou pouvant nécessiter des compétences encore non acquises. Mais aussi de la perte d'information suite au départ d'un développeur, à l'absence de documentation ou de couverture de tests. Et pour finir quelques sujets délicats comme l'ego parfois incompatible avec la notion d'équipe ou la réticence au changement, qu'elle provienne de l'équipe ou de la hiérarchie. Il faut garder à l'esprit qu'un projet s’inscrit dans un contexte réaliste soumis à un budget, à des délais et d'autres événements imprévus.

Pour chacun de ces points, elle nous propose une mise en situation par l'intermédiaire d'une courte animation. Un état des lieux de comment l'équipe en est arrivée là. Une explication de pourquoi ces points sont néfastes pour le projet et pour l'équipe. Et enfin un ensemble de solutions qu'elle a pu éprouver au fil de son parcours.

Retour rapide : nous avons aussi adopté les méthodes agiles depuis quelques années chez Prestaconcept. Et nous avons bien entendu rencontré ce genre de difficultés. Avec à chaque fois des variantes, en fonction de l'équipe projet, du client, des spécificités ou encore du besoin. Mais finalement il est assez rassurant de voir que nous n'avons pas été les seuls et que nous avons adopté progressivement des solutions similaires.

Après-midi

Pied au plancher avec Symfony Turbo (Kévin Dunglas)

On démarre l'après-midi avec une conférence de Kévin Dunglas qui nous présente Symfony Turbo.

Cette conférence va tenter de répondre à une question : "A-t-on encore besoin de JavaScript ?"

D'abord, Hotwire. Il se présente comme un framework JavaScript minimaliste qui a l'ambition de fournir l'expérience utilisateur d'une Single Page App sans avoir besoin d'écrire de JavaScript. Contrairement à la majorité des frameworks actuels, il fonctionne en rendant des fragments de HTML plutôt que des payloads JSON.

Hotwire est composé de 3 briques :

  • Turbo : le coeur de Hotwire chargé de rendre des fragments de HTML
  • Stimulus : permet d'écrire un peu de JavaScript de base (20 % des cas d'utilisation) pour enrichir l'UX
  • strada : support application mobile

Intéressons nous maintenant à la brique Turbo qui donne son titre à la conférence :

Il se compose de :

  • Turbo Drive : automatiquement activé, il intègre Turbo à Symfony via Symfony UX. Il permet d'accélérer la navigation en évitant le rechargement complet de la page, utilise le history‧pushState du navigateur pour améliorer la navigation, évite les flashs blancs en chargeant la page progressivement et en affichant une progress bar si ce processus prend trop de temps, écoute les interactions de l'utilisateur avec la page (clics, soumission de formulaires, etc...). Le tout sans avoir à écrire aucun code. La seule contrainte consiste à retourner un code 40X en cas d'erreur de validation d'un formulaire dans la réponse Symfony (une méthode renderForm() a été introduite dans Symfony 5.3).
  • Turbo Frames : il permet de décomposer la page en blocs indépendants à la manière des composants React pour isoler certains contenus et permettre de faire du lazy load ou de les mettre en cache.
  • Turbo Streams : il permet d'intégrer la notion de temps réel dans Turbo en gérant la connexion persistante à un serveur via Mercure (sur Symfony par défaut) ou Websocket.
  • Turbo Native : il permet de transpiler l'application pour l'intégrer dans une application mobile native sous forme de webview.

Concrètement, Symfony Turbo permet de se rapprocher de ce qu'on fait en Vue.JS, en React, mais avec nos outils habituels tels que Symfony et Twig.

A utiliser en fonction des use case :

  • pour un site classique sans code lourd côté client : Symfony UX Turbo répond au besoin et simplifie la stack tout en améliorant l'expérience utilisateur
  • webapps, (offline-first, temps réel consommé par le client géoloc) : continuer d'utiliser les outils existants (Next‧js, Nuxt‧js, React Native)

Des trésors cachés dans Symfony (Nicolas Grekas)

Une conférence fort intéressante présentant nombre de features ajoutées au composant de Symfony au fil des versions. Cependant cette dernière étant constituée d'une énumération assez dense et entièrement technique, il est difficile de proposer un résumé sans paraphraser.

Si le sujet vous intéresse, je vous renvoie vers le replay de la conférence mais sachez toutefois que parmi les sujets traités on retrouve :

  • le kernel
  • l'injection de dépendances
    • named autowiring aliases
    • service locators and iterators (référencer les services taggués et les indexés)
    • autoconfigure (ajouter des tags sur les classes implémentant une interface)
    • Env Var Processors (4.3 : require, trim, default, url - 4.4 : EnvVarLoaderInterface)
  • composant console
  • VarDumper
  • HttpClient (4.4 : Async HTTPlug client, 5.2 : mettre en pause une réponse)
  • translation (5.2: pseudo localization translator)
  • validation (automatic constraint)
  • et enfin quelques features en vrac (VarExporter, debugging flex apps, command debug: etc...)

Retour rapide: pour cette conférence, je vais reprendre les derniers mots de Nicolas : "15 ans de Symfony, drivé par les contributions".

Démarrer avec Symfony UX (Titouan Galopin)

Symfony UX est une initiative pour rallier le camp des applications traditionnelles construites en HTML + CSS + JavaScript et comprenant beaucoup de logique serveur, et celui des Single Page Apps qui comprend beaucoup de logique serveur pour fabriquer le HTML de la page à partir de JavaScript.

Face à ce changement de paradigme, les SPA ont dû réinventer beaucoup de choses, ce qui a conduit à l'apparition de frameworks tels que React ou Vue.JS. Cependant, les SPA sont longues et difficiles à développer et engendrent bien souvent de petits bugs nuisant à l'expérience utilisateur. Symfony UX ambitionne de conserver l'expérience utilisateur des SPA mais en cachant leur complexité derrière une couche "Symfony like".

Symfony UX exploite plusieurs composants :

  • Webpack : un bundler (prend le code et le combine en un seul fichier pour la performance)
  • Symfony Webpack Encore : facilite l'intégration de Webpack dans Symfony
  • Stimulus : framework modeste qui vient enrichir le HTML fabriqué par le serveur en augmentant ses fonctionnalités pour améliorer l'expérience utilisateur

Revenons sur les principes de bases :

  • Les controllers : un contrôleur Stimulus est une classe JavaScript associée à un noeud (tag) HTML.
  • Les targets permettent d'accéder à d'autres noeuds HTML à l'intérieur du noeud principal.
  • Les actions permettent de configurer comment réagir à certains événements sur les noeuds
  • Les values enfin sont là pour stocker des données dans le HTML. Typiquement elles permettent d'exposer des données depuis l'application Symfony vers l'application Stimulus à l'initialisation de la page, ou de stocker un état, ce qui est pratique pour partager des données entre les contrôleurs.

La présentation était illustrée par un projet de démo : une application Symfony traditionnelle dans un premier temps puis l'enrichissement de l'application avec UX.

Pour conclure, Symfony UX est un lien entre Symfony, Stimulus et des packages PHP (intègre automatiquement les contrôleurs JavaScript des packages importés grâce à Symfony Flex). Symfony UX dropzone est cité comme exemple mais de nouveaux packages sont prévus.

Retour rapide : au vu des réactions dans le chat, on note pas mal d'attente quant à ce composant même s'il semble faire débat. L'impression que j'ai, c'est que pour l'instant cela semble être une bonne solution pour remplacer certains frameworks tels que Vue‧js mais cela ne remplace pas une solution Angular ou React pour une SPA. Tout dépend des besoins du projet. Le projet étant assez récent, il y a encore assez peu de retour d'expérience sur le sujet mais à surveiller ou essayer si l'occasion se présente.

The New Testing Landscape: Panther, Foundry & More (Ryan Weaver)

Enchaînons avec la dernière conférence de la journée. Ryan Weaver nous parle de tests au cours d'une présentation découpé en plusieurs parties que nous allons reprendre.

Partie 1 - Rappel des 3 types de tests

  • tests unitaires : aucune interaction avec Symfony, il s'agit juste de tester nos classes
  • tests d'intégration : tests liés au Kernel de Symfony, on utilise les vrais services depuis le container
  • tests fonctionnels : test des pages/endpoints en utilisant l'intégralité de l'application Symfony

Partie 2 - Quel package pour PHPUnit ?

Il y a 2 manières d'installer PHPUnit : soit de manière "pure" (composer require phpunit/phpunit --dev), soit avec le bridge Symfony (composer require phpunit --dev).

Le bridge Symfony venant enrichir phpunit avec les fonctionnalités suivantes :

  • affichage des dépréciations (mais on peut le faire aussi sans ce bridge)
  • mock les dates (mais on peut le faire aussi sans ce bridge)
  • lancer les tests unitaires avec des versions différentes de PHPUnit
  • sépare les dépendances de PHPUnit des dépendances du projet, ce qui évite des conflits en cas de montée de version incompatible (mais PHPUnit n'a désormais plus que très peu de dépendances, il est donc très peu probable de rencontrer ce genre de conflits de nos jours)

Ryan nous conseille donc d'utiliser PHPUnit pur, le bridge et ses fonctionnalités apportant finalement peu de plus-value.

Partie 3 - Tests unitaires

Rien de très exotique ici, on teste une classe PHP (pas de Symfony, pas de container)

Partie 4 - Tests d'intégration

Le kernel fournit un container spécial qui rend tous les services publiques afin qu'on puisse y accéder dans nos tests. La seule spécificité consiste à tester les repositories. Il faut configurer l'application pour accéder à une base de données différente de la base de développement. Il faut aussi charger un jeu de données spécifique pour nos tests. Ryan recommande l'utilisation de zenstruck/foundry : ce package permet de facilement réinitialiser la base de données avant chaque test grâce à un trait, et de créer des entités en PHP dont les données peuvent être simulées avec faker avant d'être enregistrées dans la base de test.

Partie 5 - Tests fonctionnels (sans JavaScript)

Ce type de tests n'utilise pas de navigateur : ils exécutent directement l'application Symfony et vont parser la réponse (code HTTP, contenu HTML...) pour effectuer les assertions.

Partie 6 - Tests fonctionnels (avec JavaScript) en utilisant Panther

Ce type de tests utilise un navigateur "headless" comme Chrome ou Firefox. Il faut donc disposer d'un driver pour ce navigateur. Ryan suggère l'installation du package "dbrekelmans/bdi" qui contient les drivers pour Chrome et Firefox. Le client Panther a la même API que le client classique, ce qui facilite son utilisation, voire la migration d'un test classique vers un test Panther. Il permet de prendre des captures d'écrans automatiquement en cas d'échec du test, mais aussi d'utiliser un vrai navigateur pour débugguer plus facilement, voire de geler le navigateur dans l'état où il était au moment où le bug est survenu.

Attention : le test s'exécutant dans un navigateur, il utilisera le fichier .env par défaut de votre projet, et ne s'exécutera donc probablement pas sur la base de données de test. Il faut donc créer un fichier .env‧panther basé sur le fichier .env‧test mais contenant la variable d'environnement APP_ENV=panther en attendant que l'équipe de développement simplifie ce cas d'usage. Il ne faut pas non plus oublier d'attendre que les éléments chargés de manière asynchrone aient fini de s'afficher pour effectuer nos assertions. Cela peut se faire grâce à la méthode waitForElementToContain().

Partie 7 - Pour aller plus loin

Ryan suggère d'utiliser le package zenstruck/browser pour disposer d'une API plus fluide que celle du client de test de Symfony. En plus de prendre une capture d'écran en cas d'échec, ce package permet de dump le code HTML exécuté au moment de l'échec ainsi que les erreurs de la console JavaScript du navigateur. Enfin il permet l'usage du composant "symfony/var-dumper" en mode test.

Partie 8 - Paratest

Enfin, Ryan suggère de paralléliser l'exécution des tests. Cela permet de gagner du temps pour jouer des suites de tests longues à exécuter. Il suggère l'utilisation du package "brianium/paratest". Il faut toutefois bien penser à configurer la variable d'environnement DATABASE_URL="mysql://root@127.0.0.1:3306/app_${TEST_TOKEN}" avec le paramètre ${TEST_TOKEN} pour permettre à chaque processus d'avoir sa propre base de données et d'éviter que les tests écrasent leurs données en s'exécutant en parallèle. De même, en cas d'écriture sur le système de fichier, il faudra utiliser un système d'abstraction tel que Flysystem configuré de manière à écrire dans des emplacements différent sur le disque pour chaque processus qui s'exécute en parallèle.

Pour conclure, Ryan nous conseille sa stack de test en 2021

  • utiliser phpunit/phpunit directement
  • utiliser zenstruck/foundry pour la gestion des jeux de données
  • utiliser symfony/panther et zenstruck/browser pour écrire ses tests fonctionnels

Retour rapide : une conférence technique très concrète. Ryan revient sur la notion de tests. L'objectif de chacun, la mise en œuvre, les problèmes rencontrés et nous apporte un ensemble de solution qu'il a pu expérimenté. Le tout supporté par une démo reprenant chaque étape. Pour avoir rencontré la majorité des problèmes énoncés durant cette conférence, certain étant toujours d'actualité, j'ai bien pris note des solutions et outils proposés pour de prochaines expérimentations.

Clôture

L'événement se termine par un petit mot d'Anne-Sophie suite à la conférence de Ryan ma foi assez bavard lors d'une session de questions/réponses passionnantes. La journée fut riche en découvertes et en informations ouvrant la porte à pas mal d'investigations dans les mois à venir.

Si je devais résumer ce Symfony Live en quelques mots je dirais :

  • du pragmatisme dans l'adoption des nouvelles technologies
  • des retours d'expériences qui confirment certains de nos choix et/ou proposent un autre point de vue et de nouvelles pistes
  • Symfony a une base solide mais ne se repose pas sur ses lauriers, de nouveaux composants arrivent afin de répondre à nos besoins (comme Symfony UX)

J'ajouterais que d'autres activités étaient disponibles en marge des conférences comme dans n'importe quel événement physique, notamment la présence de stands virtuels tenus par les sponsors proposant des démos de produits ou simplement pour échanger.

Pour finir, j'étais assez curieux quant à ce format "online" qui s'est avéré finalement plus interactif que je ne le pensais. Loin d'être de simples spectateurs, les participants ont pu interagir pendant la conférence entre eux mais aussi avec le conférencier. Ce qui me semble difficilement compatible avec une conférence "physique". Ces échanges via le chat ont rendu l'événement bien vivant.

Suivez notre actualité en avant première. Pas plus d’une newsletter par mois.