Le blog

AFUP Day Lyon 2024 : notre retour sur les conférences

Publié le 27 mai 2024

Vendredi dernier, nous avons participé à l'AFUP Day, le cycle de conférences printanier de l'AFUP, l'association francophone des utilisateurs et utilisatrices de PHP, à laquelle nous sommes adhérents et bénévoles de longue date. Cette journée de talk se déroulait dans 4 villes de France : Lille (le compte-rendu arrive cette semaine !), Nancy, Poitiers et Lyon. Cet article résume les conférences de l'AFUP Day Lyon, qui accueillait plus de 250 personnes à la CPE.

#

Attributs en PHP : un regard rétrospectif de la magie à l'adoption par Kevin Balicot

Dans sa conférence, Kevin Balicot revient sur l'évolution des attributs en PHP. Alors que la plupart des langages de programmation les ont intégrés il y a des années, voire dès leur création, l'intégration native des attributs en PHP est relativement récente, datant de la version 8.0.

Avant l'arrivée des attributs natifs, depuis 2013, les développeurs PHP utilisaient la bibliothèque doctrine/annotations, maintenue par Doctrine. Cette bibliothèque a été largement adoptée par les utilisateurs de Symfony pour ajouter des métadonnées au code source. Par exemple, elle permettait de configurer le mapping des entités directement dans les classes PHP. Les annotations étaient basées sur des blocs de commentaires PHPDoc, récupérés via l'API Reflection de PHP et parsés grâce à doctrine/lexer pour instancier des classes spécifiques avec d'éventuels arguments.

Avec PHP 8.0, la gestion des attributs est devenue native, permettant d'ajouter des métadonnées aux classes, propriétés, méthodes ou constantes. Ces attributs sont paramétrables et peuvent accepter des arguments nommés ou positionnels, des constantes ou même des instances d'objets. La gestion native des attributs évite la phase de parsing des chaînes de caractères et est mieux supportée par les IDE.
Depuis la version 8.x, PHP continue d'ajouter de nouveaux attributs natifs, et ce n'est que le début.

Symfony a rapidement adopté cette nouveauté et propose désormais aux développeurs pas moins de 48 attributs, simplifiant la configuration manuelle des services, remplaçant les anciennes annotations Doctrine, et ajoutant des comportements spécifiques selon les environnements.

Kevin présente deux applications concrètes de création d'attributs personnalisés :

  • Gestion de features flags pour activer ou désactiver des méthodes.
  • Création d'un profiler pour analyser les performances et comportements du code.

Cependant, il rappelle qu'un attribut ne doit pas devenir une dépendance forte et qu'il ne doit pas créer un couplage indésirable dans le code. Il faut également être vigilant aux traitements lourds exécutés au runtime, comme dans un listener, pour ne pas impacter les performances.

L'intégration des attributs natifs en PHP ouvre de nouvelles possibilités pour les développeurs, tout en améliorant la lisibilité et la maintenabilité du code. Symfony, en adoptant ces nouveautés, facilite encore davantage le travail des développeurs en fournissant des outils puissants et flexibles.

#

À la Recherche des Trésors Cachés de PostgreSQL par Lætitia Avrot

Voilà le genre de conférences où l'on découvre une multitude de fonctionnalités utiles pour le quotidien des développeurs, qu'on les connaisse déjà ou non. Lætitia AVROT est claire : son objectif n'est pas que l'on retienne tout ce qu'elle présente, mais que l'on sache que ces fonctionnalités existent, et que l'on pense à consulter la documentation lorsqu'un besoin spécifique se présente dans le contexte de bases de données PostgreSQL.

Souvent, les développeurs ont tendance à réaliser des développements PHP complexes et lourds là où le système de gestion de bases de données (SGBD) peut effectuer des opérations de manière beaucoup plus performante.

Laetitia nous offre une série d'exemples concrets et pratiques, notamment :

  • Utilisation des transactions : pour garantir l'intégrité des opérations.
  • Ajout de commentaires sur tout type d’éléments SQL : pour améliorer la lisibilité et la maintenance du code.
  • Index spécialisés : pour optimiser les requêtes et améliorer les performances.
  • Foreign Data Wrappers (FDW) : pour interroger n’importe quelle source de données (CSV, LDAP, Oracle, ou même une source personnalisée) comme si c’était une table SQL.
  • Merges et Common Table Expressions (CTE) : pour des opérations de manipulation de données avancées.

Laetitia aborde également des erreurs fréquentes, telles que l'échappement de texte et la recherche de texte avec ou sans sensibilité à la casse, avec ou sans expressions régulières.

PostgreSQL est un SGBD vivant et en constante évolution, avec de nouvelles fonctionnalités souvent ajoutées dans les versions majeures, parfois en avance sur le support du standard SQL. C'est le cas, par exemple, de la gestion des types de données complexes comme JSON, de leurs opérateurs spéciaux, mais aussi des fonctionnalités à venir comme JSON Path et JSON tables.

Cette présentation offre un tour d’horizon sympathique et instructif de la puissance de PostgreSQL, même si certaines fonctionnalités ne sont pas toujours exploitables à travers l'ORM Doctrine, ce qui est un autre débat…
Laetitia nous rappelle l'importance de connaître et d'exploiter les capacités avancées de PostgreSQL pour des développements plus efficaces et performants.

#

Rôles & permissions : comment développer une marque blanche avec du Feature Flipping par Florian Bogey

Première conférence donnée par Florian Bogey, et c'est une mission réussie ! Florian a partagé un retour d'expérience intéressant sur la façon dont GL Events a dû adapter son extranet pour répondre à des besoins complexes, notamment en adaptant son application à un usage en marque blanche, avec des fonctionnalités différentes et d'autres spécificités.

Florian commence par clarifier la distinction entre les rôles et les permissions. Les rôles sont des groupes attribués à un utilisateur pour définir ses droits de manière statique, regroupant les utilisateurs ayant le même niveau d'autorisation. En revanche, les permissions sont des règles métier spécifiques qui déterminent dynamiquement si un utilisateur peut effectuer une action donnée sur une ressource précise. Ces deux concepts sont complémentaires et permettent ensemble de fournir un contrôle d'accès fin et granulaire.

Symfony offre plusieurs outils pour implémenter ces concepts, notamment les contrôles d'accès, la hiérarchie de rôles, les attributs ou méthodes "isGranted" / “is_granted”, ainsi que les Voters.

GL Events a opté pour une architecture multi-tenant : une seule instance pour différents clients, sur le même hébergement et la même base de données. Cette approche nécessite une isolation rigoureuse des données et une sécurisation stricte des accès. Ils utilisent pour cela une variable d'environnement fournie par le serveur web en fonction du nom de domaine cible pour définir un fichier .env spécifique à chaque site. Cette variable pilote la personnalisation de nombreux éléments dans Symfony : logo, style, nom, favicon et diverses variables.
Ces variables peuvent être utilisées directement dans les services ou les templates Twig pour adapter le rendu.

Pour la gestion du feature flipping, GL Events a développé une solution maison, permettant un contrôle fin en fonction de l'utilisateur, du contexte et de la marque blanche. Ils utilisent les permissions pour une gestion dynamique, avec les Voters et une association des actions aux utilisateurs dans la base de données, le tout administré via un back-office avec un CRUD.

Pour les performances, Florian rappelle l'importance d'avoir des requêtes simples et la possibilité de mettre en cache les calculs, par exemple via Redis, notamment pour les calculs partagés. Leur mise en place nécessite une discipline et une rigueur accrues da

Florian conclut en soulignant l'importance de la rigueur et de la discipline dans le développement, particulièrement dans un environnement multi-tenant complexe.

#

Au-delà des heures : la semaine de 4 jours comme levier d’égalité par Albane Veyron

Albane Veyron est coach professionnelle et travaille chez IDEME, une agence de conseil en engagement et tech. Elle revient sur la semaine de 4 jours, à ne pas confondre avec un contrat au 4/5ème. Ce type d’organisation, qui est une dynamique mondiale, signifie diminuer le temps de travail tout en gardant un salaire complet. Elle nous partage aussi quelques statistiques sur ce format mis en place dans quelques pays comme le Royaume-Uni (épuisement professionnel en baisse de 71%, stress en baisse de 31% sur l’échantillon d’entreprises qui l’appliquent).

Qu'est-ce que la semaine de 4 jours peut nous apporter ?

  1.  D’un point de vue perso  

Un équilibre de vie, du temps pour soi. Une coupure la semaine permet de se décharger des tâches que l’on fait habituellement le week-end. On note aussi un impact positif pour la santé physique, et une chute des arrêts maladie de 65%, et une facilité d’organisation personnelle (rendez-vous médicaux, etc).

  1. Une réduction des inégalités 

Égalité de genre et vie familiale. Lorsqu’une femme devient mère, plus d’une sur quatre passe à la semaine de 4 jours, mais pas en travaillant moins : elle perd car son salaire baisse. La semaine de 4 jours permet aussi une meilleure répartition des tâches et peut donner l’opportunité de réduire ces inégalités. 

  1. Un impact à grande échelle

La semaine de quatre jours est bénéfique pour l’environnement (moins de déplacements véhiculés) mais aussi d’un point de vue social (bénévolat, accès à des études additionnelles, accès à la propriété immobilière, apprentissage de la langue française…)

Et si tout le monde avait à y gagner ? En termes d’employabilité, la semaine de 4 jours permet une diminution du turnover de 57% tout en gardant une productivité effective.

En France, on compte près de 8000 entreprises qui sont passées à la semaine de 4 jours. Pour mettre cela en place, il faut d’abord faire une évaluation des besoins et des possibilités, savoir communiquer avec les personnes avec qui on a travaillé. Un accompagnement à la co-construction est nécessaire, et surtout c’est un format qui reste adaptable. Albane conclut sa conférence en nous mentionnant et expliquant qu’il existe plein de formes de flexibilité pour conduire à un bien être au travail.

#

Et donc du coup, j'ai voulu rendre le Serializer de Symfony plus rapide par Mathias Arlaud

Mathias Arlaud nous confie que les événements sont avant tout pour lui une occasion de discuter avec d'autres contributeurs et d'enrichir ses développements pour l'open source. Et aujourd’hui il veut nous parler du composant Serializer de Symfony, qui, bien que performant, présente des lenteurs, notamment lorsqu'il est utilisé conjointement avec Doctrine.

Il commence par rappeler ce qu'est la sérialisation et la normalisation, ainsi que les différents formats de représentation après transformation des flux de données. Il présente le composant PropertyInfo de Symfony, qui permet d'obtenir des informations sur les propriétés des classes en utilisant diverses sources de métadonnées. Ce composant aide à mieux comprendre et traiter les données en fournissant des informations sur le type de données et leur visibilité.

Cependant, PropertyInfo a ses limites. Pour aller plus loin, un nouveau composant TypeInfo, vient d'être introduit en expérimental dans Symfony 7.1. Ce composant améliore la gestion des métadonnées et est conçu pour évoluer, levant ainsi certaines des limitations actuelles.

Le composant Serializer, malgré les optimisations et l'utilisation du cache, présente des limites intrinsèques, notamment en termes de performance lorsqu'il utilise l'API Reflection, ce qui est particulièrement problématique pour les grandes collections d'objets. Une des solutions explorées est le streaming JSON, qui est incompatible avec les tableaux de PHP. Pour pallier cela, une pull request sur un composant JsonEncoder est en cours de développement. 

Ce composant, grâce à TypeInfo, peut connaître la structure du JSON sérialisé et écrire progressivement (streaming) dans le JSON final en parcourant une collection.

L'avantage de cet encodeur réside dans la réutilisation de calculs pour transformer un objet en JSON, une fois que cela a été fait pour un autre objet de la même classe. Il permet non seulement d'améliorer les performances, mais aussi d'apporter des fonctionnalités supplémentaires comme la lecture des types génériques et le streaming en lecture/écriture.

L'utilisation conjointe avec des mappers, comme celui d'Antoine Bluchet (PR en cours) ou encore l'automapper de Jolicode, permet de résoudre les problèmes de transformation des données lors de la sérialisation. Ces mappers facilitent le renommage des propriétés, la mise à jour des valeurs et leur transformation.

En bref, beaucoup de belles choses en perspective ! Les idées sont posées, les développements bien entamés, voire en phase de maturité, cela promet de belles évolutions dans les prochaines versions de Symfony et souligne également l'importance de la contribution à l'open source pour l'évolution de nos outils du quotidien !

#

Composer 101 : Gérer Efficacement ses Dépendances PHP par Alexandre Daubois

Alexandre nous propose un tour d’horizon de Composer, un outil essentiel pour gérer les dépendances, leurs versions, les mises à jour et la cohérence des paquets dans les projets PHP. Depuis sa création, Composer s'est imposé comme un standard incontournable, grâce à sa configuration simple et sa gestion efficace et rapide.

Alexandre commence par rappeler les commandes de base de Composer :

  • require : ajouter une nouvelle dépendance au projet
  • install : installer toutes les dépendances listées dans le fichier composer.json
  • update : mettre à jour les dépendances vers leurs versions les plus récentes compatibles avec les contraintes définies

Ces commandes permettent de gérer facilement les dépendances et de maintenir la cohérence du projet.

Composer ne se contente pas de gérer les paquets de votre projet, il s'assure également que la version de PHP et les extensions PHP requises sont installées.

Bien que Composer ne puisse pas encore installer des extensions PHP, une initiative intéressante, PIE (PHP Installation Environment), a été lancée par la PHP Foundation. Cette initiative vise à combler cette lacune et pourrait grandement simplifier la gestion des extensions à l'avenir.

Outre les commandes de base, Alexandre présente quelques commandes moins connues mais tout aussi utiles :

  • bump : augmenter la version d’un paquet
  • audit : vérifier les dépendances du projet pour détecter les vulnérabilités de sécurité connues
  • status : afficher l'état actuel des dépendances et des modifications éventuelles des vendors

Composer utilise le versionnage sémantique (SemVer) pour gérer les versions des paquets, ce qui permet une gestion claire et prévisible des versions. Les flags de stabilité, comme dev, alpha, beta, RC, et stable, permettent de contrôler la stabilité des versions installées. De plus, Composer peut utiliser des SHA de branches GIT pour pointer vers des versions spécifiques de dépendances en développement.

Alexandre rappelle que Composer est également responsable de la génération du fichier d’autoloading, un atout important du bon fonctionnement des projets PHP. Composer peut générer un fichier d'autoload optimisé pour améliorer les performances, et plusieurs niveaux de configuration sont disponibles pour ajuster ce processus selon les besoins du projet.

Une chouette présentation de cet outil puissant qui a bien changé la manière dont les développeurs PHP gèrent les dépendances.

#

Plongée dans l’injection de dépendances par Florian Merle

Lors de cette conférence, Florian Merle nous emmène sur un fond d’histoire de roadtrip en moto à travers la Suisse avec son ami, pour nous parler de l'injection de dépendances et du développement d'un conteneur maison. Son objectif n’est pas de proposer une solution pour la production, mais de plonger dans le code et de démystifier le fonctionnement des conteneurs de dépendances.

Florian commence par rappeler qu’un conteneur de dépendances répond à une interface standardisée par la PSR-11. Cette interface définit deux méthodes publiques essentielles :

  • get : Pour obtenir un service à partir de son identifiant
  • has : Pour vérifier si un service est disponible dans le conteneur.

Chaque service dans un conteneur est identifié par une chaîne de caractères, ce qui permet de les référencer facilement.

Au fil de sa conférence, Florian guide l'audience à travers la création d'un conteneur très simple, qu'il complexifie progressivement pour inclure des fonctionnalités supplémentaires :

  1. Gestion des services
  2. Configuration des paramètres de configuration dans le conteneur
  3. Implémentation de l'autowiring pour résoudre automatiquement les dépendances en instanciant les services requis

Florian illustre l'usage pratique de la résolution de dépendances avec deux exemples concrets avec la résolution de dépendances d’une collection d’interfaces (tagged iterators) dans un pattern de chaîne de responsabilité. Puis avec l’implémentation de la résolution du service @.inner, dans un cas de décoration de services pour ajouter ou modifier des comportements.

Alors bien sûr ce conteneur est encore loin de celui d’un conteneur complet comme celui de Symfony, qui gère bien d’autres fonctionnalités de manière plus efficace, mais ce type de projet est une excellente école pour comprendre les fonctionnalités de base de la résolution et de l'injection de dépendances. 

Cela permet aux devs de mieux appréhender les concepts fondamentaux et d'apprécier les complexités gérées par des frameworks plus robustes comme Symfony.

#

DDD !== Archi hexagonale par Benoit Galati

Benoît Galati nous présente une exploration du Domain-Driven Design (DDD) et de l'architecture hexagonale, clarifiant ce que sont ces concepts et insistant sur le fait qu'ils ne vont pas nécessairement de pair.

L'architecture hexagonale (Ports et Adapters), est une approche de conception qui sépare le cœur applicatif des interfaces externes grâce à l'inversion de dépendances. 

L'application ne doit pas dépendre des détails d'implémentation des interfaces externes. Bien que cette architecture puisse être plus complexe à mettre en place, elle offre une flexibilité accrue et fonctionne bien avec le DDD, car elle permet une meilleure isolation et se concentre sur le domaine métier.

Le DDD de son côté est une approche neutre en termes d'architecture, se concentrant sur la modélisation du domaine métier et la gestion de la complexité des domaines complexes. Il définit le modèle de domaine en alignement avec le business de l'entreprise, sans imposer de structure architecturale spécifique.

Benoît rappelle les concepts fondamentaux de l'architecture hexagonale et du DDD, en passant en revue les différents termes et principes de chacun. Il explique notamment les différences du DDD entre

  • les patterns stratégiques : concernent la vision d'ensemble de l'organisation du domaine, comme les bounded contexts et les relations entre eux
  • les patterns tactiques : aident à exprimer le métier de façon technique (Entités, Value Objects, Services, Agrégats, Repositories…)

Benoît explique que bien que DDD et l'architecture hexagonale se complètent bien, ils peuvent fonctionner indépendamment l'un de l'autre. Le DDD se concentre sur la modélisation et la compréhension du domaine métier, tandis que l'architecture hexagonale se concentre sur la structuration du code pour isoler le domaine métier des dépendances techniques.

Pour illustrer ses propos, il présente des exemples de code d'une petite application développée d’abord un utilisant uniquement le DDD, puis en utilisant uniquement une architecture hexagonale sans DDD, et enfin en combinant le DDD et l’architecture hexagonale.

#

Recettes de découplage équilibré avec Symfony par Robin Chalas

En clôture de l'AFUP Day Lyon, et dans la suite de la conférence sur le DDD, Robin Chalas aborde la notion de couplage d’une application et de ses composants. Sans se focaliser sur le DDD ou une quelconque architecture, il partage son expérience et ses conseils sur les problèmes récurrents de code. 

Pour lui, l’absence totale de couplage n’est pas toujours pertinente, mais veiller à certaines isolations de code facilite la maintenance, la compréhension et les mises à jour ou changements de bibliothèque. Voici ce que nous retenons :

#
Favoriser les contrôleurs à action unique
  • Un contrôleur = un use case
  • Cela facilite la lecture du code et rend les intentions claires
#
Déclarer les dépendances explicitement
  • N’injecter que ce dont le contrôleur a besoin
  • Cela permet de connaître rapidement les capacités d’une classe en fonction des services injectés
  • Parfois, il vaut mieux dupliquer du code que d’avoir un code non lisible et difficile à déchiffrer
#
Ne pas étendre AbstractController systématiquement dans Symfony
  • Il masque les dépendances, obscurcit le scope et favorise un couplage fort avec Symfony
  • Symfony lui-même revient sur cette recommandation petit à petit
#
Séparer la logique métier de l’infrastructure, un des premiers enjeux de découplage
  • controller, console command, forms… => point d’entrée de l’application = infra
  • entités = domain = coeur du métier
#
Utiliser des DTO : Ne pas attaquer le domaine depuis l’infrastructure, ne pas hésiter à abuser des DTO
  • Utilisation de l’attribut MapRequestPayload qui permet d’hydrater automatiquement un DTO en fonction de la requête
  • Les DTO fonctionnent partout et n’ajoutent pas de couplage
  • Ils contiennent de la donnée “sale” et évitent de manipuler des tableaux
  • Les entités sont la source de vérité du système et ne doivent pas être “tordues”. Mapper les formulaires avec des DTO et non avec les entités.
#
Faire des applications services + DTO : Les traitements métier appartiennent au domaine et ne doivent pas être gérés dans le code du contrôleur.
  • Les services font le pont entre l’infrastructure et le domaine. 
  • Éviter un service magique qui fait tout (ex. “manager”).
#
Envisager le pattern command (sans aller jusque CQRS), structure bien le code autour des use cases
  • La commande est un impératif, à l’origine d’une requête utilisateur
  • Elle porte la donnée qui sert à traiter un use case pour impacter l’état du système
  • 1 use case = 1 command + handler
  • Utilisation de Symfony Messenger pour coupler automatiquement la Commande et son Handler
  • Ajout du HandleTrait de Messenger avec la méthode handle() pour les commandes synchrones
#
Éviter de faire transiter les Value Objects du framework à travers les services
  • Cela crée un couplage fort
  • Par exemple, ne pas transmettre l’objet Request ou l’Input/Output de la console, mais utiliser un DTO.
#
Mettre des contrats sur les services métiers
  • Notion de découplage importante
  • Définir une interface maison sur chaque Repository Doctrine permet de spécifier les méthodes dont on a vraiment besoin
  • Facilite les tests et la maintenance
  • Permet aussi de faire différentes implémentations du Repository dans les tests
#

Conclusion

Comme à chaque événement de l'AFUP, avons passé une excellente journée : les talks étaient tous très pointus et diversifiés, et la fluidité de l'organisation de l'événement nous a permis de vivre une excellente expérience en tant que spectatrices. Nous tenons à féliciter vivement l'équipe d'organisation de l'AFUP Day Lyon pour la préparation de cette journée de conférences, ainsi que les speakers pour leurs contenus enrichissants partagés dans une bonne humeur palpable. Du côté de nos collègues lillois, ne manquez pas leur compte-rendu qui arrivera prochainement !

Le blog

Pour aller plus loin