
Partager:
Acteur de formation avec une thèse sur la comédie, je suis venu au développement PHP par le biais de la scène des rencontres. Vous pouvez me trouver en train de parler et d'écrire sur la technologie, ou de jouer/acheter des disques bizarres de ma collection de vinyles.
Qu'est-ce que le développement axé sur les performances en PHP ?
Temps de lecture : 7 minutes
Au cours de mes années d'expérience dans le développement Web, j'ai vu des codes étonnants. Bien que je ne me considère pas exactement comme une sorte de magicien du code, j'ai une certaine compréhension de certains des principes fondamentaux que nous devons connaître pour écrire des applications propres et efficaces.
L'un des plus grands défis auxquels nous sommes confrontés dans ce secteur est d'amener les développeurs à écrire en utilisant le développement piloté par les tests (TDD). La bonne nouvelle, c'est que les choses semblent être en train de changer, d'après ce que je peux voir - en particulier au sein des startups et des agences.
Notre travail est donc terminé, n'est-ce pas ? (évidemment pas !)
Dans une conférence que j'ai donnée sur Xdebugj'ai fait allusion à la nécessité d'un "développement axé sur les performances". Il est temps d'y revenir pour honorer ma promesse d'approfondir le sujet.
Si nous écrivons du code pour le rendre plus robuste en le testant, pourquoi ne faisons-nous pas la même chose en ce qui concerne la performance ? Qui a entendu parler de PDD ? Le comportement des professionnels du développement de logiciels que j'ai vu revient toujours au cliché selon lequel les développeurs considèrent que le développement d'un logiciel est un processus complexe.
Sécurité
Performance
...dernier. Vous avez des délais à respecter. Vous devez l'expédier. Il fonctionne. Nous nous occuperons de ces deux points plus tard. Il est temps de commencer à regarder un exemple.
L'un des aspects du développement en PHP que j'ai le plus vu est celui des développeurs qui martèlent les ORMs en Symfony et Laravel "jusqu'à ce qu'il fasse ce que je veux", sans penser à la requête SQL sous-jacente et en ajoutant des boucles forEach à chaque fois que l'occasion se présente. Les relations, lorsqu'elles ne sont pas prises en compte dans l'architecture, peuvent facilement créer n+1 problèmes lors de l'utilisation de requêtes. On pourrait penser que ce n'est pas trop courant, mais comme je l'ai dit par expérience : c'est partout.
Prenons l'exemple du code Laravel suivant :
public function getDashboardData()
{
$dashboardData = [];
foreach (Contact::all() as $contact) {
$settings = $contact->settings()->get();
foreach ($settings as $setting) {
if ($setting->setting_name === 'CanPhone') {
if ($setting->setting_value === '1') {
$dashboardData['canPhone']['contact'][] = $setting->contact()->with('settings')->get()->toArray();
}
}
}
}
return view('dashboard', ['data' => $dashboardData]);
Avant de nous plonger dans les mécanismes de l'utilisation de l'ORM par les développeurs, notre point de départ est Contact::all(). J'ai vu des choses comme ça partout - dans la tête des développeurs, la façon la plus simple de compiler les données de ce tableau de bord est de parcourir en boucle chaque entité d'une table, donc de tout récupérer. En termes de balayage de table dans MySql, cela signifie que vous récupérez déjà une table entière et que vous exécutez ensuite d'autres requêtes pour obtenir la relation de paramétrage. Dans ce cas (et il s'agit d'un morceau de code anonyme de la vie réelle, je vous le promets), la relation Setting fait alors un appel pour extraire à nouveau le contact, bien qu'il existe déjà dans le contexte de la boucle.
Ces exemples ne sont pas nécessairement ceux qu'un développeur expérimenté écrirait, mais cela n'a pas d'importance. Le fait est que vous pouvez hériter d'un monolithe complet écrit par quelqu'un d'autre ou le consulter. Si vous n'êtes pas expérimenté, il est possible que vous vous soyez lancé directement dans le développement d'applications sans comprendre au préalable le fonctionnement complexe du langage SQL (pour les requêtes plus complexes, je ne le comprends pas, pour être honnête). Ainsi, n+1 problèmes se produiront si vous ne pouvez pas coder un ORM pour utiliser efficacement des concepts SQL tels que LEFT JOIN et INNER JOIN.
Nous avons beaucoup d'outils pour vous aider à découvrir des problèmes comme ceux-là. Symfony a son excellente barre de débogageLaravel en a une aussi, Xdebug est livré avec un profileur puissant, et Tideways possède maintenant Xhprof. Le problème que je vois est que les développeurs du bas vers le haut ont tendance à penser à la performance en dernier lorsqu'il s'agit d'écrire des fonctionnalités, au lieu d'utiliser ces outils dans le cadre du processus d'écriture du code et de le soumettre à des Pull Requests. D'une certaine manière, cela ressemble au cliché selon lequel les développeurs pensent à la sécurité en dernier, alors qu'une solution plus idéale serait que toute l'équipe prenne en compte à la fois la sécurité et la performance lorsqu'elle écrit du code PHP.
J'ai parlé avec Blackfire et Platform.sh Ingénieur chargé des relations avec les développeurs Thomas di Luccio sur ce que nous devrions prendre en compte lorsque nous écrivons des applications qui considèrent la performance comme une préoccupation de "première classe". L'argument principal, a-t-il dit, est qu'en tant que développeurs, nous devons prendre en compte les performances à partir du niveau de base absolu lorsque nous écrivons du code, et nous devons le faire plus souvent.
C'est ce qui est apparu lorsque j'ai travaillé sur une application, il y a de nombreuses années, qui adoptait une approche bien trop familière. Au lieu de prendre en compte les instructions SQL et la quantité de travail des différentes classes qui utilisaient des fonctions SPL telles que foreach() et array_map(), sans aucun contrôle sur le cadre sous-jacent (qui était propriétaire, donc avec peu de contrôle sur l'ORM), Fastly a été boulonné sur la partie frontale. Oui, le problème est résolu. Mais la base de code sous-jacente était toujours pleine de dettes techniques.
Il est temps de trouver des solutions. Reprenons notre exemple getDashboardData() ci-dessus, nous devons le corriger. Cependant, avant d'y remédier, nous devons établir le profil de ce qui se passe lorsque nous accédons à la page du tableau de bord. En lançant la barre de débogage de Laravel, nous obtenons le résultat suivant :
Deux cent quatre-vingt-six requêtes SQL pour le chargement du tableau de bord - en 11,92 secondes. Comment cela se produit-il ?
Il s'agit d'un classique n+1.
Sur la machine des développeurs, le tableau de bord met une seconde à se charger parce que la base de données contient une poignée de données. Dès que ce code est mis en production, voici ce qui se passe.
Cependant, si vous avez activé ces outils pour les environnements de développement de vos équipes, ce genre d'événements peut être relégué au passé. La première étape du contrôle de ce type de problèmes consiste à définir des seuils. Des outils comme Blackfire et Tideways vous permettent de fixer des seuils et même de les intégrer dans vos pipelines, mais quelle que soit l'approche que vous adoptez (outils gratuits ou produits d'entreprise), vous devrez toujours avoir des Applications acceptables pour votre application lorsque les développeurs la codent.
Disons que nous voulons que l'objectif soit de moins de 5 requêtes et que le temps de chargement soit inférieur à une seconde.
Un développeur plus expérimenté vérifie le code, repère les problèmes n+1 et explique au junior comment obtenir les données en une seule fois. Voici le résultat :

Deux cent quatre-vingt-six requêtes SQL pour le chargement du tableau de bord - en 11,92 secondes. Comment cela se produit-il ?
Il s'agit d'un classique n+1.
Sur la machine des développeurs, le tableau de bord met une seconde à se charger parce que la base de données contient une poignée de données. Dès que ce code est mis en production, voici ce qui se passe.
En effet, si ces outils sont activés dans les environnements de développement de vos équipes, ce genre d'incidents peut être relégué au passé. La première étape pour contrôler ce type de problèmes est de la définition de vos seuils. Des outils tels que Blackfire et Tideways vous permettent de définir des seuils et même de les intégrer dans vos pipelines, mais quelle que soit l'approche que vous adoptez (outils gratuits ou produits d'entreprise), vous devrez toujours avoir des Applications acceptables pour votre application lorsque les développeurs la codent.
Disons que nous voulons que l'objectif soit de moins de 5 requêtes et que le temps de chargement soit inférieur à une seconde.
Un développeur plus expérimenté vérifie le code, repère les problèmes n+1 et explique au junior comment obtenir les données en une seule fois. Voici le résultat :
public function getDashboardData()
{
$dashboardData = Contact::with('settings')
->whereRelation('settings', 'setting_name', '=', 'canPhone')
->paginate(10)
->toArray();
return $dashboardData;
}
C'est beaucoup plus propre. Mais le plus important est de savoir ce que cela donne dans la barre de débogage.

C'est beaucoup plus propre. Mais le plus important est de savoir ce que cela donne dans la barre de débogage.
Quatre instructions SQL, 324 ms de chargement.
La leçon à tirer de cet article n'est pas "voici un code manifestement mauvais, je l'ai corrigé et les performances sont meilleures". Vous pourriez probablement voir que le code était mauvais et qu'il avait besoin d'être corrigé, bien sûr. C'est que si vous êtes dans une position de leadership, les barres de débogage Symfony et Laravel devraient être activées et utilisées dans le cadre de votre processus de développement afin que toute votre équipe l'utilise. Vous pouvez fixer un seuil approximatif, introduire un test qui force une méthode à travailler beaucoup plus et évaluer le temps de chargement. Nous avons les outils pour le faire, alors pourquoi cela devrait-il être une considération secondaire ?
Qu'est-ce que le développement axé sur les performances ? C'est le processus.
Il s'agit de donner à vos développeurs les outils dont ils ont besoin pendant qu'ils travaillent sur une fonctionnalité. Tout comme la sécurité, elle devrait être un citoyen de première classe dans le cycle de développement, et dans le monde PHP, nous avons des outils open-source de premier ordre pour livrer des logiciels de qualité.
Partager:
Acteur de formation avec une thèse sur la comédie, je suis venu au développement PHP par le biais de la scène des rencontres. Vous pouvez me trouver en train de parler et d'écrire sur la technologie, ou de jouer/acheter des disques bizarres de ma collection de vinyles.