<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>DevOps life</title><description>Tristan Bessoussa’s technical blog: infrastructure, Symfony, serverless and AI coding, in French and English.</description><link>https://devops-life.com/</link><atom:link href="https://devops-life.com/feed.xml" rel="self" type="application/rss+xml"/><lastBuildDate>Thu, 28 Nov 2024 00:00:00 GMT</lastBuildDate><image><url>https://devops-life.com/apple-touch-icon.png</url><title>DevOps life</title><link>https://devops-life.com/</link></image><item><title>How I Used AI to Hack My CrossFit Waitlist Problem (and Why It Changed My View on AI Development)</title><link>https://devops-life.com/blog/2024/11/28/how-i-used-ai-to-hack-my-crossfit-waiting-list/</link><guid isPermaLink="true">https://devops-life.com/blog/2024/11/28/how-i-used-ai-to-hack-my-crossfit-waiting-list/</guid><description>As a CTO who barely codes anymore, I never thought I&apos;d build another app from scratch - until my CrossFit addiction and AI joined forces. Here&apos;s how I used…</description><pubDate>Thu, 28 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As a CTO who barely codes anymore, I never thought I’d build another app from scratch - until my CrossFit addiction and AI joined forces. Here’s how I used generative AI to increase my chances of getting into popular CrossFit classes from 20% to 90%.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-crossfit-class-booking-blues&quot;&gt;The Problem: CrossFit Class Booking Blues&lt;/h2&gt;
&lt;p&gt;For two years, I’ve been battling with my CrossFit box’s booking system. The classes are incredibly popular, requiring reservations up to 14 days in advance. Miss that window? Welcome to waitlist hell, often 15 people deep for the coveted after-work slots.&lt;/p&gt;
&lt;p&gt;Here’s the kicker: I’m terrible at planning ahead. My only hope was to pounce on cancellation notifications, but even my lightning-fast thumb wasn’t enough. Why? The push notifications arrived with up to a minute delay between users. Even when I clicked within a second, I’d still miss out 80% of the time.&lt;/p&gt;
&lt;h2 id=&quot;the-light-bulb-moment&quot;&gt;The Light Bulb Moment&lt;/h2&gt;
&lt;p&gt;As someone who coded for a decade before getting more hands-off, I knew there had to be a better way. The solution was clear: why wait for delayed push notifications when I could query the API directly (which is not public by the way) ? But there was a catch - while the concept was simple, the modern development landscape had evolved significantly since my coding days.&lt;/p&gt;
&lt;h2 id=&quot;enter-ai-my-unexpected-coding-buddy&quot;&gt;Enter AI: My Unexpected Coding Buddy&lt;/h2&gt;
&lt;p&gt;Last week, I decided to test all the “AI coding hype” I’d been seeing on social media. Armed with Cursor and Claude, I embarked on my diabolical plan to enhance my fitness journey.&lt;/p&gt;
&lt;p&gt;The process was fascinating:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I started small, asking AI to create an interface displaying available classes, participant counts, and waitlist numbers&lt;/li&gt;
&lt;li&gt;I extracted network calls (.HAR) from the official web app and fed them to Claude&lt;/li&gt;
&lt;li&gt;Within an hour, I had my first “wow” moment - what would have taken me 4 hours in my familiar tech stack, I accomplished in unfamiliar territory (Astro &amp;amp; React)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;the-reality-check-ai-isnt-magic-its-a-partnership&quot;&gt;The Reality Check: AI Isn’t Magic, It’s a Partnership&lt;/h2&gt;
&lt;p&gt;Working with AI wasn’t all smooth sailing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sometimes it was like working with a brilliant but distracted child&lt;/li&gt;
&lt;li&gt;It would forget context (“You generated pure React, but we’re in an Astro project, remember?”)&lt;/li&gt;
&lt;li&gt;Adding features could break existing functionality (turns out AI shares some human coding traits 😅)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key was learning to provide context effectively, whether sharing specific files or the entire project scope to ensure coherent solutions.&lt;/p&gt;
&lt;h2 id=&quot;the-cto-perspective-a-game-changing-realization&quot;&gt;The CTO Perspective: A Game-Changing Realization&lt;/h2&gt;
&lt;p&gt;This experience transformed my view on AI tools in development. While some of my team already uses GitHub Copilot or Cursor, this personal project revealed the true potential of AI-assisted development. It’s not about replacing developers - it’s about forming an effective partnership with AI tools.&lt;/p&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Clear Requirements Matter&lt;/strong&gt;: AI needs well-defined scope and expectations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context is King&lt;/strong&gt;: The limiting factor is often human communication - vague requests yield vague results&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Embrace Evolution&lt;/strong&gt;: Tech constantly changes; while core concepts remain, tools and frameworks evolve&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI as an Enabler&lt;/strong&gt;: It can help experienced developers work with unfamiliar technologies more effectively.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For experienced developers, this can be a &lt;strong&gt;true game-changer&lt;/strong&gt;, enabling them to work &lt;strong&gt;XX% faster&lt;/strong&gt; even when dealing with unfamiliar technologies.&lt;/p&gt;
&lt;p&gt;For junior developers, it’s a powerful learning tool, accelerating their understanding of new technologies. However, there’s a potential downside: relying too heavily on AI could hinder their ability to develop essential skills and gain a deeper understanding of what’s happening “under the hood.”&lt;/p&gt;
&lt;p&gt;For non-technical individuals, as of 2024, it might still be a bit early to create fully functional code from scratch without a technical foundation. That said, it serves as an excellent communication aid, empowering them to convey their ideas to developers with greater clarity and precision.
At this point of time (and it could change), I don’t see AI replacing developpers, because it required me using my experience and knowledge of the&lt;/p&gt;
&lt;p&gt;P.S. Did my evil plan work? Absolutely. My success rate for getting into cancelled CrossFit slots jumped from 20% to 100%. More importantly, it freed my mind from having to constantly be prepared to jump on my phone for cancellations notifications.
Sometimes the best coding projects start with a selfish need!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;This post was written by Tristan Bessoussa, CTO at Wamiz (Nestlé), where I am exploring ways to blend technology with practical solutions - even if it means gaming the system for a better workout! 💪&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post was then enhanced by AI, and If you read this it until the very end, it means the AI was better at writing than me&lt;/em&gt;&lt;/p&gt;
</content:encoded><dc:creator>Tristan Bessoussa</dc:creator><dc:language>en</dc:language><category>AI</category><category>Development</category><category>Personal Project</category><category>CrossFit</category><category>Technology</category></item><item><title>Un environnement de développement sain en 2021. Bonjour Docker, bye machines virtuelles</title><link>https://devops-life.com/blog/2021/04/28/un-environnement-de-developpement-sain-en-2021-hello-docker-goodbye-machines-virtuelles/</link><guid isPermaLink="true">https://devops-life.com/blog/2021/04/28/un-environnement-de-developpement-sain-en-2021-hello-docker-goodbye-machines-virtuelles/</guid><description>Depuis mai 2015, le modèle chez Yproximité de &quot;tout installer à la main en local en 1/2 journée&quot; a été abandonné pour une solution basée sur une machine…</description><pubDate>Wed, 28 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;contexte&quot;&gt;Contexte&lt;/h2&gt;
&lt;p&gt;Depuis mai 2015, le modèle chez Yproximité de “tout installer à la main en local en 1/2 journée” a été abandonné pour une solution basée sur une machine virtuelle, configurée à l’aide de playbook &lt;a href=&quot;https://www.ansible.com/&quot;&gt;Ansible&lt;/a&gt; afin qu’en une commande, l’environnement de développement soit opérationnel après quelques minutes.&lt;/p&gt;
&lt;p&gt;Les prérequis pour faire tourner les &lt;strong&gt;projets Symfony&lt;/strong&gt; consistait à installer :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make, afin de lancer les commandes&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.virtualbox.org/wiki/Downloads&quot;&gt;VirtualBox&lt;/a&gt;, pour la VM&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.vagrantup.com/downloads.html&quot;&gt;Vagrant&lt;/a&gt;, afin de piloter la VM&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vagrant-landrush/landrush&quot;&gt;Vagrant Landrush&lt;/a&gt;, un DNS pour accéder aux URL de développement&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FiloSottile/mkcert&quot;&gt;mkcert&lt;/a&gt;, pour générer le certificat TLS local&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L’utilisateur était alors invité alors à exécuter dans son terminal &lt;code&gt;make setup&lt;/code&gt;, puis une vingtaine de minutes plus tard, le projet était complètement opérationnel, les données de la base de données importés et toute l’équipe sur les mêmes versions mineures de PHP, Nginx, PostgreSQL.&lt;/p&gt;
&lt;p&gt;❤️ Je tiens d’ailleurs à remercier les contributeurs du projet &lt;a href=&quot;https://www.manala.io/&quot;&gt;manala.io&lt;/a&gt; porté par mon ancienne agence web, &lt;a href=&quot;https://www.elao.com/&quot;&gt;Elao&lt;/a&gt; et notamment &lt;a href=&quot;https://github.com/nervo&quot;&gt;Nervo&lt;/a&gt; qui maintient les différents &lt;a href=&quot;https://github.com/manala/ansible-roles&quot;&gt;rôles Ansible&lt;/a&gt;. Merci pour leurs contributions open source et d’avoir permis de faire tourner notre usine de développement pendant 6 ans.&lt;/p&gt;
&lt;p&gt;Nous sommes maintenant en 2021. Qu’est-ce qui m’a poussé à prévoir ce changement d’usine de développement et à abandonner ce modèle de machines virtuelles (VM) ?&lt;/p&gt;
&lt;h2 id=&quot;pourquoi-séloigner-du-modèle-machines-virtuelles-&quot;&gt;Pourquoi s’éloigner du modèle machines virtuelles ?&lt;/h2&gt;
&lt;p&gt;Plusieurs arguments étaient pour l’abandon des VM :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker qui devient de plus en plus mature et qui a un bon taux d’adoption dans la communauté web sur les environnements de développement.&lt;/li&gt;
&lt;li&gt;Les performances un peu en retrait (surtout sur Linux si j’en crois mon équipe) par rapport à une installation locale du projet.&lt;/li&gt;
&lt;li&gt;Le poids des machines virtuelles (compter plusieurs Go par projets)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Néanmoins, l’idée d’adopter une usine de développement uniquement basée sur Docker m’a énormément freiné. Avec une équipe réduite et sans compétence Docker particulière (notamment pour les problématiques de performances macOS vs Linux) ce choix s’avère risqué pour la stabilité de l’environnement de développement, qui doit être là pour permettre aux développeurs d’être le plus productif, et non pas comme étant une source de frustration, ou de ralentissement.&lt;/p&gt;
&lt;p&gt;Je savais que les VM allaient bientôt être poussées vers la sortie, mais était-ce suffisant pour arrêter une date butoire de transition vers autre chose ? Prévoir un plan de formation ? Faire évoluer nos dizaines de projets vers un autre environnement de développement basé sur du Docker ? Pas tout à fait…&lt;/p&gt;
&lt;p&gt;L’élément qui à permis de faire basculer la balance vers “autre chose” est &lt;a href=&quot;https://forums.virtualbox.org/viewtopic.php?f=8&amp;amp;t=98742#wrap&quot;&gt;l’annonce discrète par l’équipe de VirtualBox&lt;/a&gt; qui dit ne pas pouvoir techniquement porter VirtualBox sur un processeur ARM. VirtualBox, qui fait tourner les VM, est un hyperviseur, et non un émulateur CPU. VirtualBox ne peut donc pas émuler un processeur x86.&lt;/p&gt;
&lt;p&gt;En quoi c’est gênant ? Et bien peut-être avez vous raté &lt;a href=&quot;https://nr.apple.com/dE7O5p9q0t&quot;&gt;l’annonce d’Apple&lt;/a&gt; de leur plan de transition vers une architecture ARM sous 2 ans environ en débutant par leur puce “M1” (qui envoie du lourd), équipant les MacBook Pro 13”, le MacBook Air et le Mac Mini. Il semblerait même que devant les retours extrêmement positifs des utilisateurs, la firme ait même acceléré le déploiement de la nouvelle architecture ARM en annoncant il y à quelques jours les iMac 24” et les iPad Pro avec la puce M1. Pour le grand public, il ne reste donc plus que le MacBook Pro 16” et l’iMac 27” à sauter le cap.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/vm-docker/apple-m1.jpg&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/vm-docker/apple-m1.jpg&quot; alt=&quot;Illustration du processeur d&apos;Apple sous architecture ARM baptisé M1&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;442&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Illustration du processeur d&apos;Apple sous architecture ARM baptisé M1&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Je vois venir les trolls d’Apple au loin, mais dans mon équipe, j’ai toujours eu à cœur de proposer aux développeurs/euses le choix entre du Linux et du macOS (&lt;a href=&quot;https://barometre.afup.org/report/os_developpment?filter%5Bcampaign%5D%5B%5D=6&amp;amp;filter%5Bcampaign%5D%5B%5D=7&amp;amp;filter%5Bcampaign%5D%5B%5D=8&amp;amp;filter%5Bsalary%5D%5Bmin%5D=&amp;amp;filter%5Bsalary%5D%5Bmax%5D=&amp;amp;filter%5Bsubmit%5D=&quot;&gt;voir baromètre AFUP pour les répartions d’OS&lt;/a&gt;). Donc merci de rediriger les troll vers les seuls qui le méritent : les devs PHP/JS sous Windows.&lt;/p&gt;
&lt;h2 id=&quot;une-solution-propulsée-par-docker-mais-pas-que-&quot;&gt;Une solution propulsée par Docker, mais pas que !&lt;/h2&gt;
&lt;p&gt;Dans mon contexte d’entreprise et d’équipe, une solution basée uniquement sur Docker est compromise tant que le problème de performance soit définitivement reglé sur Mac ou qu’il y ait besoin d’une ressource experte Docker/Linux pour implémenter la solution.&lt;/p&gt;
&lt;p&gt;J’ai donc choisi de pousser l’adoption d’une solution hybride afin d’éviter les volumes partagés (et donc pas de problème de performances). Il semblerait, d’après ma mémoire de SymfonyLive que ça soit aussi le choix de &lt;a href=&quot;https://twitter.com/fabpot&quot;&gt;Fabien Potencier&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Sur la machine hôte (macOS/Linux) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PHP et composer&lt;/li&gt;
&lt;li&gt;NodeJS&lt;/li&gt;
&lt;li&gt;Docker Desktop&lt;/li&gt;
&lt;li&gt;Symfony CLI. Ce dernier offre un serveur web avec gestion du TLS, le support docker, et la gestion des versions de PHP spécifiques.&lt;/li&gt;
&lt;li&gt;Binaire Manala (Permettra de générer votre &lt;code&gt;docker-compose.yaml&lt;/code&gt; d’après un template. Voir &lt;a href=&quot;#aller-plus-loin&quot;&gt;aller plus loin&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;⚠ Malgré tous les avantages qu’offre Symfony CLI, ce dernier n’est pas open source. C’est à noter, surtout si on se repose dessus pour une usine de développement.&lt;/p&gt;
&lt;p&gt;Avec Docker :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Base de données (MySQL, PostgreSQL, MariaDB…)&lt;/li&gt;
&lt;li&gt;Serveur Redis&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/vm-docker/docker-containers.jpg&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/vm-docker/docker-containers.jpg&quot; alt=&quot;Liste des containeurs Docker&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;411&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Liste des containeurs Docker&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;L’expérience de développement avec cette nouvelle stack hybride est vraiment très plaisante et rapide, je retrouve les performances natives de ma machine.&lt;/p&gt;
&lt;h2 id=&quot;aller-plus-loin&quot;&gt;Aller plus loin&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/HugoAlliaume&quot;&gt;Hugo Alliaume&lt;/a&gt; a repris le POC que j’ai réalisé en Août 2020 et levé tous les points de bloquages. Il s’est saisi de la problématique à bras le corps et a mené le projet de transition à son exécution sur tous les projets de l’équipe R&amp;amp;D.&lt;/p&gt;
&lt;p&gt;Il a abordé des parties plus techniques dans sur son blog, notamment :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une analyse plus poussée des limites des VM et des workaround nécessaires&lt;/li&gt;
&lt;li&gt;Pourquoi remplacer son serveur web / reverse proxy et gestion DNS local par Symfony CLI&lt;/li&gt;
&lt;li&gt;Un exemple de &lt;code&gt;docker-compose.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Comment tirer profit de cette stack de développement pour le CI, avec GitHub Actions ?&lt;/li&gt;
&lt;li&gt;Comment aller plus loin avec le binaire &lt;code&gt;manala&lt;/code&gt; pour faciliter la gestion et la maintenance (ex: &lt;code&gt;Makefile&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;📖  Je vous invite à lire son article : &lt;a href=&quot;https://hugo.alliau.me/2021/04/26/migration-stack-developpement/&quot;&gt;migration de notre stack de développement vers Docker&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;installation-des-prérequis-sous-macos&quot;&gt;Installation des prérequis sous macOS&lt;/h2&gt;
&lt;p&gt;Ce chapitre s’adresse aux utilisateurs sous macOS 🍎 qui souhaiteraient retrouver ici toutes les procédures d’installation des outils sur votre machine.&lt;/p&gt;
&lt;h3 id=&quot;prérequis&quot;&gt;Prérequis&lt;/h3&gt;
&lt;p&gt;Installation de &lt;a href=&quot;https://brew.sh/index_fr&quot;&gt;&lt;code&gt;brew&lt;/code&gt;&lt;/a&gt; le gestionnaire de paquets pour macOS.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;/bin/bash&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AE3F14;--shiki-dark:#F3996F&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;$(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AE3F14;--shiki-dark:#F3996F&quot;&gt; -fsSL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Installation de &lt;a href=&quot;https://ohmyz.sh/#install&quot;&gt;&lt;code&gt;Zsh&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;sh&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AE3F14;--shiki-dark:#F3996F&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;$(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AE3F14;--shiki-dark:#F3996F&quot;&gt; -fsSL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;installation-de-php&quot;&gt;Installation de PHP&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; php&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt; # installe la dernière version stable de PHP, soit la version 8.0.x à l&apos;heure ou j&apos;écris cet article.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; php@7.4&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt; # installe php 7.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; composer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Si vous avez des projets sous différentes versions de PHP, pas de soucis, installez toutes les versions de PHP nécessaires à vos projets, Symfony utilisera la bonne version grâce au fichier &lt;code&gt;.php-version&lt;/code&gt; déposé à la racine de votre projet.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/vm-docker/symfony-cli-php-version.jpg&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/vm-docker/symfony-cli-php-version.jpg&quot; alt=&quot;Détection des différentes versions de PHP installées sur votre machine tel que vu par le binaire Symfony&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;347&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Détection des différentes versions de PHP installées sur votre machine tel que vu par le binaire Symfony&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;installation-de-nodejs&quot;&gt;Installation de NodeJS&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt; # installe la dernière version stable de NodeJS, soit la version 16.0.x à l&apos;heure ou j&apos;écris cet article.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; node@14&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt; # installe la nodeJS 14&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; yarn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt; # si vous avez besoin du gestionnaire de dépandance JS Yarn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sur le même schéma, si vous avez des projets sous différentes versions de NodeJS, installez toutes les versions nécessaires à vos projets, nous utiliserons &lt;code&gt;nvm&lt;/code&gt; qui permet d’utiliser la bonne version de node selon le projet (la version étant contenue dans le fichier à la racine du projet &lt;code&gt;.nvmrc&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; nvm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enfin lorsque vous lancerez votre &lt;code&gt;yarn install&lt;/code&gt; ou &lt;code&gt;yarn dev-server&lt;/code&gt; pour éviter de faire un &lt;code&gt;nvm use&lt;/code&gt; pour sélectionner la bonne version de nodejs, vous pouvez ajouter ce bloc dans votre &lt;code&gt;~/.zshrc&lt;/code&gt; (puis relancer votre terminal, ou executez &lt;code&gt;source ~/.zshrc&lt;/code&gt;). Cela aura pour effet de regarder si dans votre chemin courant, un &lt;code&gt;.nvmrc&lt;/code&gt; existe avec une version de node spécifique au projet, et l’utilise, si elle est installée.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt; NVM_DIR&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;/.nvm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;/usr/local/opt/nvm/nvm.sh&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; ]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;/usr/local/opt/nvm/nvm.sh&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt;  # This loads nvm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;/usr/local/opt/nvm/etc/bash_completion.d/nvm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; ]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;/usr/local/opt/nvm/etc/bash_completion.d/nvm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt;  # This loads nvm bash_completion&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt;# place this after nvm initialization!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;autoload&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AE3F14;--shiki-dark:#F3996F&quot;&gt; -U&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; add-zsh-hook&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;load-nvmrc&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;  local&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt; node_version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;$(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;nvm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;  local&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt; nvmrc_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;$(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;nvm_find_nvmrc&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;$nvmrc_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; ];&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;    local&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt; nvmrc_node_version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;=$(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;nvm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;$(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;${&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;nvmrc_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;}&quot;)&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;$nvmrc_node_version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;N/A&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; ];&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;      nvm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;    elif&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;$nvmrc_node_version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;$node_version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; ];&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;      nvm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; use&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;  elif&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;$node_version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;$(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;nvm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; version default&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;)&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; ];&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;Reverting to nvm default version&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;    nvm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; use&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;  fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;add-zsh-hook&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; chpwd&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; load-nvmrc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;load-nvmrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;bonus-avec-mux-et-tmuxinator&quot;&gt;Bonus avec mux et tmuxinator&lt;/h3&gt;
&lt;p&gt;Si vous travaillez avec un projet Symfony contenant du JS ayant besoin d’être compilé, vous allez surement avoir besoin de 3 onglet de terminal:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une session sur &lt;code&gt;symfony serve&lt;/code&gt; le webserveur&lt;/li&gt;
&lt;li&gt;Une session à la racine de votre projet&lt;/li&gt;
&lt;li&gt;Une session sur &lt;code&gt;yarn dev-server&lt;/code&gt; pour compiler votre Javascript quand il est modifié.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour gagner en confort, je vous suggère d’utiliser &lt;a href=&quot;https://iterm2.com/&quot;&gt;iTerm2&lt;/a&gt; avec le multiplexer de terminal &lt;code&gt;tmux&lt;/code&gt;. Il permettra de scinder vos terminaux en terminaux virtuels et de pouvoir les splitter. Concrètement, quand je lance dans mon terminal &lt;code&gt;mux start &amp;lt;nom_du_projet&amp;gt;&lt;/code&gt; j’ai automatiquement mes containers qui se lancent, mon split de terminal qui se fait, et &lt;code&gt;yarn dev-server&lt;/code&gt; dans un onglet virtuel comme ci-dessous.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/vm-docker/symfony-cli.jpg&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/vm-docker/symfony-cli.jpg&quot; alt=&quot;Illustration du binaire Symfony CLI, sur la gauche, différentes étapes pour booter le projet, sur la droite le serveur web lancé par `symfony serve` qui traitera vos requêtes&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;396&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Illustration du binaire Symfony CLI, sur la gauche, différentes étapes pour booter le projet, sur la droite le serveur web lancé par `symfony serve` qui traitera vos requêtes&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Pour profiter de la même chose:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; tmux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; tmuxinator&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;puis rajouter l’alias dans votre &lt;code&gt;~/.zshrc&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;alias mux=tmuxinator&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;puis la configuration d’un projet est assez basique&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;mux open &amp;lt;nom_du_projet&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;et configurer votre projet à l’aide de la documentation de &lt;a href=&quot;https://github.com/tmuxinator/tmuxinator&quot;&gt;tmuxinator&lt;/a&gt;, comme par exemple :&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt;# /Users/t.bessoussa/.config/tmuxinator/&amp;lt;nom_du_projet&amp;gt;.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; &amp;lt;nom_du_projet&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; ~/workspace/&amp;lt;mon_projet&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt; # Chemin de votre projet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt;# Run on project exit ( detaching from tmux session )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;on_project_exit&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; make halt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt;# Run on project stop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;on_project_stop&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; make halt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;windows&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;  -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt; php&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;      layout&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; main-vertical&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;      panes&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;        -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; make setup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;        -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; symfony serve&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;  -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt; js&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;    -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; sleep 70&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt; # on attends un peu vu que mon make setup va lancer un build js de dev qui rentrerait en conflit avec le dev-server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;    -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; yarn dev-server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Il ne vous reste plus qu’à retenir &lt;code&gt;mux start &amp;lt;nom_du_projet&amp;gt;&lt;/code&gt; et &lt;code&gt;mux stop &amp;lt;nom_du_projet&amp;gt;&lt;/code&gt; et le tour est joué.&lt;/p&gt;
&lt;p&gt;Une typo ? L’article est disponible sur mon &lt;a href=&quot;https://github.com/tristanbes/devops-life/blob/gh-pages/_posts/2021-04-28-un-environnement-de-developpement-sain-en-2021-hello-docker-goodbye-machines-virtuelles.md&quot;&gt;dépôt Github&lt;/a&gt;&lt;/p&gt;
</content:encoded><dc:creator>Tristan Bessoussa</dc:creator><dc:language>fr</dc:language><category>VM</category><category>Docker</category><category>Machine Virtuelles</category><category>PHP</category><category>environnement de développement</category></item><item><title>Essai du PaaS Suisse, Hidora</title><link>https://devops-life.com/blog/2021/01/19/test-paas-suisse-hidora/</link><guid isPermaLink="true">https://devops-life.com/blog/2021/01/19/test-paas-suisse-hidora/</guid><description>Ce billet s&apos;inscrit dans la suite d&apos;une série d&apos;articles visant à faire un retour d&apos;expérience sur les différents PaaS français dans une problématique…</description><pubDate>Tue, 19 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ce billet s’inscrit dans la suite d’une série d’articles visant à faire un retour d’expérience sur les différents PaaS français dans une problématique d’hébergement d’un parc de 120+ WordPress.&lt;/p&gt;
&lt;p&gt;Dans la série initiale :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Part1. &lt;a href=&quot;https://devops-life.com/blog/2019/01/19/comparatif-paas-wordpress-francais/&quot;&gt;Contexte du comparatif de l’offre PaaS Française&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part2. &lt;a href=&quot;https://devops-life.com/blog/2019/01/20/paas-ovh-comparatif-cloud-web/&quot;&gt;Comparatif PaaS : OVH tombe à l’eau&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part3. &lt;a href=&quot;https://devops-life.com/blog/2019/01/21/paas-clever-cloud-comparatif/&quot;&gt;Comparatif PaaS : Clever Cloud, &lt;del&gt;le bateau prends l’eau&lt;/del&gt; le capitaine redresse la barre&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part4. &lt;a href=&quot;https://devops-life.com/blog/2019/01/22/paas-scalingo-comparatif/&quot;&gt;Comparatif PaaS : Scalingo reste à flot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part5. &lt;a href=&quot;https://devops-life.com/blog/2019/01/23/paas-platform-sh-comparatif/&quot;&gt;Comparatif PaaS : Platform.sh au mouillage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part6. &lt;a href=&quot;https://devops-life.com/blog/2021/01/19/test-paas-suisse-hidora/&quot;&gt;Comparatif PaaS : Hidora, le cloud suisse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part7. &lt;a href=&quot;https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/&quot;&gt;Comparatif PaaS : Les performances, Clever Cloud VS Scalingo VS Hidora&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bien que ma quête pour héberger notre parc de WordPress s’est achevée fin 2019, j’ai décidé de tester Hidora, un PaaS suisse 🇨🇭.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;hidora&quot;&gt;Hidora&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;#r%C3%A9sum%C3%A9-hidora-tldr&quot;&gt;Accéder au résumé si vous êtes pressés&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;build-de-lapplication-sur-hidora&quot;&gt;Build de l’application sur Hidora&lt;/h4&gt;
&lt;p&gt;Hidora propose des installations préconçues pour les principaux CMS, néanmoins, il n’est pas possible de choisir l’édition de WordPress désirée et l’unique proposée est l’édition basique, et non &lt;a href=&quot;https://roots.io/bedrock/&quot;&gt;Bedrock&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Comment build notre WordPress qui nécessite d’installer les dépendances &lt;code&gt;composer&lt;/code&gt; et &lt;code&gt;javascript&lt;/code&gt; ?&lt;/p&gt;
&lt;p&gt;Plusieures difficultés se sont posés pour arriver à déployer notre projet avec  WordPress - Bedrock:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Les environnements PHP chez Hidora n’embarquent aucune runtime &lt;code&gt;Node.js&lt;/code&gt;, il n’est pas possible d’y faire &lt;code&gt;yarn install &amp;amp;&amp;amp; yarn build&lt;/code&gt; pour générer les fichiers &lt;code&gt;css&lt;/code&gt; et &lt;code&gt;js&lt;/code&gt;. Il a donc fallu identifier la distribution sur laquelle tourne le scaler (CentOS), puis installer &lt;code&gt;Node.js&lt;/code&gt;, puis &lt;code&gt;yarn&lt;/code&gt; à la main sur le noeud PHP en SSH, en ayant au préalable demandé au support de nous mettre les droits &lt;code&gt;root&lt;/code&gt; sur notre environnement.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lorsque nous devons personnaliser le script de “post deploy” pour y rajouter notre &lt;code&gt;composer install&lt;/code&gt;, nous nous attendons à être à la racine du dossier contenant notre application déployée, ce n’est pas le cas. Il n’a pas été facile de savoir ou se rendre pour rentrer dans notre répertoire applicatif (&lt;code&gt;cd $WEBROOT/app&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Il n’y a malheureusement pas de multi-edition des variables d’environnements. J’ai du en saisir 30 à la main, une par une: c’est long. Avoir une zone de texte éditable pour pouvoir coller toutes nos variables aurait été plus rapide.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je pense que la frustration ressentie face à ces nombreuses problématiques/questions peuvent être réglées par l’édition de “cookbook” pour répondre aux questions que les nouveaux clients doivent se poser quand ils arrivent sur Hidora (ex: Comment déployer une application Symfony, WordPress…). Les seuls guides que j’ai trouvés sont ceux de la solution qu’à choisi Hidora pour exploiter son cloud: &lt;a href=&quot;https://jelastic.com/&quot;&gt;Jelastic&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Capture d’écran de l’interface d’administration :
&lt;img src=&quot;https://devops-life.com/img/paas/hidora-ui.png&quot; alt=&quot;Interface Hidora UI&quot; width=&quot;1305&quot; height=&quot;884&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;performance-chez-hidora&quot;&gt;Performance chez Hidora&lt;/h4&gt;
&lt;p&gt;Voilà une des typologies de l’infrastructure faisant tourner le WordPress. Les visuels viennent faciliter la compréhension et les ressources allouées.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://devops-life.com/img/paas/hidora-typology.png&quot; alt=&quot;Hidora Typologie Infrastructure WordPress&quot; width=&quot;979&quot; height=&quot;609&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;Exemple : J’envoie 5 visiteurs uniques par seconde pendant 2 minutes sur la page d’accueil. Pas d’optimisations excepté le &lt;code&gt;pm.max_children&lt;/code&gt; réglé sur 10.&lt;/p&gt;
&lt;p&gt;Pour &lt;strong&gt;10,8€&lt;/strong&gt;/mois chez &lt;u&gt;Scalingo&lt;/u&gt;, j’obtiens &lt;strong&gt;492ms&lt;/strong&gt; de moyenne de temps de réponse.&lt;/p&gt;
&lt;p&gt;Pour &lt;strong&gt;15,7€&lt;/strong&gt;/mois chez &lt;u&gt;Hidora&lt;/u&gt;, j’obtiens &lt;strong&gt;2 048ms&lt;/strong&gt; de moyenne de temps de réponse.&lt;/p&gt;
&lt;p&gt;Les performances ne sont donc pas bonnes par défaut. Je pense qu’il serait possible d’obtenir de meilleurs performances, mais n’ayant eu à appliquer d’autres améliorations sur les autres plateformes testés, je ne l’ai pas fait ici non plus.&lt;/p&gt;
&lt;p&gt;Pour plus de détail, voir :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Part7. &lt;a href=&quot;https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/&quot;&gt;Comparatif PaaS : Les performances, Clever Cloud VS Scalingo VS Hidora&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notons qu’Hidora propose une tarification à la ressource réellement consommée. Nous pouvons reserver 2Ghz/2Gb de RAM, et dire que nous autorisons jusqu’à 6Ghz/6Gb de RAM consommés. Si votre applicatif consomme par moment 3,4Ghz de CPU, vous serez facturé uniquement sur la base de cette consommation, et non la borne maximale (6Ghz) choisie ce qui permet de mieux maitriser les coûts lors de pics de charge.&lt;/p&gt;
&lt;h3 id=&quot;résumé-hidora-tldr&quot;&gt;Résumé Hidora (TLDR)&lt;/h3&gt;
&lt;h4 id=&quot;-inconvénients&quot;&gt;👎 Inconvénients&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Interface basé sur Jelastic: complexité de l’interface, peu sexy.&lt;/li&gt;
&lt;li&gt;L’interface Jelastic aurait pu être plus orienté UX.&lt;/li&gt;
&lt;li&gt;La flexibilité peut introduire des mauvaises pratiques (= modifications à la main sur le serveurs de fichiers de config)&lt;/li&gt;
&lt;li&gt;PaaS pas vraiment 100% “PaaS”: on se retrouve à installer des choses manuellement en &lt;code&gt;SSH&lt;/code&gt; via &lt;code&gt;apt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Le build de l’application se fait sur la même machine qui éxecute le code. J’ai dû augmenter la RAM disponible de la plateforme juste pour le build, alors que pour le run, il n’y en avait pas réellement besoin.&lt;/li&gt;
&lt;li&gt;Pas de possibilité de déporter facilement (1 click) le build de l’application sur un scaler, plus gros, à part afin de ne payer que la consommation de ce scaler au moment où l’on en a besoin.&lt;/li&gt;
&lt;li&gt;Performances brutes par défaut (sans avoir à faire des optimisations)&lt;/li&gt;
&lt;li&gt;Le support ne propose pas un canal “live chat”&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;-avantages&quot;&gt;👍 Avantages&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Interface basé sur Jelastic: les ressources internes sont dédiées à autre chose que développer l’UI.&lt;/li&gt;
&lt;li&gt;Très flexible (accès &lt;code&gt;root&lt;/code&gt;, &lt;code&gt;sFTP&lt;/code&gt;, &lt;code&gt;ssh&lt;/code&gt;). C’est top si vous avez beaucoup d’intégrations qui ne sont pas supportés par d’autres PaaS.&lt;/li&gt;
&lt;li&gt;Beaucoup de technologies supportés, dont Docker&lt;/li&gt;
&lt;li&gt;Le support qui à pris le temps de répondre a certaines problématiques par visioconférence, en écran partagé.&lt;/li&gt;
&lt;li&gt;Les data sont hébérgées en Suisse.&lt;/li&gt;
&lt;li&gt;Les ressources consommées sont celles réellement facturées lorsque l’on utilise des ressources flexibles.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;verdict&quot;&gt;Verdict&lt;/h3&gt;
&lt;p&gt;Je ne suis pas sûr d’être en mesure de recommander Hidora dans le scénario ou un &lt;strong&gt;développeur&lt;/strong&gt; serait chargé de configurer et déployer un applicatif (comme on peut le retrouver dans des petites équipes). En effet la couche d’UI fournie par Jelastic est, je trouve, assez complexe à prendre en main et l’expérience nécessite plus de compétences “infra / ops / run” que d’autre hébergeur 100% PaaS que j’ai évoqué dans cette série d’articles.&lt;/p&gt;
&lt;p&gt;On peut se retrouver à faire des opérations hybrides entre de la configuration au travers de l’UI, comme l’on peut s’y attendre pour un PaaS. Mais, de manière plus surprenante, on peut aussi avoir à modifier via &lt;code&gt;sFTP&lt;/code&gt; ou via &lt;code&gt;SSH&lt;/code&gt; des fichiers de configuration (&lt;code&gt;php.ini&lt;/code&gt;, &lt;code&gt;vhost.conf&lt;/code&gt;) ce qui donne l’impression de configurer un serveur dédié ou un VPS.&lt;/p&gt;
&lt;p&gt;Pour les clients qui découvrent l’interface Jelastic, utilisé par Hidora, le partage d’écran avec le support est nécessaire pour y voir plus clair.&lt;/p&gt;
&lt;p&gt;⚠️ Mon avis sur cet hébérgeur ne concerne que l’utilisation que j’en ai faite. Honnêtement, je ne suis pas sûr que mon cas d’utilisation tire le meilleur parti de cet hébérgeur ⚠️&lt;/p&gt;
</content:encoded><dc:creator>Tristan Bessoussa</dc:creator><dc:language>fr</dc:language><category>PaaS</category><category>Performances</category><category>Hidora</category><category>Hosting</category><category>Cloud</category></item><item><title>How Serverless Saved Us For $2.</title><link>https://devops-life.com/blog/2020/03/06/how-serverless-saved-us-for-%242-with-bref-sh/</link><guid isPermaLink="true">https://devops-life.com/blog/2020/03/06/how-serverless-saved-us-for-$2-with-bref-sh/</guid><description>You&apos;ve probably heard or seen words &quot;serverless&quot; or &quot;FaaS&quot; -Function as a Service- over the past few months asking yourself, &quot;ok, is this hype or does it…</description><pubDate>Fri, 06 Mar 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You’ve probably heard or seen words “serverless” or “FaaS” -Function as a Service- over the past few months asking yourself, “ok, is this hype or does it actually have some benefits” ?&lt;/p&gt;
&lt;p&gt;Well, I’m going to share a feedback for our use case at my job that will illustrate why going serverless helped us achieved what was asked.&lt;/p&gt;
&lt;p&gt;To achieve our goal we used the following products/framework/libraries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://symfony.com/&quot;&gt;Symfony (PHP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bref.sh/&quot;&gt;Bref.sh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://serverless.com/&quot;&gt;Serverless framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/spatie/browsershot&quot;&gt;Browsershot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pptr.dev/&quot;&gt;Puppeteer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/sqs/&quot;&gt;Amazon SQS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/lambda/?nc2=type_a&quot;&gt;Amazon Lambda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.scaleway.com/en/object-storage/&quot;&gt;Scaleway S3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My team works with &lt;code&gt;PHP7&lt;/code&gt;, &lt;code&gt;Symfony&lt;/code&gt; and &lt;code&gt;Vue.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can contribute to this article for any typos or errors you may find by &lt;a href=&quot;https://github.com/tristanbes/devops-life/tree/gh-pages/_posts/2020-03-06-how-serverless-saved-us-for-$2-with-bref-sh.md&quot;&gt;submitting a pull request&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-need-generate-pdf-analytics-reports&quot;&gt;The need: Generate PDF analytics reports&lt;/h2&gt;
&lt;p&gt;Here’s the user stories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“As a customer of the CMS,
I should receive each month a PDF report containing serveral analytics for my website”&lt;/li&gt;
&lt;li&gt;“As a reseller of this group of customer of the CMS,
I should receive each month a PDF report of each customer’s reports (containing a part of each)”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In two sentences, for our few customers with this feature, we’ll have to generate 2,000+ PDFs.
Here’s what it looks like for one of the PDFs we have to generate:&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/serverless/pdf-lambda-result.jpg&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/serverless/pdf-lambda-result.jpg&quot; alt=&quot;PDF result&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;842&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;PDF result&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;vps--dedicated-server-option&quot;&gt;VPS / Dedicated server option&lt;/h3&gt;
&lt;p&gt;You could setup a cron job on one of your servers and it will take care of launching a command to generate the PDF.
The main problem: &lt;strong&gt;it doesn’t scale&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;~20 seconds (pdf generation) x 2,000 PDF = &lt;em&gt;11 hours of PDF generation&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Average of generation is 2 seconds, but on a heavy PDF that contains multiple pages of multiple reports it can require up to 30 seconds.&lt;/p&gt;
&lt;p&gt;During those 11 hours you’d need to ensure that the generation can survive that long (through app deployements, server restart etc…) and a way to monitor that the process is running, for example using &lt;a href=&quot;http://supervisord.org/&quot;&gt;Supervisor&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It would also require you to code the whole process using “&lt;a href=&quot;https://en.wikipedia.org/wiki/Defensive_programming&quot;&gt;defensive programming&lt;/a&gt;” in order to ensure the continuing function of your code under unforeseen circumstances.&lt;/p&gt;
&lt;p&gt;Since we run a PHP app, it’s not multi-threaded, meaning, we can’t easily take advantage from all the CPU cores of our dedicated server. One of the options, if we want to achieve concurrency, is to rent more servers which we have to deploy, provision and manage.&lt;/p&gt;
&lt;h3 id=&quot;serverless-option&quot;&gt;Serverless option&lt;/h3&gt;
&lt;p&gt;Here’s the workflow of our setup.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/serverless/pdf-lambda-architecture.jpg&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/serverless/pdf-lambda-architecture.jpg&quot; alt=&quot;PDF generation serverless architecture with 2 Symfony apps. Full HD image for the serverless architecture .&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;310&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;PDF generation serverless architecture with 2 Symfony apps. &lt;br /&gt;&lt;a href=&apos;/img/serverless/pdf-lambda-architecture.jpg&apos;&gt;Full HD image for the serverless architecture&lt;/a&gt;.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/serverless/puml-lambda-pdf.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/serverless/puml-lambda-pdf.png&quot; alt=&quot;PUML diagram of the PDF generation workflow&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;310&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;PUML diagram of the PDF generation workflow&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h4 id=&quot;step-1-preparing-the-data&quot;&gt;Step 1: preparing the data&lt;/h4&gt;
&lt;p&gt;Since this PDF is an aggregation of multiple external and internal data, you will want to have the &lt;strong&gt;data ready&lt;/strong&gt; when you’ll generate the PDF. The CMS application (&lt;code&gt;app #1&lt;/code&gt;, PHP/Symfony) is responsible of &lt;strong&gt;gathering and storing all the data&lt;/strong&gt; that is necessary to build the PDF into a Redis instance.&lt;/p&gt;
&lt;p&gt;Since we want to achieve scalability, you don’t want the service responsible of generating the PDF to ask via an API the data to the &lt;code&gt;app #1&lt;/code&gt; because it would become a bottleneck if 3,000 simultaneous lambda would send requests to your API.&lt;/p&gt;
&lt;h4 id=&quot;step-2-create-async-messages&quot;&gt;Step 2: create async messages&lt;/h4&gt;
&lt;p&gt;Now that all the data is ready, the &lt;code&gt;app #1&lt;/code&gt; is crafting the data in a message, wrapping it inside an enveloppe using &lt;a href=&quot;https://symfony.com/doc/current/messenger.html&quot;&gt;Symfony Messenger&lt;/a&gt; in order to &lt;strong&gt;send the messages to an Amazon SQS queue&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Note for Symfony users: because the messages will be read by another (Symfony) application, you must use a custom message serializer. You can read more on a &lt;a href=&quot;https://github.com/symfony/symfony/issues/33912&quot;&gt;RFC I opened on Symfony repository&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;step-3-store-messages-in-a-queue&quot;&gt;Step 3: store messages in a queue&lt;/h4&gt;
&lt;p&gt;As soon as the messages arrive inside an Amazon SQS queue, it triggers an action on our lambda running our code to generate PDFs.&lt;/p&gt;
&lt;p&gt;Note: our message structure (Plain Old PHP Object) is stored in another git repository. Why ? because both &lt;code&gt;app #1&lt;/code&gt; and &lt;code&gt;app #2&lt;/code&gt; need to have this POPO, so chances that a developper would update the message structure on &lt;code&gt;app #1&lt;/code&gt; but not on &lt;code&gt;app #2&lt;/code&gt; were an unecessary risk.&lt;/p&gt;
&lt;h4 id=&quot;step-4-generate-the-pdfs&quot;&gt;Step 4: generate the PDFs&lt;/h4&gt;
&lt;p&gt;Up to &lt;strong&gt;3,000 lambda instances are started&lt;/strong&gt;, that’s some serious scalability there (in our case we limited it at 50 concurrent lambdas). Each lambda receives one message containing the data to generate 1 PDF.&lt;/p&gt;
&lt;p&gt;Then the lambda runs our &lt;code&gt;app #2&lt;/code&gt; (PHP, Symfony) responsible of rendering a view inside a web page using a simple &lt;code&gt;.twig&lt;/code&gt; templates with some javascript to render charts.&lt;/p&gt;
&lt;p&gt;Then the code uses &lt;a href=&quot;https://github.com/spatie/browsershot&quot;&gt;Browsershot&lt;/a&gt;, which transforms a web page to a PDF by using a headless Chrome controlled via pupetter to visit the URL that renders the &lt;code&gt;.twig&lt;/code&gt; template which will become our PDF.&lt;/p&gt;
&lt;p&gt;Once the PDF is generated, it’s stored in a &lt;strong&gt;S3 bucket&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We used &lt;a href=&quot;https://bref.sh/&quot;&gt;Bref.sh&lt;/a&gt; around Symfony; It’s &lt;strong&gt;awesome&lt;/strong&gt; because it provides lambda integration for your favorite PHP framework and also different &lt;a href=&quot;https://bref.sh/docs/runtimes/#bref-runtimes&quot;&gt;PHP runtime&lt;/a&gt; that will run on the lambda.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;All the 2,000 PDFs are generated within 2 minutes&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;step-5-email-the-pdf-to-the-client&quot;&gt;Step 5: email the PDF to the client&lt;/h4&gt;
&lt;p&gt;The architecture image is only a part of what really happens. Because once the PDF has been generated in the bucket, we generate a new Message, send it to another SQS queue, and then, this particular queue is using &lt;code&gt;app #2&lt;/code&gt; again (but another part of the code) to send an email to the client with the PDF attached and notify the CMS application so clients can download their PDF through the backoffice too.&lt;/p&gt;
&lt;h2 id=&quot;comparison&quot;&gt;Comparison&lt;/h2&gt;
&lt;div class=&quot;table-scroll&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Table&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;VPS or Dedicated server&lt;/th&gt;
&lt;th&gt;Serverless&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Expensive&lt;/td&gt;
&lt;td&gt;Cheap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Complex&lt;/td&gt;
&lt;td&gt;Very scalable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;One of the main advantage of using serverless architecture is that you get billed only for the time it was required to run the code.&lt;/p&gt;
&lt;p&gt;You also don’t have to take care of where or how it runs. You just ship code and it runs in the cloud. The cloud provider is responsible of managing the allocation of the machine resources.&lt;/p&gt;
&lt;p&gt;In our example, using the free tier of Amazon Lambda and Amazon SQS, generating 2,000 PDFs is costing us &lt;strong&gt;~$1.63&lt;/strong&gt; ($1.62 for SQS, $0.01 for Lambda). You can use this &lt;a href=&quot;https://cost-calculator.bref.sh/&quot;&gt;serverless costs calculator&lt;/a&gt; to get better insights.&lt;/p&gt;
&lt;p&gt;If you think you have some part of your code that could benefit from being moved to a serverless architecture, I would advise that you start with a very simple POC so you can get familiar with these new concepts. We did that with a small portion of our code before even attempting to solve the PDF problem to better understand the full ecosystem (queuing, lambda, notification…). We now have 5 lambdas doing specific jobs (outside the PDF needs).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You can read more on this&lt;/strong&gt; from a more technical point of view: &lt;a href=&quot;https://hugo.alliau.me/2020/01/02/generate-pdfs-on-amazon-aws-with-php-and-puppeteer/&quot;&gt;Generate PDFs on Amazon AWS with PHP and Puppeteer&lt;/a&gt;, written by Hugo Alliaume, who helped a lot on this subject. It contains a lot of details, such as how we shipped chrome into the lambda.&lt;/p&gt;
</content:encoded><dc:creator>Tristan Bessoussa</dc:creator><dc:language>en</dc:language><category>faas</category><category>serverless</category><category>architecture</category><category>bref.sh</category><category>Symfony</category><category>sqs</category><category>lambda</category><category>php</category></item><item><title>How not to be depressed when working with WordPress</title><link>https://devops-life.com/blog/2019/04/10/state-of-wordpress-in-2019/</link><guid isPermaLink="true">https://devops-life.com/blog/2019/04/10/state-of-wordpress-in-2019/</guid><description>Ok, so you chose to start a new WordPress project (or someone chose for you)? Well good news, it&apos;s 2019, it doesn&apos;t have to suck from the start anymore;</description><pubDate>Wed, 10 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ok, so you chose to start a new WordPress project (or someone chose for you)? Well good news, it’s 2019, it doesn’t have to suck from the start anymore;&lt;/p&gt;
&lt;p&gt;In this article, I’m not going to explain everything in details, that would require me to write a book about it. I will just point out directions: &lt;strong&gt;what you can do better than the broken official way of doing&lt;/strong&gt; that was legitimate 10 years ago. It’s designed for everyone, web developers, backend developers, front-end developers…&lt;/p&gt;
&lt;p&gt;I promise you that there is &lt;em&gt;no more than 3 minutes of reading&lt;/em&gt; per chapter.&lt;/p&gt;
&lt;p&gt;In the company I work for, we have 150+ WordPress sites. I made the decision for the new ones to adopt everything I wrote in this article, and slowly migrate the legacy ones. Already ~10% of them are using this architecture at the time I was writing this article.&lt;/p&gt;
&lt;p&gt;Note: I’m accepting &lt;a href=&quot;https://github.com/tristanbes/devops-life/blob/gh-pages/_posts/2019-04-10-state-of-wordpress-in-2019.md&quot;&gt;pull requests&lt;/a&gt; to fix english mistakes if you catch them.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;use-bedrock-edition&quot;&gt;Use Bedrock Edition&lt;/h2&gt;
&lt;p&gt;It’s &lt;strong&gt;THE&lt;/strong&gt; starting point of this article. Bedrock is a WordPress boilerplate created by &lt;a href=&quot;https://roots.io/&quot;&gt;Roots&lt;/a&gt;. It leverages the use of modern development tools and embrace the &lt;a href=&quot;https://12factor.net/&quot;&gt;12 Factor app methodology&lt;/a&gt;. Some of the things WordPress can’t/won’t do because of their dinosaur 🦖 status in the PHP world.&lt;/p&gt;
&lt;p&gt;The main advantages of this boilerplate are:&lt;/p&gt;
&lt;h4 id=&quot;support-of-environment-variables&quot;&gt;Support of environment variables&lt;/h4&gt;
&lt;p&gt;If you worked with modern software applications, you’re familiar with the concept of having your application configuration stored as environment variables.&lt;/p&gt;
&lt;p&gt;The benefit of having environment variables is for you to have multiple environments such as &lt;code&gt;production&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt; and &lt;code&gt;development&lt;/code&gt; where you can for example only enable sending emails on &lt;code&gt;production&lt;/code&gt;, without the need of constantly changing values depending on which environment you are.&lt;/p&gt;
&lt;p&gt;In 2019, every major frameworks has a concept of environnement variables in the PHP world: &lt;em&gt;Symfony&lt;/em&gt;, &lt;em&gt;Laravel&lt;/em&gt;, &lt;em&gt;Yii&lt;/em&gt;. It’s a common practice that exists since decades on Windows and Unix world.&lt;/p&gt;
&lt;p&gt;Environment variables can be stored as a file, for &lt;code&gt;development&lt;/code&gt; and injected in your web server for &lt;code&gt;staging&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt; environments. Don’t freak out, a lot of decent hosting companies provide an UI to manipulate environment variables. For example, look at what &lt;a href=&quot;https://devcenter.heroku.com/articles/config-vars#using-the-heroku-dashboard&quot;&gt;Heroku does for environment variables&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Environment variables look a lot like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;mysql://john_doe:p4sSWorD@127.0.0.1:3306/db_awesome_blog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;WP_ENV&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;development&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;WP_HOME&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;http://my-awesome-wordpress.vm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;WP_SITEURL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;=${&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;WP_HOME&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;/wp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;better-directory-structure&quot;&gt;Better directory structure&lt;/h4&gt;
&lt;p&gt;Everything is organized better and as a result, it’s easier to find what you were looking for. The structure look likes:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; composer.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; .env&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;-----------------&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; where&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; majority&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; configuration&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; will&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; happen,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; must&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; be&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; committed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; inside&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; git&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; repository&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;   ├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; application.php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; environments&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;       ├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; development.php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;       ├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; staging.php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;       └──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; production.php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; vendor&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;--------------&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; where&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; 3rd&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; party&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; code&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; lives&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;└──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;    ├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;    │&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;   ├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; mu-plugins&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;    │&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;   ├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; plugins&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;    │&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;   ├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; themes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;    │&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; uploads&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;    ├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; wp-config.php&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; do&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; touch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;    ├──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; index.php&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;------&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; entry&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; point&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; your&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; application,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; each&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; web&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; are&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; send&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; through&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;    └──&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; wp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;-------------&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; WordPress&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt; files&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bonus point to security since the web root (entry point of your application) &lt;code&gt;web/index.php&lt;/code&gt; is isolated from the rest of the structure. It means that your visitor can’t access your &lt;code&gt;config/production.php&lt;/code&gt; file since it’s outside &lt;code&gt;web/&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;reproducible-builds&quot;&gt;Reproducible builds&lt;/h4&gt;
&lt;p&gt;The concept of &lt;a href=&quot;https://en.wikipedia.org/wiki/Reproducible_builds&quot;&gt;reproducible builds&lt;/a&gt; can sum up as: no matter when or where i’m going to build and deploy the application, I will always have the same version of the code (and plugins).&lt;/p&gt;
&lt;p&gt;Since you’re going to be working on you local environment (if it’s not already the case 👀), you need to guarantee that what you have on your computer will be exactly the same that what you’ll have on your production. Let me take an example on why this is important.&lt;/p&gt;
&lt;p&gt;Let’s say you’ve been running a website in production for like a year until there’s a nasty hardware crash on you server. Now all your files are lost. Luckily for you you did things right and had your &lt;code&gt;uploads/&lt;/code&gt; directory and database backup somewhere in the cloud.&lt;/p&gt;
&lt;p&gt;The next step will be to re-install WordPress using the database and media backup. Then re-install the 20 plugins you had on that website. In one year, plugins evolve (and it’s good), but your theme, or some of your features might not be compatible with WooCommerce &lt;code&gt;v3.5&lt;/code&gt;. It might result of a &lt;strong&gt;broken website&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Another example is when you’re working as a team on a project, without reproducible builds you will end up with the frontend person working with WordPress 5.1.1 while the developer still has version 4.9.10 and won’t be able to reproduce the bug you have with that setup.&lt;/p&gt;
&lt;p&gt;Because of this concept, you’ll need to &lt;strong&gt;forbid any type of plugins/themes installation or updating from the WordPress backend&lt;/strong&gt;. By default Bedrock will take care of this when you are in the &lt;code&gt;production&lt;/code&gt; environment. Since WordPress is also a composer dependency, updating it is as simple as &lt;code&gt;composer update roots/wordpress&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But how to guarantee reproducible builds? Well the answer is just below: use &lt;strong&gt;Composer&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;use-composer&quot;&gt;Use Composer&lt;/h2&gt;
&lt;p&gt;Bedrock boilerplate allows you to manage dependencies of your project using &lt;a href=&quot;https://getcomposer.org/&quot;&gt;Composer&lt;/a&gt; like &lt;strong&gt;any&lt;/strong&gt; modern and decent PHP project should do (WordPress, I’m looking at you right now).&lt;/p&gt;
&lt;p&gt;Do you want to install &lt;code&gt;WooCommerce&lt;/code&gt;? Go inside your terminal and type:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;composer require woocommerce/woocommerce&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It’ll fetch the latest version and freeze the version you got on your &lt;code&gt;composer.lock&lt;/code&gt;. This file is what is used to always get the same version of everything no matter where you download your project dependencies, or where you do it when you run &lt;code&gt;composer install&lt;/code&gt;. Because of the importance of this file, it has to be committed ⚠️.&lt;/p&gt;
&lt;p&gt;A good article can be found on &lt;a href=&quot;https://roots.io/using-composer-with-wordpress/&quot;&gt;how to use composer with WordPress&lt;/a&gt; on roots.io website.&lt;/p&gt;
&lt;p&gt;All the plugins are also installable via composer; How? &lt;strong&gt;3 scenarios are possible&lt;/strong&gt;:&lt;/p&gt;
&lt;h4 id=&quot;the-plugin-provides-a-composerjson&quot;&gt;The plugin provides a &lt;code&gt;composer.json&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The developer or company behind the plugin is not locked in a WordPress thing of the past syndrome and has developed modern applications. This would mean that their plugin also ships a &lt;a href=&quot;https://github.com/woocommerce/woocommerce/blob/master/composer.json&quot;&gt;composer.json&lt;/a&gt; file that allows installation through composer. With this scenario you can search for your plugin inside &lt;a href=&quot;https://packagist.org/?query=woocommerce&quot;&gt;packagist.org&lt;/a&gt; which is a repository containing all the public PHP packages in the universe ✨.&lt;/p&gt;
&lt;h4 id=&quot;the-plugin-does-not-provide-a-composerjson&quot;&gt;The plugin does not provide a &lt;code&gt;composer.json&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;If you don’t see the plugin on &lt;a href=&quot;https://packagist.org/&quot;&gt;packagist.org&lt;/a&gt;, then the plugin does not have a &lt;code&gt;composer.json&lt;/code&gt; file.
Don’t worry, &lt;strong&gt;wpackagist&lt;/strong&gt; comes to the rescue. Outlandish created this project to offer a way to install 100% of the plugins and themes using the main WordPress repository. So, this particular WordPress plugin cannot be found on packagist.org, so let’s &lt;a href=&quot;https://wpackagist.org/&quot;&gt;use wpackagist&lt;/a&gt; instead:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;composer require wpackagist-plugin/cookie-law-info&lt;/code&gt;&lt;/p&gt;
&lt;h4 id=&quot;the-plugin-is-a-paidprivate-one-and-does-not-have-a-composerjson&quot;&gt;The plugin is a paid/private one and does not have a &lt;code&gt;composer.json&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;You’ll have multiple options from there:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/elementor/elementor/issues/4042&quot;&gt;Open a ticket to their support&lt;/a&gt; or on their Github and ask to provide a way to install their plugin via composer. You are their customer, you are paying for a product that you can’t install in a proper way. They should care.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;👎 Bad players are ACF Pro, Elementor Pro, Formidable Forms&lt;/li&gt;
&lt;li&gt;👍 Good player is &lt;a href=&quot;https://deliciousbrains.com/wp-migrate-db-pro/doc/installing-via-composer/&quot;&gt;Deliciours brains&lt;/a&gt; (Migrate DB Pro, Offload Media…).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/PhilippBaschke/acf-pro-installer&quot;&gt;Use alternative solutions&lt;/a&gt; when available.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new private Github repository (it’s free), copy/paste the code there and add a &lt;a href=&quot;https://gist.github.com/tristanbes/fbacfb2ce6990e7fdc7411a73715fd92&quot;&gt;composer.json like in this example&lt;/a&gt;, tag a new release using &lt;a href=&quot;https://help.github.com/en/articles/creating-releases&quot;&gt;Github releases&lt;/a&gt;, and then require this package using a custom repository. All the procedure is &lt;a href=&quot;https://roots.io/guides/private-or-commercial-wordpress-plugins-as-composer-dependencies/&quot;&gt;listed in detail on roots.io website&lt;/a&gt;. I’d advise, if you have the budget for, to use &lt;a href=&quot;https://packagist.com/&quot;&gt;Private Packagist&lt;/a&gt; to host your private packages.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;use-a-better-templating-system-than-php-im-yelling-timber&quot;&gt;Use a better templating system than PHP: “I’m yelling timber”!&lt;/h2&gt;
&lt;p&gt;What about the templating system?
PHP is not a good templating system. Hard to read, hard to write, and let’s not fool ourselves, we’re no longer in the early 2010, we have tools created especially for each use case. The best PHP templating system is &lt;a href=&quot;https://twig.symfony.com/&quot;&gt;Twig&lt;/a&gt;. It is widely used in the Symfony ecosystem (but not only).&lt;/p&gt;
&lt;p&gt;So how can we use Twig inside a WordPress project? Luckily for us, there’s a project called  &lt;a href=&quot;https://github.com/timber/timber&quot;&gt;Timber&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Plugin to write WordPress themes with object-oriented code and the Twig Template Engine&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It adds a View / Controller model that will have a huge benefit on the readability and the maintenance of your theme.&lt;/p&gt;
&lt;p&gt;Once you start writing your themes using Twig, &lt;strong&gt;you won’t go back to plain PHP&lt;/strong&gt;. Period.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pro tip&lt;/strong&gt;: Since you’re not designing your themes with plain PHP anymore but with Twig, the server needs to transform your &lt;code&gt;.twig&lt;/code&gt; files into &lt;code&gt;.php&lt;/code&gt; files. This phase is called compilation. It adds extra time to do that. Luckily there’s a cache system that stores the compiled templates on your file system so Twig doesn’t recompile your twig templates on each request that your server needs to process.&lt;/p&gt;
&lt;p&gt;By default, Timber does not activate that cache.&lt;/p&gt;
&lt;p&gt;Here’s how to activate it safely. You’ll save up to 40% of generation time by doing so. Inside your theme’s &lt;code&gt;functions.php&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt;// Activate Twig caching&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;class_exists&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;Timber&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AE3F14;--shiki-dark:#F3996F&quot;&gt; WP_ENV&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;production&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;    Timber&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;$cache &lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AE3F14;--shiki-dark:#F3996F&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt;// Replace WP_ENV === &apos;production&apos; by!WP_DEBUG if you are NOT in a Bedrock structure&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/timber-cache.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/timber-cache.png&quot; alt=&quot;Difference of rendering time before/after enabling Twig cache system. More details on this Blackfire trace .&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;37&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Difference of rendering time before/after enabling Twig cache system. &lt;a href=&apos;https://blackfire.io/profiles/compare/5b79d23e-3bb8-4089-8e56-82aaae679b6b/graph&apos;&gt;More details on this Blackfire trace&lt;/a&gt;.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Note that it caches the the compiled php template and not the data. Any edits made to the &lt;code&gt;.twig&lt;/code&gt; templates on the production won’t be reflected unless you clear the cache. (Who edits files on production though? 😱 Certainly not you!)&lt;/p&gt;
&lt;h2 id=&quot;prefer-storing-your-assets-on-the-cloud&quot;&gt;Prefer storing your assets on the cloud&lt;/h2&gt;
&lt;p&gt;Storing your assets on the local filesystem under &lt;code&gt;uploads/&lt;/code&gt; directory is nice, but at some point, you’ll have to synchronize this folder through all your environments, otherwise your local version will a complete different set of medias than the production and vice-versa.&lt;/p&gt;
&lt;p&gt;Remember when we talked about reproducable builds? Wouldn’t it be nice if we can store our media remotely so we don’t use local filesystem? Spoiler alert, yes, it’s nice.&lt;/p&gt;
&lt;p&gt;The one other major advantage of this technique is &lt;strong&gt;allow your website to scale&lt;/strong&gt; to receive a huge spike of traffic load. All you have to do is to add more servers (horizontal scaling), since you have a reproducible build, the project and plugins will be the same on server number 1, 2, … 23, 24.&lt;/p&gt;
&lt;p&gt;Services you can use to store your media on the cloud :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/s3/&quot;&gt;Amazon S3&lt;/a&gt;. The most famous, yet, not the cheapest one 💸.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/products/spaces/&quot;&gt;Digital Ocean Spaces&lt;/a&gt;. S3-compatible, 45 locations available.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.scaleway.com/object-storage/&quot;&gt;Scaleway&lt;/a&gt;. Cheap storage, S3-compatible but only 2 locations available (Paris and Amsterdam).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ Remember to always use a bucket location near where the majority of your audience live.
I would advise you to choose a “S3 compliant API” since there’s not much WordPress plugin that allow you to use a remote storage that work in majority of use-case.&lt;/p&gt;
&lt;p&gt;Here’s a list of free plugins that allow you to store your media on different cloud storage:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wordpress.org/plugins/ilab-media-tools/&quot;&gt;MediaCloud&lt;/a&gt; (free)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/humanmade/S3-Uploads&quot;&gt;humanmade/s3-uploads&lt;/a&gt; (free)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My wish for WordPress is for them to use an filesystem abstraction such as &lt;a href=&quot;https://flysystem.thephpleague.com/docs/&quot;&gt;Flysystem&lt;/a&gt;. This way, we no longer have to rely on plugins to hack into WordPress to tell it to upload medias and assets elsewhere. Until this happens, you can use one of the plugins above.&lt;/p&gt;
&lt;h2 id=&quot;know-tools-youre-working-with-acf-can-hurt-your-website-performance&quot;&gt;Know tools you’re working with: ACF can hurt your website performance&lt;/h2&gt;
&lt;p&gt;If you’re a user of Advanced Custom Field, known as ACF, then you must know some of the performance bottleneck you might have if you’re abusing the &lt;code&gt;get_field&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;You must only expose the variables you need per page. I’ve seen a lot of example, even in the documentation, where you are invited to do:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;$context&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt; get_fields&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;);&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt; // retrieve all options fields from the database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;Timber&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;render&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;index.twig&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt; $context&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;);&lt;/span&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt; // render the index.twig page with the options passed to the twig context so you can use them inside your view.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you do that, it will trigger one database call per field you’re getting. So let’s say you have 35 fields under the option category, it’ll trigger 35 database call just to get those fields, but, do you really need those 35 fields on all pages?&lt;/p&gt;
&lt;p&gt;What to do instead?&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;$context&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;twitter_link&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt; get_fields&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;twitter_link&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;$context&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;logo_footer_img&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt; get_fields&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;logo_img&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;Timber&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6139C4;--shiki-dark:#B8A8FA&quot;&gt;render&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#0D7358;--shiki-dark:#5FCDA8&quot;&gt;index.twig&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt; $context&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;twig&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#5F6B7D;--shiki-light-font-style:italic;--shiki-dark:#8795A9;--shiki-dark-font-style:italic&quot;&gt;{# use them inside your .twig template; #}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;footer&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AE3F14;--shiki-dark:#F3996F&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;{{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt; options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;twitter_link&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; }}&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;Follow us&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AE3F14;--shiki-dark:#F3996F&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&apos;{{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC&quot;&gt; options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;logo_footer_img&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; }}&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2855BC;--shiki-dark:#8DAEF6&quot;&gt;footer&lt;/span&gt;&lt;span style=&quot;--shiki-light:#4B586B;--shiki-dark:#A2AEBE&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In real world project, doing this kind of optimization leads to important performance improvements.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/blackfire-acf.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/blackfire-acf.png&quot; alt=&quot;Difference of rendering time before/after retrieving only the strict necessary ACF fields. -850 requests to the database and -37% of rendering time! More details on this Blackfire trace .&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;38&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Difference of rendering time before/after retrieving only the strict necessary ACF fields. -850 requests to the database and -37% of rendering time! &lt;a href=&apos;https://blackfire.io/profiles/compare/3984573f-3fc2-48fc-9683-2668c3a4a7e5/graph&apos;&gt;More details on this Blackfire trace&lt;/a&gt;.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Explicit is better than implicit. It helps your colleague to provide a more accurate code review of your work. That work is harder when you don’t know what your template has access to.&lt;/p&gt;
&lt;p&gt;And what about videos and images fields? If you are using them, you should know that if you retrieve them “as is” using the &lt;code&gt;get_field(&apos;my_youtube_video&apos;)&lt;/code&gt;, the code will try to fetch the metadata (size, orientation, length…) of the videos and images.&lt;/p&gt;
&lt;p&gt;What’s the matter here? Well, since you’re hosting your medias on the cloud (or a remote service, eg: YouTube in this example), &lt;strong&gt;the video and images has to be downloaded on the server side&lt;/strong&gt; to allow retrieve this information you won’t need in 98% of the cases. In this situation doing external HTTP calls from your server to the internet adds precious extra time and kills your site’s performance.&lt;/p&gt;
&lt;p&gt;I’ve seen project spending almost 1 second doing external calls, preventing the server to send HTML to the browser by fetching just 10 images information from the cloud.&lt;/p&gt;
&lt;p&gt;In those cases you need to use &lt;code&gt;get_field(&apos;my_youtube_video&apos;, null, false)&lt;/code&gt;. The last option (&lt;code&gt;false&lt;/code&gt;), tells to retrieve the field (in this case, the YouTube url of the video, without any formatting or additionnal treatment). One other case is to set the configuration of the field as a “URL” field, (and not oEmbed), and for images, “Image URL”&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/external_http_calls_blackfire.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/external_http_calls_blackfire.png&quot; alt=&quot;Difference of rendering time before/after configuring fields as URL fields instead of oEmbed. All the external HTTP calls the server made to fetch the metadata of images or videos were eliminated (-7) and it saved 35% of time (-846ms)! More details on this Blackfire trace .&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;39&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Difference of rendering time before/after configuring fields as URL fields instead of oEmbed. All the external HTTP calls the server made to fetch the metadata of images or videos were eliminated (-7) and it saved 35% of time (-846ms)! &lt;a href=&apos;https://blackfire.io/profiles/compare/29fc43d1-fce1-447e-9d4e-cef4b2f53750/graph&apos;&gt;More details on this Blackfire trace&lt;/a&gt;.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;lint-your-code&quot;&gt;Lint your code&lt;/h2&gt;
&lt;p&gt;Is your theme shipping CSS, Javascript and some PHP? You should lint them, make sure you write code compliant with industry standard. Use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/&quot;&gt;ESlint&lt;/a&gt; - Javascript&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stylelint.io/&quot;&gt;stylelint&lt;/a&gt; - CSS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/&quot;&gt;Prettier&lt;/a&gt; - Javascript, CSS…&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cs.symfony.com/&quot;&gt;PHP-CS-Fixer&lt;/a&gt; - PHP (Example of our &lt;a href=&quot;https://gist.github.com/tristanbes/8f29b6f9336a77fd9b205f3453aae892&quot;&gt;.php_cs_dist file&lt;/a&gt; that contains linting rules)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use whatever building tool/task runner you feel comfortable with (&lt;a href=&quot;https://gulpjs.com/&quot;&gt;Gulp&lt;/a&gt;, &lt;a href=&quot;https://brunch.io&quot;&gt;Brunch&lt;/a&gt;). If you don’t have picked up a tool yet, and you need a simple one, I’d suggest you take a look at &lt;strong&gt;&lt;a href=&quot;https://github.com/Yproximite/yProx-cli&quot;&gt;yProx-CLI&lt;/a&gt;&lt;/strong&gt; that we’ve been using at Yproximite for some times and just released as an open source project.&lt;/p&gt;
&lt;p&gt;For your own sanity, please don’t open code you’re downloading from the plugins you use. You might be shocked by the poor code quality you’re dealing with and might end up re-writing a whole lot of WordPress plugins.&lt;/p&gt;
&lt;h2 id=&quot;use-a-continuous-integration-ci-service&quot;&gt;Use a continuous integration (CI) service&lt;/h2&gt;
&lt;p&gt;Use a CI (&lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis&lt;/a&gt;, &lt;a href=&quot;https://about.gitlab.com/product/continuous-integration/&quot;&gt;Gitlab&lt;/a&gt;, &lt;a href=&quot;https://circleci.com/&quot;&gt;CircleCI&lt;/a&gt;, &lt;a href=&quot;https://jenkins.io/&quot;&gt;Jenkins&lt;/a&gt;).
Here’s our base &lt;code&gt;.travis.yml&lt;/code&gt; file that ensure our &lt;code&gt;composer.json&lt;/code&gt; is valid, that our PHP Code is linted and same goes for our JavaScript files; No pull requests should be merged if you have linting errors that will never be fixed once they hit the production. This will allow your peer to review your code and focus on important things.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dist: trusty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;language: php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;php:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - &apos;7.3&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cache:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  yarn: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  directories:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    - ./vendor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    - ./node_modules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    - ~/.composer/cache/files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;before_install:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if [ -f &quot;package.json&quot; ]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        set -e # properly fails Travis if one of the following commands fails&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        nvm install v10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        nvm use 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        node --version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        npm --version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        npm install --global yarn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        set +e # re-enable previous behaviour&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;script:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - composer validate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - composer install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - vendor/bin/php-cs-fixer fix -v --dry-run --using-cache=no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - if [ -f &quot;package.json&quot; ]; then yarn install; fi;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - if [ -f &quot;package.json&quot; ]; then yarn lint; fi;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - if [ -f &quot;package.json&quot; ]; then yarn build; fi;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;setup-an-automated-dependency-updates-tool&quot;&gt;Setup an automated dependency updates tool&lt;/h2&gt;
&lt;p&gt;Since we have 150 WordPress projects in our organization, running &lt;code&gt;composer update&lt;/code&gt; on all of them once per week is not something we want to do, we had to figure how to handle the updates.&lt;/p&gt;
&lt;p&gt;We were using &lt;a href=&quot;https://managewp.com/&quot;&gt;ManageWP&lt;/a&gt; to update WordPress and all of their dependencies, but this option is now off the table since it breaks the concept of reproducible builds. Nothing should alter/mutate your environment. The code should be exactly the same like in your git repository.&lt;/p&gt;
&lt;p&gt;One viable option for us was to delegate the updating process to &lt;a href=&quot;https://dependabot.com/&quot;&gt;Dependabot&lt;/a&gt; which job is to open a pull request when updates are available. Alternatives exists, for example, &lt;a href=&quot;https://renovatebot.com/&quot;&gt;Renovate&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We configured it to automatically merge the pull requests if the package update is a major or a minor (&lt;code&gt;v1.0.0 -&amp;gt; v1.1.4&lt;/code&gt; will be merged automatically, but &lt;code&gt;v1.0.0 -&amp;gt; v2.0.0&lt;/code&gt; won’t);&lt;/p&gt;
&lt;p&gt;⚠️ The WordPress ecosystem does not necessarily respect the &lt;a href=&quot;https://semver.org/&quot;&gt;SemVer&lt;/a&gt;, because… (I’m still looking for a reason…).&lt;/p&gt;
&lt;p&gt;Since we choose a “Platform as a Service” (PaaS) to host all of our WordPress, as soon as a pull request gets merged on master branch, the project gets re-deployed on the production.&lt;/p&gt;
&lt;p&gt;No matter which hosting you chose, you should have automatic deployment, otherwise, the project will be up-to-date but will never hit the production if you need to re-deploy each project if you have a huge amount of them.&lt;/p&gt;
&lt;h2 id=&quot;choose-the-right-hosting&quot;&gt;Choose the right hosting&lt;/h2&gt;
&lt;p&gt;I would strongly advise to go for a PaaS. The main advantages of a Platform as a Service (PaaS) are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No maintenance needed for the server or the software&lt;/li&gt;
&lt;li&gt;Automated deployments&lt;/li&gt;
&lt;li&gt;Vertical, horizontal scaling ready&lt;/li&gt;
&lt;li&gt;Cheap&lt;/li&gt;
&lt;li&gt;Easy&lt;/li&gt;
&lt;li&gt;Isolated (no cross contamination from one site A to site B when hosted on the same server)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some examples of PaaS are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.heroku.com/&quot;&gt;🌍 Heroku&lt;/a&gt; (from 14$/month)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scalingo.com/&quot;&gt;🇫🇷 Scalingo&lt;/a&gt; (from 10,80€/month)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.clever-cloud.com/en/&quot;&gt;🇫🇷 Clever Cloud&lt;/a&gt; (from 26,50€/month)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;⛔️ Don’t ever use a FTP or a SFTP to deploy to the production. Since you need to build your project by running &lt;code&gt;composer install&lt;/code&gt; and maybe build assets by running &lt;code&gt;yarn build&lt;/code&gt;, the long dead process of copy/paste the project on your FTP are &lt;strong&gt;definitely and finally&lt;/strong&gt; dead ⛔️&lt;/p&gt;
&lt;h2 id=&quot;what-you-should-already-be-doing&quot;&gt;What you should already be doing&lt;/h2&gt;
&lt;p&gt;Here’s a list of things you should already be doing, so they don’t deserve a chapter on their own:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Work with a Virtual Machine, that will allow everyone to have the same environment. You can use &lt;a href=&quot;https://roots.io/trellis/&quot;&gt;trellis&lt;/a&gt; or &lt;a href=&quot;http://www.manala.io/&quot;&gt;manala&lt;/a&gt; if you’re more technical&lt;/li&gt;
&lt;li&gt;Use the latest version of PHP available&lt;/li&gt;
&lt;li&gt;Work with pull request&lt;/li&gt;
&lt;li&gt;Review, and ask reviews on your code by your peers&lt;/li&gt;
&lt;li&gt;Configure Github to disallow pull request merging if your pull request doesn’t have reviews.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;note-for-wordpress-plugins-developers&quot;&gt;Note for WordPress plugins developers&lt;/h2&gt;
&lt;p&gt;In order to make the WordPress ecosystem a better place please, you have to respect at least 5 things:&lt;/p&gt;
&lt;p&gt;⚠️ Don’t assume that your plugin user will stores their uploaded files on the local file system. &lt;strong&gt;Assume they don’t&lt;/strong&gt;. Abstract your file manipulation by using for instance &lt;a href=&quot;https://flysystem.thephpleague.com/docs/&quot;&gt;Flysystem&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The main reason behind this reasoning is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When hosting your application on the cloud, you might want to be able to scale your application by adding new servers.&lt;/li&gt;
&lt;li&gt;When you host your WordPress on an &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/what-is-immutable-infrastructure&quot;&gt;immutable infrastructure&lt;/a&gt;, which basically means
&lt;ul&gt;
&lt;li&gt;Either you’re not able to write to the server, preventing any modifications&lt;/li&gt;
&lt;li&gt;Either the modifications your made are lost when the project gets redeployed. (A deploy happens each time you merge code on your code repository or when you scale (add or remove servers) on your application. Only what is on your git repository gets deployed on the server.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;⚙ Provide a way to configure your plugin through environment variables, and use a fallback using the database if the environment variable is not found.
&lt;strong&gt;Environment variables &amp;gt; Configuration stored inside the DB&lt;/strong&gt; in terms of importance; This allow us to automate plugins installation and put all the configuration in one place.&lt;/p&gt;
&lt;p&gt;🎻 Make your plugin installable with &lt;strong&gt;composer&lt;/strong&gt;, it requires a &lt;code&gt;composer.json&lt;/code&gt; file with 10 lines of code at the minimum. Just watch some examples &lt;a href=&quot;https://github.com/deliciousbrains/wp-amazon-s3-and-cloudfront/blob/master/composer.json&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://github.com/awesomemotive/WP-Mail-SMTP/blob/master/composer.json#L4&quot;&gt;here&lt;/a&gt; or &lt;a href=&quot;https://github.com/Yoast/wordpress-seo/blob/trunk/composer.json&quot;&gt;here&lt;/a&gt;. The next step is to tag your releases using &lt;a href=&quot;https://github.com/deliciousbrains/wp-migrate-db/releases&quot;&gt;Github Releases&lt;/a&gt; respecting SemVer and submit your package to &lt;a href=&quot;https://packagist.org/packages/submit&quot;&gt;packagist.org&lt;/a&gt; by entering the Github URL of your repository.&lt;/p&gt;
&lt;p&gt;🔒 Support &lt;a href=&quot;https://www.php.net/supported-versions.php&quot;&gt;maintained version of PHP&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;💅🏽 Lint your PHP code using PHP-CS-Fixer FFS! Choose between PSR2 or Symfony preset, but use one and fix your code.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;If you want to look at a project structure implementing the majority of the point made in this article, you can &lt;a href=&quot;https://github.com/tristanbes/wordpress-boilerplate&quot;&gt;take a look at my WordPress boilerplate example based on Bedrock and Timber&lt;/a&gt;.
This repository should not be used “as is”, but it’ll help you understand how to structure your project files.&lt;/p&gt;
</content:encoded><dc:creator>Tristan Bessoussa</dc:creator><dc:language>en</dc:language><category>WordPress</category><category>Architecture</category><category>composer</category><category>best practices</category><category>Bedrock</category></item><item><title>Le benchmark PaaS de Clever Cloud vs Scalingo vs Hidora</title><link>https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/</link><guid isPermaLink="true">https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/</guid><description>Cette série de billets a pour but de faire un retour d&apos;expérience sur les différents PaaS français dans une problématique d&apos;hébergement d&apos;un parc de 120+…</description><pubDate>Thu, 24 Jan 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Cette série de billets a pour but de faire un retour d’expérience sur les différents PaaS français dans une problématique d’hébergement d’un parc de 120+ WordPress.&lt;/p&gt;
&lt;p&gt;Dans la série :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Part1. &lt;a href=&quot;https://devops-life.com/blog/2019/01/19/comparatif-paas-wordpress-francais/&quot;&gt;Contexte du comparatif de l’offre PaaS Française&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part2. &lt;a href=&quot;https://devops-life.com/blog/2019/01/20/paas-ovh-comparatif-cloud-web/&quot;&gt;Comparatif PaaS : OVH tombe à l’eau&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part3. &lt;a href=&quot;https://devops-life.com/blog/2019/01/21/paas-clever-cloud-comparatif/&quot;&gt;Comparatif PaaS : Clever Cloud, &lt;del&gt;le bateau prends l’eau&lt;/del&gt; le capitaine redresse la barre&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part4. &lt;a href=&quot;https://devops-life.com/blog/2019/01/22/paas-scalingo-comparatif/&quot;&gt;Comparatif PaaS : Scalingo reste à flot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part5. &lt;a href=&quot;https://devops-life.com/blog/2019/01/23/paas-platform-sh-comparatif/&quot;&gt;Comparatif PaaS : Platform.sh au mouillage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part6. &lt;a href=&quot;https://devops-life.com/blog/2021/01/19/test-paas-suisse-hidora/&quot;&gt;Comparatif PaaS : Hidora, le cloud suisse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part7. &lt;a href=&quot;https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/&quot;&gt;Comparatif PaaS : Les performances, Clever Cloud VS Scalingo VS Hidora&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;EDIT 01/21&lt;/strong&gt; Les tests de performances ont été ré-actualisés. La première fournée de tests en 2019, accessibles ici: &lt;strong&gt;&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1hrny3Rf4RB7qqezy8jHQ_DbZXGzBK293sttXRlmxUMA/edit?usp=sharing&quot;&gt;exhaustivité des ~80 tests du comparatif 2019 de performances de PaaS entre Scalingo et Clever Cloud&lt;/a&gt;&lt;/strong&gt; contenait 80 tests.
En 2021, j’ai été beaucoup plus concis sur les tests, disponibles sur &lt;a href=&quot;https://docs.google.com/spreadsheets/d/1Lv9eyBcLTh2hEt7-9YxrTPGz5QUB1OQ2GbOVl-xmahA/edit?usp=sharing&quot;&gt;cette feuille de calcul&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;les-performances-mesurées&quot;&gt;Les performances mesurées&lt;/h2&gt;
&lt;p&gt;Sont retenus pour ce benchmark :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ Clever Cloud&lt;/li&gt;
&lt;li&gt;✅ Scalingo&lt;/li&gt;
&lt;li&gt;✅ Hidora&lt;/li&gt;
&lt;li&gt;⛔️ OVH Cloud Web (impossible de faire tourner le projet, voir Partie II)&lt;/li&gt;
&lt;li&gt;⛔️ Platform.sh (trop cher pour notre contexte WordPress)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les tests ont été réalisés dans des conditions réelles. J’ai pris un WordPress “représentatif” déjà en production chez nous. Il ne s’agit pas de tests sur un WordPress sans plugins qui ne comporte qu’une page vierge.&lt;/p&gt;
&lt;p&gt;J’ai effectué les tests avec un outil de test de montée de charge (&lt;a href=&quot;https://k6.io/&quot;&gt;k6.io&lt;/a&gt;) depuis un serveur à Paris, FR : 5 visiteurs unique par seconde pendant 2 minutes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Les tests chez les différents PaaS ont été réalisés dans les même conditions&lt;/strong&gt; : Même versions de wordpress et des plugins, même page testée. Aucune optimisation apportée excepté la variable d’ajustement &lt;code&gt;pm.max_children&lt;/code&gt; pour gérer la concurrence des requêtes à &lt;code&gt;php-fpm&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Avant de consigner les résultats obtenus, j’ai passé quelques temps à trouver la valeur optimale pour la configuration &lt;code&gt;pm.max_children&lt;/code&gt; qui permet de dire aux scalers combien de requêtes PHP concurrentes il est capable de traiter.&lt;/p&gt;
&lt;p&gt;Une valeur trop haute, et ce sont les performances qui sont plombées à cause du manque de RAM (qui swap). Une valeur trop faible, et le scaler est alors bridé, et vos performances aussi.&lt;/p&gt;
&lt;p&gt;⚠️ Notez que le nombre de visiteur unique est variable, même si l’on règle le test sur 5 visiteurs uniques par secondes pendant 2 minutes. Je n’ai jamais obtenu 5x60x2 = 600 requêtes. Pensez donc à regarder le nombre de requête que le serveur à eu à traiter. ⚠️&lt;/p&gt;
&lt;h4 id=&quot;résultat-des-tests-extraits&quot;&gt;Résultat des tests (extraits)&lt;/h4&gt;
&lt;h5 id=&quot;5-clients-par-seconde-sur-2-minutes&quot;&gt;5 clients par seconde sur 2 minutes&lt;/h5&gt;
&lt;div class=&quot;table-scroll&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Table&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Prix/mois&lt;/th&gt;
&lt;th&gt;Détail&lt;/th&gt;
&lt;th&gt;BDD&lt;/th&gt;
&lt;th&gt;Moyenne (ms)&lt;/th&gt;
&lt;th&gt;Nombre de requêtes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scalingo&lt;/td&gt;
&lt;td&gt;10,8€&lt;/td&gt;
&lt;td&gt;1x S&lt;/td&gt;
&lt;td&gt;256M&lt;/td&gt;
&lt;td&gt;492&lt;/td&gt;
&lt;td&gt;335&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalingo&lt;/td&gt;
&lt;td&gt;18,0€&lt;/td&gt;
&lt;td&gt;1x M&lt;/td&gt;
&lt;td&gt;256M&lt;/td&gt;
&lt;td&gt;451&lt;/td&gt;
&lt;td&gt;342&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clever Cloud&lt;/td&gt;
&lt;td&gt;11,9€&lt;/td&gt;
&lt;td&gt;1x nano&lt;/td&gt;
&lt;td&gt;XXS-Med (512Mb)&lt;/td&gt;
&lt;td&gt;884&lt;/td&gt;
&lt;td&gt;279&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clever Cloud&lt;/td&gt;
&lt;td&gt;20,3€&lt;/td&gt;
&lt;td&gt;1x XS&lt;/td&gt;
&lt;td&gt;XXS-Med (512Mb)&lt;/td&gt;
&lt;td&gt;588&lt;/td&gt;
&lt;td&gt;313&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hidora&lt;/td&gt;
&lt;td&gt;15,78€&lt;/td&gt;
&lt;td&gt;2gb&lt;/td&gt;
&lt;td&gt;256mb&lt;/td&gt;
&lt;td&gt;2 042&lt;/td&gt;
&lt;td&gt;239&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hidora&lt;/td&gt;
&lt;td&gt;28,70€&lt;/td&gt;
&lt;td&gt;2gb&lt;/td&gt;
&lt;td&gt;512mb&lt;/td&gt;
&lt;td&gt;1110&lt;/td&gt;
&lt;td&gt;237&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h5 id=&quot;configuration-des-tests&quot;&gt;Configuration des tests&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Edition Wordpress &lt;a href=&quot;https://roots.io/bedrock/&quot;&gt;Bedrock&lt;/a&gt; afin que WP soit compatible avec un hébergement PaaS, en plus de proposer des outils modernes (gestion de la conf par variables d’environnement, gestion des plugins WordPress par &lt;code&gt;composer&lt;/code&gt;…)&lt;/li&gt;
&lt;li&gt;PHP 7.4.x&lt;/li&gt;
&lt;li&gt;Site 1
&lt;ul&gt;
&lt;li&gt;Wordpress 5.6.x&lt;/li&gt;
&lt;li&gt;Liste des dépendances et plugins : &lt;a href=&quot;https://gist.github.com/tristanbes/b2b1f0ecbc83313cb3d5c1dc18555dfd&quot;&gt;composer.json&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pm.max_children&lt;/code&gt; est reglé sur &lt;code&gt;10&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><dc:creator>Tristan Bessoussa</dc:creator><dc:language>fr</dc:language><category>PaaS</category><category>Clever Cloud</category><category>Performances</category><category>Scalingo</category><category>Hosting</category><category>Cloud</category></item><item><title>Les PaaS Français sont sur un bateau : Platform.sh au mouillage</title><link>https://devops-life.com/blog/2019/01/23/paas-platform-sh-comparatif/</link><guid isPermaLink="true">https://devops-life.com/blog/2019/01/23/paas-platform-sh-comparatif/</guid><description>Ce billet s&apos;inscrit dans une série d&apos;articles visant à faire un retour d&apos;expérience sur les différents PaaS français dans une problématique d&apos;hébergement d&apos;un…</description><pubDate>Wed, 23 Jan 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ce billet s’inscrit dans une série d’articles visant à faire un retour d’expérience sur les différents PaaS français dans une problématique d’hébergement d’un parc de 120+ WordPress.&lt;/p&gt;
&lt;p&gt;Dans la série :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Part1. &lt;a href=&quot;https://devops-life.com/blog/2019/01/19/comparatif-paas-wordpress-francais/&quot;&gt;Contexte du comparatif de l’offre PaaS Française&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part2. &lt;a href=&quot;https://devops-life.com/blog/2019/01/20/paas-ovh-comparatif-cloud-web/&quot;&gt;Comparatif PaaS : OVH tombe à l’eau&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part3. &lt;a href=&quot;https://devops-life.com/blog/2019/01/21/paas-clever-cloud-comparatif/&quot;&gt;Comparatif PaaS : Clever Cloud, &lt;del&gt;le bateau prends l’eau&lt;/del&gt; le capitaine redresse la barre&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part4. &lt;a href=&quot;https://devops-life.com/blog/2019/01/22/paas-scalingo-comparatif/&quot;&gt;Comparatif PaaS : Scalingo reste à flot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part5. &lt;a href=&quot;https://devops-life.com/blog/2019/01/23/paas-platform-sh-comparatif/&quot;&gt;Comparatif PaaS : Platform.sh au mouillage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part6. &lt;a href=&quot;https://devops-life.com/blog/2021/01/19/test-paas-suisse-hidora/&quot;&gt;Comparatif PaaS : Hidora, le cloud suisse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part7. &lt;a href=&quot;https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/&quot;&gt;Comparatif PaaS : Les performances, Clever Cloud VS Scalingo VS Hidora&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;platformsh&quot;&gt;Platform.sh&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;#r%C3%A9sum%C3%A9-platformsh-tldr&quot;&gt;Accéder au résumé si vous êtes pressés&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pour nos projets Symfony sur mesure, nous sommes chez &lt;a href=&quot;https://platform.sh/&quot;&gt;Platform.sh&lt;/a&gt; (~7 projets).&lt;/p&gt;
&lt;p&gt;Je l’ai rapidement éliminé dans le contexte d’une offre d’hébergement de plus de 120+ projets Wordpress car le pricing n’est pas du tout adapté à notre contexte.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;40€ pour 0.8GB de mémoire&lt;/strong&gt;, sachant qu’elle est partagée entre les containers applicatifs ; donc 800Mo de mémoire divisé entre le container web, et le container de la base de données, ça ne fait pas vraiment rêver….&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/platformsh-memory.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/platformsh-memory.png&quot; alt=&quot;Répartition de la mémoire sur les plans Platform.sh. Pour un service avec du PHP et une base de données, le plan S ne suffira pas.&quot; loading=&quot;lazy&quot; width=&quot;610&quot; height=&quot;406&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Répartition de la mémoire sur les plans Platform.sh. Pour un service avec du PHP et une base de données, le plan S ne suffira pas.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Le plan supérieur est à 100€/mois. Et là, on fait x10 sur nos dépenses, sachant que dans notre contexte, la fonctionnalité pour utiliser différents environnements ne nous intéressait pas.&lt;/p&gt;
&lt;p&gt;La gestion des variables d’environnement, comment dire… c’est compliqué : on pense que l’onglet variable sur la branche en question suffirait ? En fait non, car elles ne sont accessibles qu’au runtime et pas au build.&lt;/p&gt;
&lt;p&gt;Pour rajouter des variables au build, il faut aller cliquer sur une zone de 20 par 20 pixels pas du tout miss en avant et rajouter les variables. On se retrouve souvent alors à rajouter les variables dans la configuration du projet, puis à les dupliquer dans la configuration de l’environnement master afin de bénéficier de l’héritage sur les autres branches.&lt;/p&gt;
&lt;p&gt;Notez qu’il n’y a pas d’édition de variables d’environnement en mode “Bulk Edit/Add”.&lt;/p&gt;
&lt;p&gt;Des efforts sur l’UI et l’UX/DX sont à prévoir car l’interface génère régulièrement des frustrations (en plus d’être lente).&lt;/p&gt;
&lt;p&gt;Les incidents sont fréquents (ou alors je n’ai pas de chance et le peu de fois où j’ai besoin de Platform.sh, il y a un incident…), du type “ah tiens, mes builds sont bloqués”, “l’application n’est plus auto-deployée, donc mes correctifs que je pensais être déployés en prod il y a 7 jours ne sont jamais arrivés”. Heureusement, la prod n’est jamais tombée sur nos projets, mais ces problèmes à répétition sur l’utilisation du PaaS sont usants.&lt;/p&gt;
&lt;p&gt;Pour illustrer mes propos, de décembre à janvier, il y a eu 10 incidents répertoriés, certains majeurs, sur leur &lt;a href=&quot;https://status.platform.sh/history&quot;&gt;statuspage&lt;/a&gt; (hors maintenance). A l’heure où j’écris cet article, mon équipe me signale qu’elle est encore bloquée pour déployer certains environnements.&lt;/p&gt;
&lt;h3 id=&quot;résumé-platformsh-tldr&quot;&gt;Résumé Platform.sh (TLDR)&lt;/h3&gt;
&lt;h4 id=&quot;-inconvénients&quot;&gt;👎 Inconvénients&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Cher&lt;/li&gt;
&lt;li&gt;Pas de scalabilité automatique&lt;/li&gt;
&lt;li&gt;On ne sait pas combien de ressources on consomme&lt;/li&gt;
&lt;li&gt;Interface très lente et pas sexy&lt;/li&gt;
&lt;li&gt;Gestion des variables d’environnement&lt;/li&gt;
&lt;li&gt;Incidents à repetition&lt;/li&gt;
&lt;li&gt;Hook de déploiement qu’il faut régulièrement supprimer et rajouter pour que le projet continue à se déployer automatiquement&lt;/li&gt;
&lt;li&gt;Aucun outil de monitoring depuis l’interface pour aller créer des règles d’alertes (ex : Poster un message dans Slack si la RAM &amp;gt;90%). Il y a uniquement un check sur l’espace disque&lt;/li&gt;
&lt;li&gt;Backups pas automatisés, ni proposés de manière automatique. Il faut s’occuper soi-même de créer un cron de snapshot&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;-avantages&quot;&gt;👍 Avantages&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;On peut déployer des branches comme environnements pour faire des démos ou de la préprod facilement&lt;/li&gt;
&lt;li&gt;Système d’héritage des variables d’environemment qui facilite la création d’autres environnements&lt;/li&gt;
&lt;li&gt;Copie de la base de données de production lors de la création d’un nouvel environnement&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;⛔️  &lt;strong&gt;VERDICT : ELIMINÉ&lt;/strong&gt; ⛔️&lt;/p&gt;
&lt;p&gt;Aucun benchmark n’a été réalisé avec Wordpress, tant que la projection d’une migration chez eux bloquait au niveau tarifaire.&lt;/p&gt;
&lt;h2 id=&quot;lire-la-partie-vi&quot;&gt;Lire la partie VI&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Part6. &lt;a href=&quot;https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/&quot;&gt;Comparatif PaaS : Les performances, Clever Cloud VS Scalingo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><dc:creator>Tristan Bessoussa</dc:creator><dc:language>fr</dc:language><category>PaaS</category><category>Platform.sh</category><category>Performances</category><category>Hosting</category><category>Cloud</category></item><item><title>Les PaaS Français sont sur un bateau : Scalingo reste à flot</title><link>https://devops-life.com/blog/2019/01/22/paas-scalingo-comparatif/</link><guid isPermaLink="true">https://devops-life.com/blog/2019/01/22/paas-scalingo-comparatif/</guid><description>Cette série de billets a pour but de faire un retour d&apos;expérience sur les différents PaaS français dans une problématique d&apos;hébergement d&apos;un parc de 120+…</description><pubDate>Tue, 22 Jan 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Cette série de billets a pour but de faire un retour d’expérience sur les différents PaaS français dans une problématique d’hébergement d’un parc de 120+ WordPress.&lt;/p&gt;
&lt;p&gt;Dans la série :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Part1. &lt;a href=&quot;https://devops-life.com/blog/2019/01/19/comparatif-paas-wordpress-francais/&quot;&gt;Contexte du comparatif de l’offre PaaS Française&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part2. &lt;a href=&quot;https://devops-life.com/blog/2019/01/20/paas-ovh-comparatif-cloud-web/&quot;&gt;Comparatif PaaS : OVH tombe à l’eau&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part3. &lt;a href=&quot;https://devops-life.com/blog/2019/01/21/paas-clever-cloud-comparatif/&quot;&gt;Comparatif PaaS : Clever Cloud, &lt;del&gt;le bateau prends l’eau&lt;/del&gt; le capitaine redresse la barre&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part4. &lt;a href=&quot;https://devops-life.com/blog/2019/01/22/paas-scalingo-comparatif/&quot;&gt;Comparatif PaaS : Scalingo reste à flot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part5. &lt;a href=&quot;https://devops-life.com/blog/2019/01/23/paas-platform-sh-comparatif/&quot;&gt;Comparatif PaaS : Platform.sh au mouillage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part6. &lt;a href=&quot;https://devops-life.com/blog/2021/01/19/test-paas-suisse-hidora/&quot;&gt;Comparatif PaaS : Hidora, le cloud suisse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part7. &lt;a href=&quot;https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/&quot;&gt;Comparatif PaaS : Les performances, Clever Cloud VS Scalingo VS Hidora&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;scalingo&quot;&gt;Scalingo&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;#r%C3%A9sum%C3%A9-clever-cloud-tldr&quot;&gt;Accéder au résumé si vous êtes pressés&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://sclng.io/r/dfa62f9bc47ec843&quot;&gt;Scalingo&lt;/a&gt; est un service PaaS dont je n’avais jamais entendu parler (ni sur ma timeline Twitter), c’est un peu à reculons que je l’ai ajouté dans ma liste de “candidats”.&lt;/p&gt;
&lt;p&gt;Ici, l’onboarding est très simple, je n’ai pas dû aller négocier un budget pour tester le service : &lt;strong&gt;tout est facturé à la minute&lt;/strong&gt;. De ce fait, tous les services qui facturent au mois prennent un gros coup de vieux.&lt;/p&gt;
&lt;p&gt;Si vous possédez un site qui passe sur Capital, vous pourrez commander XX scalers supplémentaires afin que l’application tienne la charge, et n’être facturé que sur les 20 minutes durant lesquelles le reportage aura parlé de vous. Et ce même pour la base de données, afin d’augmenter les fameuses limites de connexions simultanées (même si dans ce cas, il serait préférable de passer le site en lecture seule, et mettre un reverse proxy) et de RAM.&lt;/p&gt;
&lt;p&gt;L’interface ne colle plus aux tendances actuelles : elle fait un peu vieillotte, mais elle est agréable à l’utilisation et très réactive. Il vaut mieux ça qu’une interface très “belle”, mais mal pensée et lente.&lt;/p&gt;
&lt;h4 id=&quot;build-de-lapplication-sur-scalingo&quot;&gt;Build de l’application sur Scalingo&lt;/h4&gt;
&lt;p&gt;Un fichier &lt;code&gt;.buildpacks&lt;/code&gt; doit être créé à la racine du projet contenant l’URL d’un dépôt git afin de dire au PaaS comment construire l’application. Dans notre cas c’était : &lt;code&gt;https://github.com/Scalingo/php-buildpack&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Le &lt;code&gt;composer.json&lt;/code&gt; est alors détecté, et &lt;strong&gt;bonus&lt;/strong&gt;, l’édition de Wordpress Bedrock étant supportée chez eux, je n’ai rien eu à faire pour configurer le Vhost NGINX, ça a fonctionné de manière automatique (&lt;a href=&quot;https://github.com/Scalingo/php-buildpack/tree/master/frameworks&quot;&gt;liste des framework PHP auto-détectés&lt;/a&gt;), ce qui n’a pas été le cas par exemple chez Clever Cloud où il a fallu indiquer où était le front controller de l’application (&lt;code&gt;web/index.php&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;L’application se build rapidement et j’ai pu procéder aux tests.&lt;/p&gt;
&lt;h4 id=&quot;performance-chez-scalingo&quot;&gt;Performance chez Scalingo&lt;/h4&gt;
&lt;p&gt;Les tests parleront d’eux-mêmes dans le chapitre dédié. Notez que &lt;a href=&quot;https://sclng.io/r/dfa62f9bc47ec843&quot;&gt;Scalingo&lt;/a&gt; écrase Clever Cloud qui ne passe même pas certains tests à tarif équivalent.&lt;/p&gt;
&lt;p&gt;Quelques fois, nous avons obtenu des performances bien meilleures lors de tests réalisés à des dates différentes chez Scalingo. Après avoir contacté le support, cela s’expliquerait par le voisinage. En effet, les scalers peuvent bouger de machine en machine selon leur charge. Si nous avons des voisins qui possèdent des scalers avec une très forte priorité CPU (donc qui payent plus cher) et qui sont très actifs sur le moment alors moins de temps CPU sera alors alloué à nos containers avec une priorité plus faible.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Part7. &lt;a href=&quot;https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/&quot;&gt;Comparatif PaaS : Les performances, Clever Cloud VS Scalingo VS Hidora&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;résumé-scalingo-tldr&quot;&gt;Résumé Scalingo (TLDR)&lt;/h3&gt;
&lt;h4 id=&quot;-inconvénients&quot;&gt;👎 Inconvénients&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;UI pas très sexy sans être catastrophique non plus.&lt;/li&gt;
&lt;li&gt;Autoscaling (en BETA fermée) qui demande encore d’être un peu ajusté&lt;/li&gt;
&lt;li&gt;Interface de gestion des logs qui pourrait être améliorée visuellement&lt;/li&gt;
&lt;li&gt;Pas de support de Github Server (pour l’app de déploiement)&lt;/li&gt;
&lt;li&gt;Pas (encore) de vision “d’ensemble” pour les portefeuilles avec beaucoup de projets&lt;/li&gt;
&lt;li&gt;Pas de reverse proxy (ex : Varnish) facilement configurable depuis un &lt;code&gt;.vcl &lt;/code&gt; déposé à la racine de l’application afin d’augmenter les performances applicatives en tirant parti du cache HTTP&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EDIT 12/20&lt;/strong&gt; Au moins 2 incidents majeurs de la plateforme sur 2020 suite à des attaques &lt;a href=&quot;https://scalingo.com/blog/mitigating-massive-ddos&quot;&gt;DDOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;-avantages&quot;&gt;👍 Avantages&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Tarifs compétitifs&lt;/li&gt;
&lt;li&gt;Tout est facturé à la “minute”, même la base de données&lt;/li&gt;
&lt;li&gt;Auto-scaling horizontal&lt;/li&gt;
&lt;li&gt;Support réactif. &lt;strong&gt;EDIT 3/12/20&lt;/strong&gt; Toujours très réactif, et souvent un développeur est à l’autre bout qui comprends tout de suite la problématique et apporte une solution rapidement. C’est très appréciable.&lt;/li&gt;
&lt;li&gt;Interface agréable à utiliser et réactive (UX/DX)&lt;/li&gt;
&lt;li&gt;Gestion facilitée du &lt;code&gt;pm.max_children&lt;/code&gt; depuis l’UI (variable &lt;code&gt;MAX_CONCURRENCY&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Gestion d’environnements différents pour une même application (prod/préprod…), mais pas aussi facile que ce que peut proposer Platform.sh par exemple&lt;/li&gt;
&lt;li&gt;Gestion simple et assez complète des règles de monitoring de vos scalers sur différents cannaux (slack, mail…)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EDIT 3/12/20&lt;/strong&gt; Environnement plus flexible que certains PaaS sur certaines extensions: compatible avec Blackfire, Datadog…&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;-verdict--retenu-&quot;&gt;✅ &lt;strong&gt;VERDICT : RETENU&lt;/strong&gt; ✅&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://sclng.io/r/dfa62f9bc47ec843&quot;&gt;Scalingo&lt;/a&gt; a été pour moi &lt;strong&gt;LA&lt;/strong&gt; bonne surprise de ce comparatif. Les tarifs sont compétitifs par rapport au marché, sans compromis sur les performances. Les principales features que l’on peut attendre d’un PaaS sont là et fonctionnent bien !&lt;/p&gt;
&lt;h2 id=&quot;lire-la-partie-v&quot;&gt;Lire la partie V&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Part5. &lt;a href=&quot;https://devops-life.com/blog/2019/01/23/paas-platform-sh-comparatif/&quot;&gt;Comparatif PaaS : Platform.sh&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;u&gt;Disclaimer :&lt;/u&gt; les liens Scalingo sont câblés sur un système de parrainage rattaché à mon compte personnel. Si les autres PaaS testés ici avaient eu ce même système de parainage, j’aurais aussi utilisé ce système sur leurs liens (pour faire des futurs POC ou petits projets persos).&lt;/p&gt;
</content:encoded><dc:creator>Tristan Bessoussa</dc:creator><dc:language>fr</dc:language><category>PaaS</category><category>Performances</category><category>Scalingo</category><category>Hosting</category><category>Cloud</category></item><item><title>Les PaaS Français sont sur un bateau : Clever Cloud redresse la barre</title><link>https://devops-life.com/blog/2019/01/21/paas-clever-cloud-comparatif/</link><guid isPermaLink="true">https://devops-life.com/blog/2019/01/21/paas-clever-cloud-comparatif/</guid><description>Cette série de billets a pour but de faire un retour d&apos;expérience sur les différents PaaS français dans une problématique d&apos;hébergement d&apos;un parc de 120+…</description><pubDate>Mon, 21 Jan 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Cette série de billets a pour but de faire un retour d’expérience sur les différents PaaS français dans une problématique d’hébergement d’un parc de 120+ WordPress.&lt;/p&gt;
&lt;p&gt;Dans la série :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Part1. &lt;a href=&quot;https://devops-life.com/blog/2019/01/19/comparatif-paas-wordpress-francais/&quot;&gt;Contexte du comparatif de l’offre PaaS Française&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part2. &lt;a href=&quot;https://devops-life.com/blog/2019/01/20/paas-ovh-comparatif-cloud-web/&quot;&gt;Comparatif PaaS : OVH tombe à l’eau&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part3. &lt;a href=&quot;https://devops-life.com/blog/2019/01/21/paas-clever-cloud-comparatif/&quot;&gt;Comparatif PaaS : Clever Cloud, &lt;del&gt;le bateau prends l’eau&lt;/del&gt; le capitaine redresse la barre&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part4. &lt;a href=&quot;https://devops-life.com/blog/2019/01/22/paas-scalingo-comparatif/&quot;&gt;Comparatif PaaS : Scalingo reste à flot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part5. &lt;a href=&quot;https://devops-life.com/blog/2019/01/23/paas-platform-sh-comparatif/&quot;&gt;Comparatif PaaS : Platform.sh au mouillage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part6. &lt;a href=&quot;https://devops-life.com/blog/2021/01/19/test-paas-suisse-hidora/&quot;&gt;Comparatif PaaS : Hidora, le cloud suisse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part7. &lt;a href=&quot;https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/&quot;&gt;Comparatif PaaS : Les performances, Clever Cloud VS Scalingo VS Hidora&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;clever-cloud&quot;&gt;Clever Cloud&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Mise à jour Janvier 2021&lt;/strong&gt;: Clever Cloud à changé courant 2020 sa politique de prix sur les bases de données ce qui lui permet de réduire considérablement les coûts, dont je parlais dans cet article. &lt;br&gt;
De plus, après un nouveau test de performance, en utilisant le même projet qu’en décembre 2019, les performances par défaut sont bien meilleures qu’avant (voir mise à jour de l’article &lt;a href=&quot;https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/&quot;&gt;Comparatif PaaS : Les performances, Clever Cloud VS Scalingo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;#r%C3%A9sum%C3%A9-clever-cloud-tldr&quot;&gt;Accéder au résumé si vous êtes pressés&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.clever-cloud.com/&quot;&gt;Clever Cloud&lt;/a&gt; est aussi un PaaS français qui apparait souvent dans ma timeline Twitter dès que des twittos demandaient où héberger leurs projets. C’est avec enthousiasme que j’ai voulu tester leur PaaS.&lt;/p&gt;
&lt;p&gt;Sur le papier, l’offre est sexy   (auto) scaling vertical, horizontal.&lt;/p&gt;
&lt;h4 id=&quot;la-base-de-données&quot;&gt;La base de données&lt;/h4&gt;
&lt;p&gt;Au moment de prendre le service, première mauvaise surprise : la base de données est payante au mois complet, et il n’est pas encore possible de la faire scaler de manière automatique ou manuelle, mais cela devrait (bientôt) changer,&lt;/p&gt;
&lt;div class=&quot;table-scroll&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Table&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Clever Cloud&lt;/th&gt;
&lt;th&gt;Scalingo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Connexion max&lt;/td&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;td&gt;62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Taille max BDD&lt;/td&gt;
&lt;td&gt;&lt;del&gt;10&lt;/del&gt; 5Gb&lt;/td&gt;
&lt;td&gt;5Gb&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mémoire&lt;/td&gt;
&lt;td&gt;1Gb&lt;/td&gt;
&lt;td&gt;1Gb&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type&lt;/td&gt;
&lt;td&gt;Dédié&lt;/td&gt;
&lt;td&gt;Dédié (Software + RAM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU&lt;/td&gt;
&lt;td&gt;1 vCPU&lt;/td&gt;
&lt;td&gt;Partagé&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prix&lt;/td&gt;
&lt;td&gt;&lt;del&gt;45&lt;/del&gt; 22€/mois &lt;br /&gt;&lt;/td&gt;
&lt;td&gt;14,4€/mois&lt;br /&gt;(découpé par minute)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Autre point d’alerte, chez &lt;a href=&quot;https://www.clever-cloud.com/&quot;&gt;Clever Cloud&lt;/a&gt;, ils vous incitent à vous orienter vers du PostgreSQL et ce de manière assumée, puisqu’à ressource strictement équivalente, les containers de base de données sont &lt;strong&gt;plus chers&lt;/strong&gt; pour du MySQL.&lt;/p&gt;
&lt;p&gt;On parle d’une &lt;strong&gt;différence de &lt;del&gt;180&lt;/del&gt; +54€ par an&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ils justifient cette différence par le fait qu’une instance MySQL coûte plus cher à gérer que du PostgreSQL et l’équipe technique chez eux préfère maintenir du PostgreSQL.&lt;/p&gt;
&lt;p&gt;Autant pour une application Symfony, ça ne me fait ni chaud, ni froid (ou presque…) de mettre un PostgreSQL, autant pour du WordPress, nous n’avons pas le choix sur la base de données compatible avec le CMS. Donc au final, c’est l’utilisateur qui paye le coût supplémentaire.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EDIT 12/20&lt;/strong&gt; &lt;del&gt;A priori, ils seraient en train de retravailler le pricing des scaler de base de données.&lt;/del&gt; C’est maintenant chose faite, d’ou la MAJ de cet article.&lt;/p&gt;
&lt;h4 id=&quot;paramétrage-de-lapplication-sur-clever-cloud&quot;&gt;Paramétrage de l’application sur Clever Cloud&lt;/h4&gt;
&lt;p&gt;Comme toute application hebergée sur un PaaS, on passe par la case “variables d’environnement”. Chez Clever Cloud, c’est peu pratique. Lors de mes tests, il y a quelques semaines, il n’y avait pas de gestion de l’édition/ajout des variables en masse. Quand on doit saisir 20 variables : quelle perte de temps ! Heureusement, ça a été corrigé récemment par l’ajout d’un bulk edit/add.&lt;/p&gt;
&lt;p&gt;Il n’est pas possible de faire référence à une autre variable (ex: &lt;code&gt;DATABASE_URL=$MYSQL_ADDON_URI&lt;/code&gt;), et ça, c’est dommage.&lt;/p&gt;
&lt;p&gt;J’ai voulu déployer ensuite mon Wordpress. Je n’ai malheureusement pas pu puisqu’une dépendance (&lt;a href=&quot;https://github.com/wp-cli/wp-cli&quot;&gt;wp-cli&lt;/a&gt;) nécessitait la présence de l’extension PHP &lt;code&gt;ext-readline&lt;/code&gt; qui n’était pas disponible sur Clever Cloud.&lt;/p&gt;
&lt;p&gt;Il a fallu faire une demande au support, et manque de pot, c’est tombé un vendredi, donc pas de mise en prod possible avant mon départ en vacances.&lt;/p&gt;
&lt;p&gt;&lt;u&gt;NB (non dirigée contre Clever Cloud) :&lt;/u&gt; il faut arrêter avec cette politique absurde, je suis tout à fait d’accord avec le Tweet ci dessous : chez nous le vendredi est un jour comme les autres pour les déploiements parce qu’on a fait en sorte que ça soit le cas (tests, automatisation, reviews…).&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;fr&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&amp;quot;No deploys on friday&amp;quot; is cancer philosophy that enforces fear to deploy and slow down the dev cycle. Stop repeating this crap as if it&amp;#39;s cool, and improve processes and tests, for god&amp;#39;s sake.&lt;/p&gt;&amp;mdash; SergiGP 🎗 (@SergiGP) &lt;a href=&quot;https://twitter.com/SergiGP/status/1075417087714181120?ref_src=twsrc%5Etfw&quot;&gt;19 décembre 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;A mon retour de vacances, toujours pas possible de build, suite à un couac, “la feature est activée mais pas l’extension”. Bref, ça arrive quelque heures plus tard : l’application peut enfin être build.&lt;/p&gt;
&lt;h4 id=&quot;build-de-lapplication-sur-clever-cloud&quot;&gt;Build de l’application sur Clever Cloud&lt;/h4&gt;
&lt;p&gt;Alors, comment on build chez eux ?&lt;/p&gt;
&lt;p&gt;Comme le projet possède un &lt;code&gt;composer.json&lt;/code&gt;, le PaaS va récupérer les dépendances de manière automatique. Seulement, nous “buildons” le thème depuis une tâche &lt;code&gt;yarn build&lt;/code&gt;. Il faut donc que l’on puisse lancer un &lt;code&gt;yarn install&lt;/code&gt; suivi d’un &lt;code&gt;yarn build&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Et la ce n’est pas hyper pratique puisqu’il n’est pas capable de dire “Ok, je vois un &lt;code&gt;yarn.lock&lt;/code&gt; donc je vais lancer aussi un &lt;code&gt;yarn install &amp;amp;&amp;amp; yarn build&lt;/code&gt;”. Donc on est obligé de passer par un &lt;strong&gt;Build Hook.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On lui définit une variable pour lui dire d’utiliser &lt;code&gt;yarn&lt;/code&gt; comme package manager, et puis on va lui dire quelles commandes lancer et à quel moment du build, exemple : &lt;code&gt;CC_POST_BUILD_HOOK=&quot;yarn install &amp;amp;&amp;amp; yarn build&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Notez que Wordpress n’a pas été detecté automatiquement, et il a fallu que je crée un fichier dans un dossier &lt;code&gt;.clevercloud&lt;/code&gt; nommé &lt;code&gt;php.json&lt;/code&gt; afin que le routeur puisse savoir quoi servir :&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes devops-life-light devops-life-dark&quot; style=&quot;--shiki-light:#1B2638;--shiki-dark:#DAE2EC;--shiki-light-bg:#FFFFFF;--shiki-dark-bg:#151C26; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;deploy&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;webroot&quot;: &quot;/web&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;configuration&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;pm.max_children&quot;: &quot;20&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;performance-chez-clever-cloud&quot;&gt;Performance chez Clever Cloud&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;EDIT 01/21&lt;/strong&gt; Les nouvelles politiques tarifaires, ainsi que de multiples améliorations hardware/software (migration datacenter + meilleur reverse proxy en Rust) permettent à Clever Cloud de redresser la barre de manière drastique par rapport aux tests réalisés en décembre 2019.&lt;/p&gt;
&lt;p&gt;Ainsi, l’écart de prix se réduit. Mes testent réalisés en Janvier 2021 montrent qu’il ne faut plus avoir à débourser 5 à 9 fois plus d’argent pour obtenir des performances similaires à l’un de ses principaux concurrents, Scalingo.
On est plus sur un ratio de x2. Comprendre ici, pour 2 fois moins cher sur Scalingo, on a des performances similaires à Clever Cloud sur notre environnement WordPress.&lt;/p&gt;
&lt;p&gt;Exemple : J’envoie 5 visiteurs uniques par seconde pendant 2 minutes sur la page d’accueil.&lt;/p&gt;
&lt;p&gt;Pour &lt;strong&gt;10,8€&lt;/strong&gt;/mois chez &lt;u&gt;Scalingo&lt;/u&gt;, j’obtiens &lt;strong&gt;492ms&lt;/strong&gt; de moyenne de temps de réponse.&lt;/p&gt;
&lt;p&gt;Pour &lt;strong&gt;20,3€&lt;/strong&gt;/mois chez &lt;u&gt;Clever Cloud&lt;/u&gt;, j’obtiens &lt;strong&gt;588ms&lt;/strong&gt;. C’est la somme &lt;u&gt;minimum&lt;/u&gt; à débourser pour avoir des performances semblables.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Part7. &lt;a href=&quot;https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/&quot;&gt;Comparatif PaaS : Les performances, Clever Cloud VS Scalingo VS Hidora&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;résumé-clever-cloud-tldr&quot;&gt;Résumé Clever Cloud (TLDR)&lt;/h3&gt;
&lt;h4 id=&quot;-inconvénients&quot;&gt;👎 Inconvénients&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;del&gt;Ratio prix/performances sur du WordPress catastrophique&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Gestion du pricing des add-ons de base de données : &lt;del&gt;prix important, et&lt;/del&gt; engagement au mois&lt;/li&gt;
&lt;li&gt;Pas de scaling sur la base de données&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Pas de références à d’autres variables d’environnement&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Pas de support de Github Server pour déploiement auto&lt;/li&gt;
&lt;li&gt;Interface parfois peu intuitive&lt;/li&gt;
&lt;li&gt;Gestion des statistiques (en BETA depuis 2019 ?)&lt;/li&gt;
&lt;li&gt;Pas de gestion facilitée du &lt;code&gt;pm.max_children&lt;/code&gt; depuis l’UI (ex : par une variable d’environnement)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EDIT 12/20&lt;/strong&gt; Très peu d’ouverture sur l’écosystème PHP: APM / Monitoring (pas de Datadog, blackfire.io, tideways.io)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EDIT 01/21&lt;/strong&gt; Ratio prix/performances bonnes&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;-avantages&quot;&gt;👍 Avantages&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Backup automatisés&lt;/li&gt;
&lt;li&gt;Intégration avec let’s encrypt&lt;/li&gt;
&lt;li&gt;Auto-scaling vertical et/ou horizontal&lt;/li&gt;
&lt;li&gt;Support réactif sur l’aspect communication&lt;/li&gt;
&lt;li&gt;Interface sexy &amp;amp; réactive&lt;/li&gt;
&lt;li&gt;Gestion des logs claire&lt;/li&gt;
&lt;li&gt;Une alternative à Amazon S3 “maison”, pour monter un espace de stockage non volatile&lt;/li&gt;
&lt;li&gt;Une gestion optionelle d’un reverse proxy qui a l’air simplifiée (Varnish)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EDIT 12/20&lt;/strong&gt; Très stable (Rex sur 1an+ d’hébergement d’un projet chez eux)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EDIT 12/20&lt;/strong&gt; Gestion multi-régions (avec l’aide d’OVH en coulisse)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;️-verdict--eliminé-️&quot;&gt;⛔️ &lt;strong&gt;VERDICT : ELIMINÉ&lt;/strong&gt; ⛔️&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;EDIT 01/21&lt;/strong&gt; Les problèmes de rapport performance/prix, maintenant résolus, ont été les 2 raisons de l’élimination de Clever Cloud pour notre problématique d’hébergement en 2019.&lt;/p&gt;
&lt;h2 id=&quot;lire-la-partie-iv&quot;&gt;Lire la partie IV&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Part4. &lt;a href=&quot;https://devops-life.com/blog/2019/01/22/paas-scalingo-comparatif/&quot;&gt;Comparatif PaaS : Scalingo, on reste à flot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><dc:creator>Tristan Bessoussa</dc:creator><dc:language>fr</dc:language><category>PaaS</category><category>Performances</category><category>Clever Cloud</category><category>Hosting</category><category>Cloud</category></item><item><title>Les PaaS Français sont sur un bateau : OVH tombe à l’eau</title><link>https://devops-life.com/blog/2019/01/20/paas-ovh-comparatif-cloud-web/</link><guid isPermaLink="true">https://devops-life.com/blog/2019/01/20/paas-ovh-comparatif-cloud-web/</guid><description>Ce billet s&apos;inscrit dans une série d&apos;articles visant à faire un retour d&apos;expérience sur les différents PaaS français dans une problématique d&apos;hébergement d&apos;un…</description><pubDate>Sun, 20 Jan 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ce billet s’inscrit dans une série d’articles visant à faire un retour d’expérience sur les différents PaaS français dans une problématique d’hébergement d’un parc de 120+ WordPress.&lt;/p&gt;
&lt;p&gt;Dans la série :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Part1. &lt;a href=&quot;https://devops-life.com/blog/2019/01/19/comparatif-paas-wordpress-francais/&quot;&gt;Contexte du comparatif de l’offre PaaS Française&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part2. &lt;a href=&quot;https://devops-life.com/blog/2019/01/20/paas-ovh-comparatif-cloud-web/&quot;&gt;Comparatif PaaS : OVH tombe à l’eau&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part3. &lt;a href=&quot;https://devops-life.com/blog/2019/01/21/paas-clever-cloud-comparatif/&quot;&gt;Comparatif PaaS : Clever Cloud, &lt;del&gt;le bateau prends l’eau&lt;/del&gt; le capitaine redresse la barre&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part4. &lt;a href=&quot;https://devops-life.com/blog/2019/01/22/paas-scalingo-comparatif/&quot;&gt;Comparatif PaaS : Scalingo reste à flot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part5. &lt;a href=&quot;https://devops-life.com/blog/2019/01/23/paas-platform-sh-comparatif/&quot;&gt;Comparatif PaaS : Platform.sh au mouillage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part6. &lt;a href=&quot;https://devops-life.com/blog/2021/01/19/test-paas-suisse-hidora/&quot;&gt;Comparatif PaaS : Hidora, le cloud suisse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part7. &lt;a href=&quot;https://devops-life.com/blog/2019/01/24/clevercloud-vs-scalingo/&quot;&gt;Comparatif PaaS : Les performances, Clever Cloud VS Scalingo VS Hidora&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;ovh-et-son-offre-cloud-web&quot;&gt;OVH et son offre Cloud Web&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;#r%C3%A9sum%C3%A9-ovh-cloud-web-tldr&quot;&gt;Accéder au résumé si vous êtes pressés&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OVH est le dernier arrivé dans le monde du PaaS avec son &lt;a href=&quot;https://www.ovh.com/fr/hebergement-web/cloud-web.xml&quot;&gt;offre Cloud Web&lt;/a&gt;, ce n’est pas son domaine d’expertise, et ça se ressent vite, très vite.&lt;/p&gt;
&lt;p&gt;Tout d’abord, première mauvaise surprise, il est impossible de commander une offre Cloud Web pour moins de 12 mois.&lt;/p&gt;
&lt;p&gt;Si vous ne souhaitez pas commander un nom de domaine avec l’offre Cloud Web (car vous en avez déjà un), il est impossible de sauter cette étape lors de la commande de l’offre par l’interface OVH. Il est cependant possible de contourner cette étape si vous commandez l’offre par l’API d’OVH.&lt;/p&gt;
&lt;p&gt;A priori, les équipes travailleraient à lever ces contraintes, mais de source interne, ça ne sera pas traité avant de longs mois (sans garanties). Mais soyons clairs, certains concurrents proposent de la &lt;strong&gt;facturation à la minute&lt;/strong&gt;, donc débourser ~490€ TTC pour faire quelques tests sur du Cloud Web 3, ou même si l’on se projette sur notre parc de Wordpress de 120+ projets, cela reviendrait à un ticket d’entrée de ~&lt;strong&gt;60,000€&lt;/strong&gt; sans garantie que nos clients restent un an chez nous.&lt;/p&gt;
&lt;p&gt;Je suis rentré en contact avec une personne de chez OVH pour lui faire remonter ces problèmes. On m’a proposé de m’offrir l’offre Cloud Web 3 pour 1 an, en échange de feedbacks sur le produit. Merci pour cette proposition.&lt;/p&gt;
&lt;p&gt;Dès que j’ai eu accès au produit, j’ai voulu mettre PHP 7.3 et créer mes variables d’environnement afin de pouvoir configurer le wordpress et faire mes tests de performances. Mais je me suis heurté à des problèmes, dont un qui m’a empêché toute utilisation du produit :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PHP 7.3 n’est pas disponible, il est pourtant sorti le 6 Décembre 2018, soit depuis plus d’un mois lors de la création de cet article&lt;/li&gt;
&lt;li&gt;Pas de gestion de permissions (autre que pour le gestionnaire/contact technique) pour donner par exemple accès à la gestion des variables d’environnement pour un ensemble de personnes d’une équipe&lt;/li&gt;
&lt;li&gt;J’ai créé des variables d’environnement, certaines se sont créées en quelques secondes/minutes, et d’autres, rien après 15 minutes de “En cours de création”. Je me suis mis à fouiller l’UI avant de découvrir que la tâche de création de certaines variables était en erreur (sans plus de détails)&lt;/li&gt;
&lt;li&gt;Pas de gestion de “bulk insert” des variables d’environnement. J’ai dû répéter les opérations de création de variable 20 fois à cause de ce manque&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;a href=&quot;https://devops-life.com/img/ovh-environment-variables-bug.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;https://devops-life.com/img/ovh-environment-variables-bug.png&quot; alt=&quot;La création de ces variables d&apos;environnement sur OVH sont &apos;en cours&apos; depuis 14 jours sans possibilité de les supprimer ou de les modifier&quot; loading=&quot;lazy&quot; width=&quot;610&quot; height=&quot;302&quot; decoding=&quot;async&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;La création de ces variables d&apos;environnement sur OVH sont &apos;en cours&apos; depuis 14 jours sans possibilité de les supprimer ou de les modifier&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h4 id=&quot;le-support-dovh&quot;&gt;Le support d’OVH&lt;/h4&gt;
&lt;p&gt;Sans possibilité de modifier ou de supprimer les variables “fautives”, &lt;strong&gt;je suis bloqué&lt;/strong&gt; dans ma configuration, je me tourne donc vers le support.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le 8 janvier 2019, ouverture du ticket au support pour signaler que je ne peux pas utiliser le produit à cause de mon problème de variables d’environnement&lt;/li&gt;
&lt;li&gt;Le 21 janvier 2019, soit &lt;strong&gt;13 JOURS après&lt;/strong&gt;, je reçois la première réponse du support qui peut être résumé à : “Nous sommes désolés pour la prise en charge tardive du ticket, des administrateurs sont en train de vérifier votre demande.”&lt;/li&gt;
&lt;li&gt;Le 23 janvier 2019, on m’informe que les opérations en erreur ont été annulées, et on m’invite à réessayer sans m’expliquer ce qu’il s’est passé.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;résumé-ovh-cloud-web-tldr&quot;&gt;Résumé OVH Cloud Web (TLDR)&lt;/h4&gt;
&lt;h4 id=&quot;-inconvénients&quot;&gt;👎 Inconvénients&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Engagement annuel&lt;/li&gt;
&lt;li&gt;Pas de paiement mensuel&lt;/li&gt;
&lt;li&gt;Impossible de commander sans domaine associé par l’interface web&lt;/li&gt;
&lt;li&gt;Documentation très pauvre et incomplète&lt;/li&gt;
&lt;li&gt;Pas de déploiement par Git&lt;/li&gt;
&lt;li&gt;Pas de déploiement automatique via app Github/Gitlab&lt;/li&gt;
&lt;li&gt;Pas de scaling horizontal, vertical&lt;/li&gt;
&lt;li&gt;Pas &lt;a href=&quot;https://en.wikipedia.org/wiki/Autoscaling&quot;&gt;d’auto-scaling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Le support d’OVH : à proscrire&lt;/li&gt;
&lt;li&gt;Pas de gestion de permissions pour donner les droits d’accès à une équipe sur les variables d’environnement par exemple&lt;/li&gt;
&lt;li&gt;UX/DX pauvres sur la gestion des variables, en plus d’être buggées&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;-avantages&quot;&gt;👍 Avantages&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Backup automatisés&lt;/li&gt;
&lt;li&gt;Intégration avec let’s encrypt&lt;/li&gt;
&lt;li&gt;Réseau OVH&lt;/li&gt;
&lt;li&gt;C’est à peu près tout… 🤷‍♂️😱&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;️-verdict--eliminé-️&quot;&gt;⛔️ &lt;strong&gt;VERDICT : ELIMINÉ&lt;/strong&gt; ⛔️&lt;/h4&gt;
&lt;p&gt;Difficile d’émettre un jugement définitif quant aux offres PaaS d’OVH tant que l’on ressent qu’elles ont besoin de maturer encore afin de répondre au besoin du marché. Honnêtement, j’étais frustré et déçu sur le fait de ne pas avoir pu benchmarker la performance de leur offre Cloud Web 3.&lt;/p&gt;
&lt;p&gt;Mes aprioris sur le support se sont malheureusement confirmés, de ce fait, je ne peux conseiller à personne cette offre dans le cadre professionnel, où au moindre souci, vous attendez des semaines la réponse du support (à moins de les harceler sur Twitter), et ce, même si c’est critique pour le service.&lt;/p&gt;
&lt;p&gt;Quant à une utilisation personnelle, qui est capable de sortir ~490€ d’un coup pour héberger son “side project” personnel pour une offre PaaS ? 🙊&lt;/p&gt;
&lt;h2 id=&quot;lire-la-partie-iii&quot;&gt;Lire la partie III&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Part3. &lt;a href=&quot;https://devops-life.com/blog/2019/01/21/paas-clever-cloud-comparatif/&quot;&gt;Comparatif PaaS : Clever Cloud, le bateau prend l’eau&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><dc:creator>Tristan Bessoussa</dc:creator><dc:language>fr</dc:language><category>PaaS</category><category>Performances</category><category>OVH</category><category>Hosting</category><category>Cloud</category></item></channel></rss>