Alors que la popularité de Node.js augmente, la traction de PHP diminue. Avec ce contexte, ce post va élaborer sur 5 aspects pragmatiques incontournables de l’utilisation de Node.js pour les développeurs PHP. Ce seront des choses dont personne ne parle ou n’écrit, il est temps de se lancer.
- Node.js pour les développeurs PHP (pas Node.js vs PHP)
- Node.js pour les développeurs PHP le côté pratique
- L’exécution du code Node.js est asynchrone et non séquentielle
- Node.js promet des possibilités
- Le processus Node.js est long, contrairement à PHP
- Exemple de mémorisation
- Exemple de pool de connexion avec MySQL
- Le débogage est plus facile en Node.js que dans PHP
- Les mises à jour majeures de version dans Node.js sont transparentes par rapport à PHP
- Dockerizing une application Node.js est un jeu d’enfant par rapport à PHP
- L’exécution du code Node.js est asynchrone et non séquentielle
- Conclusion
Node.js pour les développeurs PHP (pas Node.js vs PHP) #
Ce morceau est une liste de choses que vous, en tant que développeur PHP, devez savoir et apprendre pour utiliser Node.js efficacement. Au contraire, ce post n’est pas un Node.js vs PHP write up où PHP est bashed. J’ai utilisé les deux langages. J’ai commencé à écrire plus de Node.js en 2016. Lorsque j’ai commencé, j’ai rencontré quelques difficultés car j’étais habitué à PHP au travail depuis plus de 7 ans avant cela. Il y avait un livre publié vers la fin de 2012 couvrant Node.js pour les développeurs PHP.
Ce billet de blog ne va pas parler de ce qu’est PHP ou Node.js, vous pouvez le lire dans d’autres billets. Je ne parlerai pas non plus beaucoup de l’entrée/sortie non bloquante ou de la boucle d’événement. Pourtant, certains de ces éléments seront effleurés lors de la discussion des aspects pratiques de l’écriture d’un bon code Node.js.
Node.js pour les développeurs PHP le côté pratique #
PHP existe depuis 1995 et serait encore utilisé par 79,% des sites web surveillés par W3tech (je ne peux pas vraiment dire si c’est tout l’internet). Il y a donc de très fortes chances que vous ayez utilisé PHP ou déployé quelque chose écrit en PHP. Par exemple avec une tendance croissante:
WordPress est utilisé par 63,7% de tous les sites web dont nous connaissons le système de gestion de contenu. Cela représente 39,0 % de tous les sites Web surveillés par W3Tech.
D’autre part, Node.js a été publié en 2009. Les grandes entreprises technologiques comme Linked In et Paypal ont commencé à l’adopter entre 2011 et 2013 pour diverses raisons comme les microservices. Selon l’enquête sur les développeurs de Stack Overflow de 2020:
Pour la deuxième année consécutive, Node.js prend la première place, car il est utilisé par la moitié des répondants.
Ce n’est pas un secret que Node.js devient très populaire au cours des 5 dernières années.
Donc, en tant que développeur PHP, voici 5 choses pratiques à savoir absolument pour être un grand ingénieur logiciel Node.js. Node.js pour les développeurs PHP est similaire dans un certain sens mais aussi différent dans certains autres aspects certains sont décrits ci-dessous:
L’exécution du code Node.js est asynchrone et non séquentielle #
C’est un comportement qui trompe beaucoup de développeurs PHP. En PHP, le code s’exécute en séquence, d’abord la ligne 1 puis 2, et ainsi de suite. En Javascript et particulièrement en Node.js, cela peut ne pas être le cas. Vous pouvez potentiellement mettre des choses en arrière-plan avec une bonne utilisation des promesses et des callbacks.
Voici un exemple de code modifié avec une explication tirée de mon repo open source currency-api:
async function getExternal(fromCurrency, toCurrency, onDate) {
const rate = await getRate(fromCurrency, toCurrency, onDate);
db.query(
`INSERT INTO exchange_rates (from_currency, to_currency, rate, on_date) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE rate = ?`,
).then(result => {
if (result.affectedRows === 0) {
console.error(`Exchange rate of ${rate} for ${fromCurrency} to ${toCurrency} on ${onDate} could not be saved`);
}
}).catch(err => {
console.log(`Error while writing to db: `, err);
}); //this is done async for the API to respond faster
console.log(`Fetched exchange rate of ${rate} for ${fromCurrency} to ${toCurrency} of ${onDate} from the API`);
return { fromCurrency, toCurrency, onDate, rate };
}
Si vous regardez de plus près, cet innocent semblant db.query
à la ligne 3, a été poussé en arrière-plan. Il s’exécutera donc comme suit:
- Get rate
- Run run insert query in the background
- Whwhile the insert is running the function are already returned the rate
- If there is an issue in the insert query it is logged in the catch
Il n’y a pas de moyen de faire quelque chose comme ça en PHP. C’est la première chose qui laisse les développeurs PHP perplexes. Cela rend plus difficile la compréhension de Node.js pour les développeurs PHP. Ce comportement d’exécution de code asynchrone rend également la recherche de la bonne stack trace plus difficile en cas d’erreurs dans Node.js.
Pour être honnête, en 2020 vous pouvez facilement utiliser async await. Même si c’est du sucre syntaxique sur les Promises, cela rend la programmation asynchrone beaucoup plus facile. Quand j’ai commencé à l’époque de Node 4/6 vers 2016 avec les callbacks et les Promises, c’était une toute autre paire de manches. Attention tout de même à ne pas utiliser async-await (comme ci-dessus) et à se contenter de promises, then et catch. Ne vous emmêlez pas dans l’enfer des promesses au cours du processus. L’enfer des promesses est comme l’itération suivante de l’enfer des callbacks.
Conseil de pro : pour savoir quelles fonctionnalités ES6 vous pouvez utiliser avec quelle version de Node.js, consultez-le sur node.green.
Autre conseil de pro :
Des versions de Node.js sont LTS, les impaires ne le sont pas. Utilisez donc Node 14 ou 16 et non 13 ou 15 en production.
En allant un peu plus loin dans l’exécution non séquentielle, les promesses et la puissance qu’elles ont jouent un rôle important ici. La capacité de faire des choses concurrentes est grande dans Node.js et javascript en général.
Les possibilités de promesses de Node.js #
Les promesses étant asynchrones, vous pouvez les exécuter simultanément. Il y a des façons de le faire. Vous pourriez faire courir 3 promesses et obtenir les résultats de celle qui est la plus rapide. Vous pouvez même faire promise.all
où si une promesse est rejetée, elle arrête toute l’opération. Veuillez lire plus sur Promise.race
, promise.all
et promise.any
dans cette grande comparaison.
Avec cela en tête, vous pouvez essayer d’autres bibliothèques NPM pour limiter la concurrence des promesses ou même filtrer à travers les promesses simultanément. Vous pouvez faire certaines de ces choses avec ReactPHP. Mais il n’est pas inclus dans le PHP natif, pas même dans PHP 8. C’est quelque chose de nouveau à envelopper votre tête autour de Node.js pour les développeurs PHP.
Passons au point suivant, le processus n’a pas besoin de mourir dans Node.js comme dans PHP.
Le processus Node.js est à long terme, contrairement à PHP #
PHP est destiné à mourir non pas dans le sens où il ne sera pas utilisé. Dans le sens où tous les processus PHP doivent mourir. PHP n’est pas vraiment conçu pour les tâches/processus qui s’exécutent longtemps. En PHP, lorsqu’une nouvelle requête HTTP arrive, le traitement commence, et après avoir renvoyé la réponse, le processus est tué. C’est ainsi que fonctionne PHP. Cela crée le besoin de FPM et d’autres serveurs. Vous pouvez soutenir que PHP était sans serveur par conception il y a 20+ ans. Je vous laisse le soin de le faire.
De l’autre côté, Node.js est un processus à long terme. Cela vous permet de partager des informations entre les demandes, car le même serveur/processus traite plusieurs demandes. Avec un processus à longue exécution, vous pouvez facilement exploiter des choses comme la mémorisation sur la mémoire et le pooling de connexion pour une base de données. Cela ouvre d’autres possibilités comme le comptage du nombre de demandes concurrentes sur ce processus par exemple.
Exemple de mémorisation #
Si vous ne connaissez pas la mémorisation.
La mémorisation est une fonction d’ordre supérieur qui met en cache une autre fonction. Elle peut transformer certaines fonctions lentes en fonctions rapides. Elle sauvegarde le résultat d’un appel de fonction après la première fois dans le cache, donc si vous appelez à nouveau la fonction avec les mêmes arguments, elle le trouvera dans le cache.
Elle peut être utilisée dans Node.js mais pas dans PHP nativement. Certaines solutions de contournement sont possibles en PHP comme la sauvegarde de la valeur de retour de la fonction dans Redis.
Voici un exemple de code de mémorisation sur une route express avec p-memoize:
const ONE_MINUTE_IN_MS = 60000;
const options = {
maxAge: ONE_MINUTE_IN_MS,
cacheKey: (arguments_) => arguments_.join(','),
};
app.get('/api/products', async (req, res, next) => {
try {
const memGetProducts = pMemoize(products.getMultiple, options);
res.json(await memGetProducts(req.query.page || 1, req.query.search));
} catch (err) {
next(err);
}
});
L’avantage clair de ceci est une charge moindre sur le datastore. Pendant 1 minute, il répondra en retour avec la même réponse pour les mêmes paramètres. La sortie de la fonction products.getMultiple
est mise en cache en mémoire pendant une minute. Cela rend les réponses très rapides.
Exemple de pool de connexion avec MySQL #
Une autre chose qui n’est pas possible à cause d’un processus mourant en PHP est le pool de connexion. Selon Wikipedia:
En ingénierie logicielle, un pool de connexion est un cache de connexions de base de données maintenu afin que les connexions puissent être réutilisées lors de futures requêtes à la base de données. Les pools de connexion sont utilisés pour améliorer les performances d’exécution des commandes sur une base de données.
Donc, vous aurez 5 connexions dans un pool et si vous voulez exécuter 5 requêtes à la base de données, cela peut être fait simultanément. Cela permet de gagner du temps tant pour la connexion à la base de données que pour l’exécution de la requête. Ceci est facile à faire dans Node.js mais pas facilement possible en PHP.
Soyez attentif au nombre de connexions disponibles et pour garder la taille de votre pool de connexion optimale.
Par exemple, si vous utilisez Kubernetes et que votre application a 5 pods avec une taille de pool de connexion de 2. Cela signifie que votre base de données aura toujours 10 connexions ouvertes même si aucune requête n’est exécutée.
Temps pour un exemple de pool de connexion avec une base de données MySQL avec le module MySQL npm:
var pool = mysql.createPool({
connectionLimit : 5,
host : 'example.org',
user : 'app',
password : 'pass',
database : 'schema'
});
for(var i=0;i<5;i++){
pool.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {
if (err) {
throw err;
}
console.log(rows.solution); //Shows 2
});
}
Le code ci-dessus exécutera la même requête 5 fois en parallèle avec 5 connexions MySQL prises dans le pool de connexion. J’aurais souhaité pouvoir faire cela en PHP dès la boîte.
D’après mon expérience, Node.js fonctionne très bien avec Mysql. Si vous voulez essayer le pooling de connexion avec Mongo DB, voici un exemple Mongo.
Avec un processus à long terme en tant que développeur, vous devez être plus prudent sur les fuites de mémoire et bien faire les choses de ménage.
C’est là que Node.js pour les développeurs PHP ont besoin d’un changement assez important dans la réflexion sur la façon dont le code est exécuté. D’un autre côté, c’est un grand avantage dans Node.js pour les développeurs PHP.
Le débogage est plus facile dans Node.js que dans PHP #
Le débogage du code ligne par ligne est une partie importante de l’expérience du développeur pour tout langage de programmation. Pour déboguer du code PHP, vous pouvez utiliser des modules complémentaires comme X-Debug avec certains paramètres de l’IDE. X-Debug est difficile à mettre en place, c’est le moins que l’on puisse dire. Vous devez l’installer, activer l’extension. Après cela, le configurer correctement avec un IDE comme PHPStorm.
En gros, facile est la dernière chose que vous direz pour faire fonctionner X-debug. À moins que tout soit bien configuré avec un conteneur docker et que les paramètres de l’IDE soient également faciles à charger.
D’autre part, l’exécution de node native debugger ou même de ndb est beaucoup plus facile par rapport à PHP et X-debug. Avec l’utilisation de VS Code, le débogage d’une application Node.js est si facile que même un homme des cavernes peut le faire.
Ouvrir les Préférences > Paramètres et dans la boîte de recherche tapez « node debug ». Sous l’onglet Extensions, il devrait y avoir une extension intitulée « Node debug ». De là, cliquez sur la première case : Debug > Node : Auto Attach and set the drop-down to « on ». Vous êtes presque prêt à partir maintenant. Oui, c’est vraiment aussi simple que cela.
Puis définissez quelques points d’arrêt sur le code VS avec disons index.js
et dans le terminal tapez node --inspect index.js
.
BOOM ! Votre débogueur Node.js pas à pas fonctionne bien sur l’éditeur VS Code sans grand effort. Une bonne différence avec PHP, il n’y a pas besoin d’installer une autre extension, de l’activer et de la configurer pour pouvoir déboguer un programme. Aucun besoin d’installer une extension supplémentaire est un avantage trouvé dans Node.js pour les développeurs PHP.
Le point suivant concerne également une meilleure expérience du développeur lors de la mise à niveau même de plusieurs versions majeures du langage.
Les mises à niveau de versions majeures dans Node.js sont transparentes par rapport à PHP #
Le saut même de plusieurs versions majeures dans Node.js est une expérience transparente. La mise à niveau de PHP 5.x à PHP 7.x est un processus d’une semaine à un mois, selon la taille et la complexité du projet.
Dans mon expérience personnelle, j’ai mis à niveau des microservices Node.js des versions 0.12 à 4 dans le passé. Récemment, j’ai mis à niveau une application de Node.js 10 à 14. Toutes mes mises à niveau de versions majeures de Node.js ont été faciles.
Certains changements mineurs de package.json ont été les seuls petits problèmes que j’ai rencontrés. Après le déploiement, il y avait rarement des problèmes liés à la compatibilité du code. En prime, les performances étaient généralement meilleures en mettant à niveau les versions majeures.
En revanche, la mise à niveau de PHP n’a pas été facile. La mise à niveau de la version mineure pour une application de PHP 5.4 à 5.6 n’était pas très encombrante. Mais, passer de PHP 5.6 à 7.2 pour une application relativement importante était une souffrance. Cela prenait beaucoup de temps et nécessitait de multiples modifications du fichier composer.json. Il était également difficile de le tester. Le bon côté d’une mise à niveau de version majeure de PHP était sûrement l’augmentation des performances.
Juste une note ici, les applications PHP avec lesquelles j’ai travaillé étaient plus anciennes que les applications Node.js. Votre expérience peut sûrement être différente de la mienne.
Dockeriser une application Node.js est un jeu d’enfant par rapport à PHP #
La popularité de Docker n’a cessé d’augmenter au cours des 5 dernières années. Il a changé la façon dont nous, ingénieurs logiciels, travaillons depuis sa sortie. Vous devriez également utiliser Docker pour le développement local. Dans cette optique, la mise sous Docker d’une application PHP peut s’avérer une tâche difficile, selon la disposition des composants et la complexité de l’application. À l’inverse, pour dockeriser une application Node.js, l’effort est moindre et le processus est un jeu d’enfant.
Vous trouverez ci-dessous un exemple de dockerfile pour une application PHP Laravel avec Apache.
FROM composer:1.9.0 as build
WORKDIR /app
COPY . /app
RUN composer global require hirak/prestissimo && composer install
FROM php:7.3-apache-stretch
RUN docker-php-ext-install pdo pdo_mysql
EXPOSE 8080
COPY --from=build /app /var/www/
COPY docker/000-default.conf /etc/apache2/sites-available/000-default.conf
COPY .env.example /var/www/.env
RUN chmod 777 -R /var/www/storage/ && \
echo "Listen 8080" >> /etc/apache2/ports.conf && \
chown -R www-data:www-data /var/www/ && \
a2enmod rewrite
La bonne chose avec cette image Docker pour Laravel est que PHP est regroupé avec apache dans la même image. On peut discuter si c’est une meilleure façon de le faire que de séparer PHP et Apache dans deux images docker.
Notez également la construction docker en plusieurs étapes dans l’image docker ci-dessus. L’installation de Composer est effectuée dans une image différente et la sortie est copiée dans l’image principale. Si nous avions utilisé PHP-FPM et Nginx dans des images docker différentes, cela aurait été plus complexe. Il y aurait eu besoin de gérer deux images docker distinctes.
Maintenant, il est temps de jeter un coup d’œil à un Dockerfile Node.js.
FROM node:14-alpine as base
WORKDIR /src
COPY package.json package-lock.json /src/
COPY . /src
EXPOSE 8080
FROM base as production
ENV NODE_ENV=production
RUN npm install
CMD
FROM base as dev
ENV NODE_ENV=development
RUN npm config set unsafe-perm true && npm install -g nodemon
RUN npm install
CMD
Comme Node.js a un serveur web intégré, le Dockerfile est beaucoup plus propre.
Lorsque vous installez node, npm est regroupé avec lui. Cela élimine le besoin d’installer des paquets à une étape différente de la construction docker.
Dans le Dockerfile ci-dessus, la construction docker à plusieurs étapes est utilisée pour séparer les images docker de production et de développement. Avoir le gestionnaire de paquets (npm) regroupé et avoir le serveur web comme partie du langage/runtime est quelque chose de différent dans Node.js pour les développeurs PHP. Si vous êtes plus intéressé par le Dockering d’une applicaiton Node.js étape par étape suivez ce tutoriel.
Conclusion #
Lorsque l’on utilise Node.js pour les développeurs PHP il faut effectivement un léger changement dans la pensée pour bien exploiter les pouvoirs de Node.js. Node.js n’est pas une solution miracle. Il y a des inconvénients et il faut s’adapter aux différentes façons d’exécuter le code.
Certes, il y a quelques avantages à utiliser Node.js pour les développeurs PHP comme la programmation asynchrone et la concurrence. D’autres avantages découlent de l’utilisation de Node.js étant long.
J’espère que ce post vous aidera à obtenir plus de Node.js en tant que développeur PHP expérimenté.
.