PART 3 : FIN !

Comment j’ai construit une plateforme BI sans me suicider (Pt 3 — END).

Orbit Turner

--

OPTIMISATION LIFECYCLE

UN DEVELOPPEUR ? KESAKO?🤔

On va parler sérieusement.

C’est bien beau tout çà. C’est super de voir à quel point les technologies ont évolué pour en arriver là. Cette rapidité, ces frameworks à tout faire etc.

Mais tout commence par la base : les BASICS.
J’ai constaté que de nos jours cette même beauté des technos qui font la course au plus ouvert ou à celle qui la plus courte “learning curve”, à fait que plein de débutant ou de nouveau venu se sont rué vers cette facilité oubliant de passage ce que c’est réellement développer.

Coder, c’est facile. Tout le monde est capable de mémoriser du code ou de faire dire à une machine “1+1 = 2”. Mais DEVELOPPER est une autre chose, une science, une philosophie, un état d’esprit.

Développer ce n’est pas suivre un tuto de 10 minutes sur comment faire une todo liste avec react et le reproduire.
Non ! Ce n’est pas non plus lire et retenir par cœur tous les livres sur les Design Patterns, le clean code, les structures de données…

Être développeur ce n’est pas connaitre des algorithmes mais c’est Algorithmer. Ce n’est pas maîtriser toutes les technos mais c’est savoir répondre efficacement et rapidement à un besoin, une problématique en prenant en compte le contexte et les facteurs secondaires avec les ressources adéquates.

Enfin c’est savoir créer si çà n’existe pas car derrière un framework c’est avant tout un langage de programmation qui lui-même est un ensemble de paradigme de programmation. Dans certain il est préférable de comprendre comment est créé la structure plutôt que d’y être un simple locataire.

Avant de parler optimisation, cache, load-balancing, Vertical/Horizontal Scaling il faut parler algo et langage.

SELF OPTIMISATION

En tant que dev on est amené à toucher énormément de technologie cela dit rien ne nous empêche de nous spécialiser dans un langage de notre choix qui représentera notre base algorithmique. Tout comme Jeff Delaney plus connu sur la chaine #fireship, j’ai appris par moi même pleins de technos.

Mais je me suis récemment spécialisé sur JS car j’en avais envie et que c’était aussi un très large univers.

Juste avant de commencer ce projet, j’avais eu la très bonne idée de recommencer JS depuis la base pour remonter même si cela faisait plusieurs années que je l’utilisais avec ces frameworks. Et j’ai été surpris !

Surpris de voir que JE NE SAVAIS RIEN !

C’était comme si il y avait JS qui était la vrai technos et moi depuis tout ce temps je faisais quelques choses de très similaire mais qui ne l’était pas le HS.

Redécouvrir le langage de base sur lequel mon projet était fait m’a permis non seulement d’écrire du code de plus en plus logique mais de plus en plus performant.

Réapprendre la logique asynchrone, le RxJs, les DataStructures m’ont permis de non pas multiplier mais de rendre exponentielle la vitesse d’exécution de certains traitements. Et même mon ordinateur était plus heureux: On était devenu Potes à nouveau 🥳

Me and My Computer’s Incarnation Dancing👨🏾‍🦯

Les Design Patterns, les architectures et toutes les méthodologies que l’on passe nos journées à lire, ont fini par rentrer naturellement, en fonction des problèmes que je rencontrais mais ce qui ne viendra jamais naturellement C’est une bonne Algorithmique/Logique. Çà on le cultive !

CODE OPTIMISATION

Il y a une tonne de manière d’optimiser un code. Mais dans tous les cas cela se fait progressivement.

On ne peut pas avoir une demande urgente avec une deadline serrée et se dire qu’on va faire le Héros en écrivant du Code Parfaitement “CLEAN”. Si tu t’obstines à le faire il est très fort probable que la chaise de ton bureau les prochains mois soit parfaitement clean et ton compte bancaire aussi.

You’ll be nicely fired ! 👨🏾‍🦯👨🏾‍🦯

Attention ! 🙄 Je vous vois venir cela ne veut pas dire que tu ne dois pas écrire du code lisible et logique mais juste que le fait qu’il soit clean, organisé et optimisé ce fais progressivement après que la logique de la feature demandée est déjà étée implémentée.

UTILISER LES METHODES DU LANGAGE

Chaque langage vient avec ses innombrables fonctions embarquées. Celles-ci ont été souvent faites en prenant en comptant tous les aspects de performances. Elles sont vos meilleures amies pour vous éviter de télécharger énormément de dépendances inutiles ou de créer un autre bordel qui tuera le prochain développeur à se pencher dessus.

En ce qui concerne Javascript, les ‘Built-in Functions’ (tels que les méthodes sur les arrays, etc) sont vos meilleurs amis. Il est très peu probable que vous ayez besoin de quelque chose qui n’a pas déjà été fait.

BE ASYNC !

Le codage asynchrone est largement utilisé dans Node.js pour assurer un flux opérationnel non bloquant. Les E/S asynchrones permettent à d’autres traitements de continuer avant même la fin de la première transmission. Le codage synchrone peut potentiellement ralentir votre application. Il utilise des opérations de blocage qui pourraient bloquer votre fil principal, ce qui réduira considérablement les performances de votre App.

L’impact est énorme ! On parle parfois d’une notation Big O en “O(log n)”.

Exemple : Ci-dessous nous avions une fonction qui permettait de séquencer des opérations. Le problème est que chaque ligne ici attend celle précédente avant de se lancer.

First Version Of Sequentializer

Après une p’tite optimisation nous avons :

Second Version

Je sais 😑 Le résultat n’est pas retourné pour certaines raisons, IT’S NOT THE POINT.

Ci-dessus on exécute les lignes de la première séquence simultanément ce qui nous permet de diviser par 4 le temps d’attente. Notez l’élégance du “Promise.all()” 😍JS est vraiment…🥰

Imagines-toi maintenant faire cela partout où c’est possible. La rapidité du système se fait ressentir sur tous les modules. Par exemple j’ai certaines règles qui me force toujours à la volée de penser et d’écrire du code plus ou moins optimisé. Comme :

  • J’éviterais toujours de parcourir totalement un tableau”
  • Je vérifierais toujours si une chose n’existe pas avant de le faire.
  • Je n’ai pas besoin de commentaire si le code parle de lui-même

Etc… C’est peut-être bête mais c’est avec çà que je m’en sors toujours. (Presque 😂).

En comparaison il nous arrivait d’attendre 8 à 10 minutes pour visualiser un graphique sur la suivie de production. Aujourd’hui cela ne nous prend que ~200ms si on désactive le cache REDIS car avec le cache la même requête prend ~4ms.

AVOID MEMORY LEAKS

Unsubscribe your Subscribers !!!!

J’ai passé deux semaines à courir derrière une lenteur générale au niveau de mon frontend alors je vous recommande cette pépite qui, si vous utilisez Angular réglera tous vos soucis:

Je ne vais même pas vous expliquer ce par quoi je suis passé. Voici en tout cas ce à quoi çà ressemble en images :

PERF MONITOR Dealing With Memory Leaks

Et voilà ceux à quoi doit ressembler le moniteur de Perf en temps normale :

PERF MONITOR AFTER PREVENTING ML !

Dans notre cas “l’Unsub ”est fait automatiquement par un helper. Si vous voulez éviter ce genre de chose mieux vaut utiliser l’async pipe au maximum sur vos Comp.HTML.

Une fois que vous maitrisez assez votre workflow de développement et que vous avez optimisé au maximum votre code, Il est alors temps de mettre en cache certains traitements ou données.

SUPPRIMEZ LES TEMPS D’ATTENTE AVEC UN CACHE !

La mise en cache côté serveur est l’une des stratégies les plus courantes pour améliorer les performances d’une application Web. Son objectif principal est d’augmenter la vitesse de récupération des données, soit en passant moins de temps à calculer ces données ou à effectuer des E/S (telles que la récupération de ces données sur le réseau ou à partir d’une base de données).

Un cache est une couche de stockage à grande vitesse utilisée comme stockage temporaire pour les données fréquemment consultées. Vous n’avez pas besoin de récupérer les données de la source principale (généralement beaucoup plus lente) des données à chaque demande.

La mise en cache est plus efficace pour les données qui ne changent pas très souvent. Si votre application reçoit de nombreuses demandes pour les mêmes données inchangées, le stockage dans un cache améliorera considérablement la réactivité de ces demandes. Vous pouvez également stocker les résultats de tâches gourmandes en calculs dans le cache, tant qu’il peut être réutilisé pour d’autres requêtes. Cela évite que les ressources du serveur ne s’enlisent inutilement en répétant le travail de calcul de ces données.

Un autre candidat courant pour la mise en cache est les requêtes API qui vont à un système externe. Supposons que les réponses puissent être réutilisées de manière fiable pour des requêtes ultérieures. Dans ce cas, il est logique de stocker les demandes d’API dans la couche de cache pour éviter la demande de réseau supplémentaire et tout autre coût associé à l’API en question.

À ce stade je n’étais plus tout seul j’avais un autre grand esprit avec moi et nous avons choisi d’aller sur dû REDIS.

Son intégration avec NestJS était hyper facile et nous disposions de toutes les ressources pour le mettre en place. Dès le premier jour nous étions ébahis du gain de performance que nous venions d’avoir. Nous nous prenions même pour des rivaux à Google car on surfait sur la vibe de la rapidité.

On parlais maintenant de moins de 7ms ! Nous avons passé des jours à célébrer çà.😂😂😂😂

En front la mise en cache côté navigateur faisait déjà le boulot puis la limitation, l’épuration de notre “bundle Size” et la gestion du Memory Leak nous ont permis de ne plus avoir de latence UI.

LE SCALING

Nous avons comme je l’ai dit plutôt, déployé d’abord avant de continuer nos builds et livraisons. Ce workflow très orienté DevOps nous a permis très tôt de penser à des solutions pour le scaling futur de notre application.

Bien que nous ayons toutes les ressources que l’on désirait j’ai toujours refusé d’utiliser plus que ce dont j’avais besoin. Ce qui veut dire que durant toute son existence. L’appli (Front & Back) était déployée dans l’un de nos plus faibles serveurs.

Une machine avec 4 Giga RAM, un disque HDD et un processeur i7. Tout ce qu’il y a de plus banal.

C’était la meilleure manière de nous forcer à avoir une bonne architecture et du bon code optimisé.

D’autant plus que dans ce serveur on trouve aussi d’autre application tels qu’un Project Management Interne que j’ai mis en place et qui gère toutes l’équipe IT (je vous en reparlerais dans un autre article), les fiches de présences, projets/tâches, ainsi que le Helpdesk et les demandes de congés; un serveurs MySQL utilisé par certaines applis mais aussi pour nos tests. Eh OUI ! 😂

Pourtant plus il y avait de module plus la plateforme devenait performante car on appliquait toujours la règle du BoyScout.

Côté CI/CD que ce soit pour le front ou le back nous avons pas mal de scripts exécutés au moment du BUILD qui permettent entre autres de : Versionner l’application, Copier ou déplacer le contenu du “dist” vers le dossier de déploiement, Mettre à jour le GIT & le GITHUB, et d’autres choses effectuées en PostBuild.

HORIZONTAL SCALING

Depuis le début de cet article vous n’avez vu nulle part où je configure un LoadBalancer ou Docker.🧐 Ma plateforme en est-elle affectée ? NON !

Tout est une question de contexte. On ne peut pas tout faire en même temps ni tout maîtriser en même temps. J’ai une tonne de technos que je ne maitrise pas et pourtant cela ne m’empêche pas de faire des choses qui marchent bien.

Nous avons utilisé NGINX comme serveur web et reverse proxy car c’était le plus adéquat et performant pour des applications tournant sur NodeJS. Implémenter un load-balancer ne nous prendrait pas plus de temps une fois la plateforme Dockerisé.

Cependant dès le départ j’ai voulu isolé et monitorer mes applis tournant sur nodeJS sans pour autant avoir à configurer Docker pour chacune d’elles.

Là encore une fois j’ai découvert PM2 !

PM2 est un “process manager” qui permet de faire pas mal de chose avec une appli node. Je vous laisse le plaisir d’aller voir par vous-même.

Mais en gros, il est utile d’utiliser un gestionnaire de processus pour :

  • Redémarrez l’application automatiquement si elle plante.
  • Obtenez des informations sur les performances d’exécution et la consommation de ressources.
  • Modifiez les paramètres de manière dynamique pour améliorer les performances.
  • Contrôler le clustering.

Un gestionnaire de processus est un peu comme un serveur d’applications : c’est un « conteneur » pour les applications qui facilite le déploiement, offre une haute disponibilité et vous permet de gérer l’application au moment de l’exécution.

Une fois toute la configuration faites sur PM2 nous étions capables d’avoir en temps sur console ou en ligne des infos précises sur la plateforme et son utilisation et d’en déduire des actions.

Exemple :

Realtime Log On PM2 WEB
Monitoring Multiple Apps On Different Servers

Mais le plus incroyable c’est le clustering.

C’EST QUOI LE HORIZONTAL SCALING D’ABORD ?

C’est la capacité d’augmenter la capacité du serveur en connectant plusieurs entités matérielles ou logicielles afin qu’elles fonctionnent comme une seule unité logique. L’H-Scaling peut être obtenue à l’aide du clustering, du système de fichiers distribué et du Load Balancing.

Une instance de Node.js s’exécute dans un seul thread, ce qui signifie que sur un système multicœur (ce que sont la plupart des ordinateurs de nos jours), tous les cœurs ne seront pas utilisés par l’application. Pour profiter des autres cœurs disponibles, vous pouvez lancer un cluster de processus Node.js et répartir la charge entre eux.

Avoir plusieurs threads pour gérer les requêtes améliore le débit (requêtes/seconde) de votre serveur car plusieurs clients peuvent être servis simultanément. Nous répartissons la Charge de demande sur plusieurs instances de notre application.

Celle-ci peut être plus ou moins facile à implémenter dans une appli qui vient de démarrer mais dans notre cas c’est au dernier moment qu’on a voulu le faire. Ne me demandez pas pourquoi 😫 C’est la vie! c’est comme çà ! Facebook aussi au début c’était de la merde.👨🏾‍🦯

On avait trop la flemme de retoucher nos modules et/ou toute notre app. C’est là que PM2 nous a encore sorti une carte car du CLUSTERING il est capable de le faire sur app déjà faites. Et comment ?

Bah Juste Comme çà ! 🥳 Il te duplique ton process et gère le balancing lui-même comme un grand ! 🔥✨

THE PM2 GOD

Ce n’est pas tout à chaque nouveau déploiement PM2 reload et mets à jour les instances One by One tout en s’assurant de n’avoir aucune downtime !!

LIST OF ALL RUNNING INSTANCE on Terminal
MONITORING INSTANCES AND THEIR LOGS ON TERMINAL

Si vous voulez en savoir plus sur comment configurer un Clustering avec PM2 je vous conseille cet article :

Async vs MultiThread

Il s’agit d’une idée fausse générale que la programmation asynchrone et le multithreading sont identiques. Mais ils ne le sont pas. La programmation asynchrone concerne la séquence asynchrone des tâches, tandis que le Multithreading est plusieurs threads ou processus fonctionnant en parallèle.

Le Multhreading est un moyen d’asynchrones dans la programmation, mais nous pouvons également avoir des tâches asynchrones sur un single thread.

Le multithread agit au niveau du processeur alors que l’asynchrone est au niveau des opérations du programme.

ENFIN LE SUIVI & LE MONITORING

Avant d’essayer d’améliorer les performances d’un système, il est nécessaire de mesurer le niveau de performance actuel. De cette façon, vous connaîtrez les inefficacités et la bonne stratégie à adopter pour obtenir les résultats souhaités. L’évaluation du niveau actuel de performances d’une application peut nécessiter l’exécution de différents types de tests, tels que les suivants :

  • Test de charge : fait référence à la pratique consistant à simuler l’utilisation attendue d’un système et à mesurer sa réponse à mesure que la charge de travail augmente.
  • Tests de résistance : conçus pour mesurer les performances d’un système au-delà des limites des conditions de travail normales. Son objectif est de déterminer combien le système peut gérer avant qu’il ne tombe en panne et comment il tente de se remettre d’une panne.
  • Spike testing : permet de tester le comportement d’une application lorsqu’elle reçoit une augmentation ou une diminution drastique de la charge.
  • Test d’évolutivité : utilisé pour trouver le point auquel l’application cesse de se mettre à l’échelle et identifier les raisons qui la sous-tendent.
  • Test de volume : détermine si un système peut gérer de grandes quantités de données.
  • Test d’endurance : permet d’évaluer le comportement d’une application logicielle sous une charge soutenue pendant une longue période, pour détecter des problèmes tels que des fuites de mémoire.

L’exécution de certains ou de tous les tests ci-dessus vous fournira plusieurs mesures importantes, telles que :

  • temps de réponse
  • latence moyenne
  • taux d’erreur
  • requêtes par seconde
  • débit
  • Utilisation du processeur et de la mémoire
    utilisateurs concurrents
    et plus.

Après avoir mis en place une optimisation spécifique, n’oubliez pas de relancer les tests pour vérifier que vos modifications ont eu l’effet souhaité sur les performances du système.

Il est également important d’utiliser un outil de surveillance des performances des applications (APM) pour garder un œil sur les performances à long terme d’un système. Différentes solutions de surveillance peuvent s’en occuper pour vous.

Aussi le suivi des utilisateurs et de leurs actions dans le cas d’un produit d’entreprise permet de prévenir les fraudes et actions frauduleux et de dégager la responsabilité ou non de ceux qui sont ciblés.

Juste comme çà 😂😅

Aujourd’hui jours après jours nous continuons à relever des défis et à répondre toujours à des demandes tout aussi folles ! Mais nous n’avons aucune crainte quant à l’évolution et à la rigidité de notre application. Il nous reste beaucoup de choses à parfaire et à implémenter mais nous le faisons avec fierté et sagesse.

Ce n’est pas à cause de mon talent ou de mon génie qu’aujourd’hui cette plateforme est là où il est, NON. C’est parce que j’ai eu la chance d’avoir pu me poser des limites. D’avoir su qu’il fallait poser de petites pierres bout à bout pour avoir cette structure.

J’ai eu aussi la chance d’avoir un DSI avec un mindset incroyable qui m’a permis de tester ce que j’avais en tête. Qui a su tolérer mes erreurs et qui m’a permis d’évoluer.

Mais je dois aussi beaucoup de choses à ce que nous développeur on oublie très souvent, les SOFTSKILLS. Être développeur c’est avoir aussi une intelligence des situations et un certain tact qui permet de saisir les opportunités là où y en a et de faire un impact dans la tête et le cœur des gens.

Car au final on fait un logiciel pour des humains et non de simples utilisateurs.

QUELQUES SCREENSHOT DE LA PLATEFORME

En raison d’un NDA et de tralala pareil je ne vous montrerais pas une version complète de l’application et des autres fonctionnalités. Néanmoins je reste ouvert pour toutes questions supplémentaires.

Login Page
Error Login — Ignore The SnowFlakes
Welcome !
Dark Mode and Eyes Protection

Les utilisateurs reçoivent de jolies mails animés quand une actions importante est effectué sur leur comptes (réinitialisation, blocage, inscription):

Mails
Calcul en temps réel de données saisie sur un tableau remplaçant des feuilles excel

Plusieurs modules nécessitent le remplissage de données ou la création du tableau complexe donc nous avons implémenté un component de Grids qui permet d’avoir soit un élément avec toutes les fonctionnalités Excel soit carrément une alternative à Excel :

Yup We Have Our Own Excel 🥳😂

FIND ME ON MY WEBSITE:

--

--

Orbit Turner

FullStack DevOps | Angular + NestJS & WordPress Lover | Truth Teller • Designer & Entrepreneur 🚀 A MOONWALKER✨