---
title: "Concevoir une application scalable sans magie"
date: 2020-05-11
language: fr
topics: ["cloud", "data", "design", "howto", "iOS", "lemmid-store", "programming", "server", "smartphone", "web", "webdesign"]
source_url: https://willem.com/fr/2020-05-11_concevoir-une-application-scalable-sans-magie/
---
# Concevoir une application scalable sans magie

*Exploiter la puissance de calcul des clients pour de hautes performances avec beaucoup d'utilisateurs*

> Pour l'appli de commande de repas en ligne que je construis, j'avais besoin de concevoir une infrastructure backend scalable, capable de gérer beaucoup d'utilisateurs simultanés. La scalabilité passe pour un problème difficile. On la présente souvent comme quelque chose de magique, réservé aux entreprises qui brassent des millions de dollars avec des outils secrets. Mais la magie n'existe pas, ou bien si ?

## Qu'est-ce que la scalabilité ?

Quand tu construis une appli, tu démarres sans doute très petit. Quelques utilisateurs (ou juste toi, le développeur) qui l'utilisent. Tout va bien : l'appli fonctionne bien, vite, et il n'y a aucun problème. *(savoure ce moment !)*

![Un utilisateur qui interagit avec un serveur](https://willem.com/global/images/02bda6e71f78.webp)

Dans ce scénario de départ, tout petit, le serveur unique qui fait tourner l'appli peut gérer l'utilisateur qui interagit avec elle. Chaque fois que l'utilisateur touche ou clique sur un bouton, le serveur unique fait un peu de travail. Si tu programmes bien, ces charges peuvent être optimisées en petits blocs de travail efficaces. Faire ainsi est un exemple typique d'architecture_logicielle_monolithique (https://willem.com/en/2020-03-03_monolithic-vs-microservices-software-architecture/).

Même si ton projet ou ton appli est plutôt petit, il peut arriver un moment où les utilisateurs affluent. Si ton système ne supporte pas les fortes charges, il a de grandes chances de tomber en panne.

![Un serveur sous forte charge qui gère plusieurs utilisateurs simultanés](https://willem.com/global/images/0983daa5d3fa.webp)

À cause de la conception_monolithique_de_l'appli (https://willem.com/en/2020-03-03_monolithic-vs-microservices-software-architecture/), tous les utilisateurs interagissent avec le même serveur. Toutes leurs interactions (touches, clics, saisies) sont traitées par ce serveur. Quand la charge augmente, il doit travailler beaucoup plus. À un certain moment, tu remarques que tout ralentit parce que le serveur n'arrive plus à suivre la quantité de travail. Cela signifie que ton appli n'est pas scalable, autrement dit : tu as un problème.

### L'échec au « moment suprême »

Mal passer à l'échelle est un gros problème que personne ne devrait sous-estimer. La plupart des applis (et de leurs modèles économiques) reposent sur de gros volumes avec peu de revenus par utilisateur. Si tu veux que ton appli soit un succès (financier), tu dois t'assurer qu'elle fonctionne bien quand le trafic augmente brusquement. Si ton appli plante au moment où elle attire soudain l'attention des foules, tu rates une occasion « unique dans une vie » de croissance (organique).

D'une certaine manière, concevoir pour la scalabilité, c'est comme garder ta ceinture attachée dans la fusée que tu as construite toi-même, avec des moteurs expérimentaux. Tu ne sais jamais exactement quand elle va s'allumer, mais quand ça arrive, mieux vaut être bien accroché (et profiter du voyage !).

## Façons courantes d'atteindre la scalabilité

On a beaucoup écrit sur la construction d'applis scalables. Voici les façons courantes d'améliorer la scalabilité :

- **Augmenter la capacité du serveur** : ajouter de la mémoire, de la puissance CPU, du stockage. Ça marche, mais ça ne t'emmène que « jusqu'à un certain point ». 

- **Ajouter des serveurs** : au lieu d'un seul serveur qui fait goulot d'étranglement, tu ajoutes des serveurs qui se partagent la charge. C'est plus facile à dire qu'à faire, car il faut de la répartition de charge et du partage de données, ce qui peut être délicat (par ex. si tu as un compteur de commandes et que deux serveurs comptent, lequel détermine le numéro suivant ?)

- **Optimiser le code** : utilise les bons outils ! Choisis un langage de programmation orienté performance et un logiciel serveur idem. Intéresse-toi à la programmation fonctionnelle pour que ton code tourne de façon asynchrone sur plusieurs cœurs. Rends-le sans état. Mesure ses performances. Optimise-le. Chaque milliseconde gagnée sur une requête s'additionne vite quand tu traites de gros volumes. 

- **Utiliser la base de données et la séparer du serveur d'application** : si tu utilises une base de données, exploite sa puissance ! Profite du cache de requêtes, des index et des capacités de recherche. La plupart des solutions de base de données offrent des options de clustering éprouvées ; n'essaie pas de réinventer la roue que d'autres ont déjà perfectionnée.

Le mieux est de considérer toutes ces options. Même si tu n'ajoutes pas de serveurs tout de suite, écris ton code pour pouvoir le faire plus tard. Mesurer et optimiser ton code doit faire partie intégrante de ton travail, pas être une simple réflexion après coup.

## Exploiter la puissance de calcul des clients

Quand tu as passé en revue toutes les façons courantes d'atteindre la scalabilité, il y a « encore une chose ».

![Les smartphones (et tablettes, PC) sont devenus plus puissants au fil des ans (image : Apple)](https://willem.com/global/images/e4d580ef3ee0.webp)

Peu de développeurs y pensent : le problème de scalabilité contient la solution ! Quand tu as 1000 utilisateurs, tu as 1000 ordinateurs avec des CPU puissants et beaucoup de mémoire. Les ordinateurs et smartphones modernes sont de plus en plus capables.

Il suffit de trouver comment puiser dans la puissance de calcul du client. Ça peut sembler diabolique (utiliser la puissance de calcul de l'utilisateur), mais ça lui offre une expérience bien meilleure et plus rapide. Le plus beau, c'est que *sa* puissance de calcul sert à *son* expérience fantastique, et résout ton problème de scalabilité par un heureux effet secondaire.

![Exploiter l'appareil de l'utilisateur : son téléphone fait l'essentiel du travail que faisait à l'origine le serveur](https://willem.com/global/images/3b24ef5be7d6.webp)

En exploitant la puissance de calcul de l'utilisateur, tu réduis la quantité de travail du serveur. Au lieu que le serveur fasse un peu de travail *chaque* fois que l'utilisateur touche ou clique sur un bouton, ce travail est maintenant surtout effectué par l'appareil de l'utilisateur. C'est plus efficace que de communiquer avec un serveur via une connexion Wi-Fi/4G (on économise batterie et temps).

Cela demande de repenser un peu les choses, mais ce principe s'applique aussi aux applications web. Au lieu de tout gérer sur le serveur, tu peux faire beaucoup de travail côté client. La recherche, la navigation, le filtrage, le passage d'une page à l'autre et même l'ajout d'articles au panier peuvent se faire avec du JavaScript côté client. À toi, cher développeur, de trouver comment y arriver, mais si tu réussis, tu auras une scalabilité quasi infinie à portée de main.

## En pratique : l'appli de commande de repas

Pour l'appli_de_commande_de_repas (https://willem.com/en/2020-05-01_designing-an-interface-for-a-food-ordering-page/), j'ai cherché des moyens d'exploiter la puissance de calcul du client pour obtenir de hautes performances. Le principal défi des commandes de livraison et à emporter, c'est qu'elles se concentrent autour de l'heure du dîner. Beaucoup de gens utilisent l'appli en même temps : c'est la recette parfaite pour des problèmes de scalabilité.

![Commander des repas en ligne](https://willem.com/global/images/d08b396a761f.webp)

Si tu penses à la commande de repas en ligne, tu peux découper tout le processus en petites étapes :

- **1) Ouvrir la page** : charger l'appli/la page

- **2) Parcourir les différentes options** : afficher la liste des produits, leurs descriptions, prix, photos, etc.

- **3) Chercher quelque chose de précis** : recherche par catégorie, nom de produit, etc.

- **4) Choisir un produit** : l'ajouter à ta commande

- **5) Personnaliser un produit** : choisir une sauce, un accompagnement, un supplément, etc. 

- **6) Saisir tes informations** : ton nom, ton numéro de téléphone, les détails de livraison, etc. 

- **7) Payer ta commande** : choisir un moyen de paiement, se connecter à ta banque ou à ta carte de crédit

- **8) Fermer l'appli**

La plupart de ces étapes peuvent être programmées de façon que le serveur ne soit *pas nécessaire*. Seules l'étape 1 (**chargement**) et l'étape 7 (**paiement**) exigent un contact avec l'infrastructure backend. Il est important de comprendre que les étapes 2 à 5 se répètent plusieurs fois, puisque les utilisateurs ajoutent souvent plusieurs produits à leur commande.

![Séparer la charge restante du serveur : servir les produits et gérer les commandes](https://willem.com/global/images/1d2831da7a52.webp)

En séparant la charge restante par tâche, on peut encore optimiser le logiciel. Le **« serveur de produits »** est optimisé pour servir des ressources statiques (textes, prix, images) qui permettent au client de construire l'expérience de navigation dans les produits. On peut très fortement optimiser ce type de serveur grâce au cache, à HTTP/2, à la compression, etc.

Seuls les utilisateurs qui vont au bout de la commande sont transmis au **« serveur de commandes »**, qui gère le paiement. Il se connecte au prestataire de paiement. Une fois le paiement terminé, le prestataire contacte le serveur de commandes pour l'informer de l'état du paiement. Voilà quelque chose dont tu veux garder le contrôle total (côté serveur), comme quand j'ai_conçu_un_système_de_paiement (https://willem.com/en/2020-03-25_designing-and-implementing-a-micro-payment-system/) auparavant. La charge restante sur le « serveur de commandes » est bien plus petite, car tout le monde ne passe pas commande, et une grande partie du traitement des commandes peut se faire en arrière-plan.

![Gérer beaucoup de trafic grâce à l'informatique distribuée](https://willem.com/global/images/4c106f30570a.webp)

Pour maximiser la scalabilité, tu peux facilement ajouter plusieurs serveurs (ou utiliser un réseau de diffusion de contenu) pour servir les ressources statiques. Pour l'appli de commande de repas, j'utilise un « serveur de produits » distinct *par restaurant*. Cela donne de hautes performances et réduit les temps de chargement. Les gens remarquent que c'est rapide, certains n'arrivent pas à croire que c'est du web : c'est *presque* magique.

## Conclusion

Concevoir une application scalable est possible sans magie ni budgets à plusieurs millions. Il suffit d'y réfléchir et de chercher les opportunités qui accompagnent les défis.

Le problème contient la solution. Gérer beaucoup d'utilisateurs simultanés n'est pas qu'un problème : ils apportent leur propre puissance de calcul, c'est la solution ! Il suffit de l'utiliser.
