diff --git a/content/en/post/pragmatic-architecture-for-productions/index.md b/content/en/post/pragmatic-architecture-for-productions/index.md new file mode 100644 index 0000000..254cd71 --- /dev/null +++ b/content/en/post/pragmatic-architecture-for-productions/index.md @@ -0,0 +1,181 @@ +--- +title: The pragmatic architecture of my production projects +date: !!timestamp '2026-03-05 15:00:00' +tags: +- architecture +- web +- infrastructure +--- + +Reading some discussions between developers or software architects, one might +think that the smallest web application today requires a distributed +infrastructure, a Kubernetes cluster, and several specialized cloud services. + +Yet many web services (including those that receive several thousand visitors +per day) can work perfectly well with a much simpler architecture. + +Here is a hands-on account of the infrastructure I use for my production +projects, some of which exceed 2,000 daily visitors, and which I also applied +for years during a cybersecurity competition with more than 250 on-site +participants. + + + +# Context + +For a long time, I hosted all my projects from home. My websites, services, Git +forge, and even my continuous integration infrastructure ran on small ARM +machines (mainly Pine64 boards). + +Contrary to what I hear everywhere, it worked very well. + +The main reason I stopped is not a problem of computing power or reliability, +but simply my shift to a more nomadic lifestyle. A stable, permanent residential +connection becomes hard to guarantee when you travel often. + +I therefore moved the public-facing part of my services to OVH, trying to keep +the same philosophy: simplicity and pragmatism. + + +# A simple observation + +In many modern web projects, the architecture looks something like this: + +``` +user → CDN → frontend → API → database +``` + +Every request triggers server-side computation, even when the content changes +very rarely. + +In my case, several of my sites share an important characteristic: **the main +content changes once a day.** + +Take the [daily game Yakazu](https://yakazu-gratuit.fr/) as an example: for the +vast majority of visitors, the only thing that matters is **the grid of the +day**, which changes just once a day. + +Under these conditions, generating the page dynamically on every request does +not make much sense. + +# Chosen architecture + +The solution is therefore very simple: the site is entirely static. + +Every day, a scheduled event triggers the CI pipeline which: + +1. generates the new grid; +2. rebuilds the site; +3. publishes the static files. + +These files are then served directly by the static hosting included with the +domain name at OVH. + +Yes, the free 100 MB plan. + +This gives a very simple architecture: + +``` +CI → site generation → static files → OVH +``` + +All traffic is absorbed by the hosting provider's infrastructure, which is +exactly what it is designed for. + + +# Frontend + +The site is built with SvelteKit. + +This choice might seem surprising since I don't use the server-side capabilities +of this framework at all. But it allows: + +- easily generating a static site (`@sveltejs/adapter-static`); +- clean routing; +- well-structured code; +- building Progressive Web Apps. + +In other words: a modern framework, but without depending on a permanent +backend. + +# And when a backend is needed? + +Some features still require a bit of server-side logic. + +For instance, regularly held championships need to verify participations and +record results and times. + +In that case, I spin up a small separate backend server, which only receives a +very limited number of requests. + +The architecture then becomes: + +``` +static site → CORS → small backend +``` + +This backend is deliberately minimal and only handles actions that cannot be +performed on the client side. + +The key point is that **the vast majority of traffic never touches it**. + +# Results + +With this architecture: + +- almost all traffic is served as static files; +- there is virtually no server-side computation; +- the failure surface is very small. + +The issues I encounter are almost always related to the generation pipeline: + +- an outdated Docker image; +- a CI trigger that fails; +- something missing in the data generation (the absence of a game grid, for example). + +But these problems are easy to detect and usually fixed within minutes. + +# Why keep it simple? + +Looking back, I realize this approach follows a few simple principles: + +1. **pre-compute what can be pre-computed**; +2. **serve files rather than computation**; +3. **reserve the backend for cases that truly need it**. + +These principles often make it possible to handle significant load with very +modest resources. + +For more than ten years, I organized a cybersecurity challenge that eventually +hosted around 300 simultaneous participants, with very basic machines. + +The secret was not the hardware's power, but the system's design. I invite you +to watch my [presentation of this +infrastructure](https://youtube.com/watch?v=naFxBW5yoUA), with the trial and +error, the mistakes, and the constraints that shaped it. + +# What about user accounts and payments? + +A "login" to a user account does not necessarily require systematic validation +by a backend (and the notion of a user account is not always meaningful anyway). + +A single API request can handle authentication (whether verifying a payment or +an email address, ...) and then you store that response in the browser to use in +the interface: right away... or even later. That way, there is no need to make +another API request for information you already have. + +Not only does this reduce server load, it also speeds up page loading for the +user, who sees their data without a network call — and therefore even offline. +Everyone wins. + +# Conclusion + +Modern infrastructure offers many very powerful tools. But it is sometimes worth +remembering that many problems can be solved in a much simpler way. + +Before adding a new technological layer, it is often worth asking a very simple +question: + +**does this content really need to be generated on every request?** + +In many cases, the answer is no. diff --git a/content/fr/post/pragmatic-architecture-for-productions/index.md b/content/fr/post/pragmatic-architecture-for-productions/index.md new file mode 100644 index 0000000..1268127 --- /dev/null +++ b/content/fr/post/pragmatic-architecture-for-productions/index.md @@ -0,0 +1,198 @@ +--- +title: L'architecture pragmatique de mes projets en production +date: !!timestamp '2026-03-05 15:00:00' +tags: +- architecture +- web +- infrastructure +--- + +Lorsqu'on lit certaines discussions entre développeurs ou architectes +logiciels, on pourrait croire que la moindre application web nécessite +aujourd'hui une infrastructure distribuée, un cluster Kubernetes et +plusieurs services cloud spécialisés. + +Pourtant, de nombreux services web (y compris ceux qui accueillent +plusieurs milliers de visiteurs par jour) peuvent fonctionner +parfaitement avec une architecture beaucoup plus simple. + +Voici un retour d'expérience sur l'infrastructure que j'utilise pour +mes projets en production, dont certains dépassent les 2000 visiteurs +quotidiens, et que j'ai également appliqué pendant des années lors +d'une compétition de sécurité informatique avec plus de 250 +participants en présentiel. + + + +# Contexte + +Pendant longtemps, j'ai hébergé l'ensemble de mes projets directement +chez moi. Mes sites web, mes services, ma forge Git et même mon +infrastructure d'intégration continue tournaient sur de petites +machines ARM (principalement des Pine64). + +Contrairement à ce que j'entends partout, cela fonctionnait très bien. + +La principale raison pour laquelle j'ai arrêté n'est pas un problème +de puissance de calcul ou de fiabilité, mais simplement mon passage à +un mode de vie plus nomade. Une connexion résidentielle stable et +permanente devient difficile à garantir lorsque l'on se déplace +souvent. + +J'ai donc déplacé la partie publique de mes services chez OVH, en +essayant de conserver la même philosophie : simplicité et pragmatisme. + + +# Une observation simple + +Dans beaucoup de projets web modernes, l'architecture ressemble à +quelque chose comme ceci : + +``` +utilisateur → CDN → frontend → API → base de données +``` + +Chaque requête déclenche du calcul côté serveur, même lorsque le +contenu change très rarement. + +Dans mon cas, plusieurs de mes sites ont une caractéristique +importante : **le contenu principal change une fois par jour.** + +Prenons par exemple le [jeu quotidien +Yakazu](https://yakazu-gratuit.fr/) : pour la majorité des visiteurs, +la seule chose qui compte est **la grille du jour**, qui ne change +qu'une fois par jour. + +Dans ces conditions, générer la page dynamiquement à chaque requête +n'a pas beaucoup de sens. + +# Architecture retenue + +La solution est donc très simple : le site est entièrement statique. + +Chaque jour, un événement déclenche la CI qui : + +1. génère la nouvelle grille ; +2. reconstruit le site ; +3. publie les fichiers statiques. + +Ces fichiers sont ensuite servis directement par l'hébergement +statique fourni avec le nom de domaine chez OVH. + +Oui, l'offre gratuite de 100 MB. + +Cela donne donc une architecture très simple : + +``` +CI → génération du site → fichiers statiques → OVH +``` + +Tout le trafic est absorbé par l'infrastructure de l'hébergeur, ce +qui est exactement ce pour quoi elle est conçue. + + +# Frontend + +Le site est construit avec SvelteKit. + +Ce choix peut surprendre puisque je n'utilise pas du tout les +capacités serveur de ce framework. Mais il permet : + +- de générer facilement un site statique (`@sveltejs/adapter-static`) ; +- d'avoir un routage propre ; +- de structurer le code proprement ; +- de construire des Progressive Web Apps. + +Autrement dit : un framework moderne, mais sans dépendre d'un backend +permanent. + +# Et quand il faut un backend ? + +Certaines fonctionnalités nécessitent malgré tout un peu de logique +serveur. + +Par exemple, les championnats organisés régulièrement doivent vérifier les +participations et enregistrer les résultats et les chronos. + +Dans ce cas, je démarre un petit serveur backend séparé, qui ne reçoit +qu'un nombre très limité de requêtes. + +L'architecture devient alors : + +``` +site statique → CORS → petit backend +``` + +Ce backend est volontairement minimal et ne traite que les actions +qui ne peuvent pas être réalisées côté client. + +Le point important est que **la majorité du trafic ne le touche +jamais**. + +# Résultat + +Avec cette architecture : + +- la quasi-totalité du trafic est servie sous forme de fichiers ; +- il n'y a quasiment pas de calcul côté serveur ; +- la surface de panne est très réduite. + +Les problèmes que je rencontre sont presque toujours liés au pipeline +de génération : + +- une image Docker qui n'est plus à jour ; +- un déclenchement CI qui échoue ; +- un oubli dans la génération des données (l'absence de grille de jeu par exemple). + +Mais ces problèmes sont faciles à détecter et se corrigent +généralement en quelques minutes. + +# Pourquoi faire simple ? + +Avec un peu de recul, je me rends compte que cette approche suit +quelques principes simples : + +1. **pré-calculer ce qui peut l'être** ; +2. **servir des fichiers plutôt que du calcul** ; +3. **réserver le backend aux cas réellement nécessaires**. + +Ces principes permettent souvent d'absorber une charge importante +avec des ressources très modestes. + +Pendant plus de dix ans, j'ai par exemple organisé un challenge de +sécurité informatique qui a fini par accueillir environ 300 +participants simultanés, avec des machines très simples. + +Le secret n'était pas la puissance du matériel, mais la conception du +système. Je vous laisse visionner ma [présentation de cette +infrastructure](https://youtube.com/watch?v=naFxBW5yoUA), avec les +tâtonnements, les erreurs et les contraintes qui l'ont façonné. + +# Et les comptes utilisateurs, les paiements ? + +Une "connexion" à un compte utilisateur n'a pas nécessairement besoin +d'une validation systématique par un backend (d'ailleurs la notion de +compte utilisateur n'a pas toujours de sens). + +Une seule requête d'API peut faire l'authentification (que ce soit +la validation d'un paiement ou d'une adresse email, ...) puis on +stocke cette réponse dans le navigateur pour en faire usage dans +l'interface : maintenant ... ou même plus tard. Comme ça, inutile de +refaire une requête à l'API pour une information que l'on a déjà. + +Non seulement cela réduit la charge du serveur, mais cela accroit +aussi la vitesse de chargement pour l'utilisateur qui voit ses données +sans appel réseau, et donc même hors ligne. Tout le monde est gagnant. + +# Conclusion + +L'infrastructure moderne propose de nombreux outils très puissants. +Mais il est parfois utile de se rappeler que beaucoup de problèmes +peuvent être résolus de manière beaucoup plus simple. + +Avant d'ajouter une nouvelle couche technologique, il vaut souvent la +peine de se poser une question très simple : + +**est-ce que ce contenu doit vraiment être généré à chaque requête ?** + +Dans bien des cas, la réponse est non.