📱 ANDROID — Pourquoi ton app "perd la mémoire" quand tu reviens dessus
T'as déjà ouvert une app, switché sur WhatsApp, répondu à un message, et quand tu reviens sur l'app, elle est en mode "Loading… je retrouve mes petits" ?
C'est pas un bug. C'est le lifecycle d'une Activity.
Sur Android, ton écran (l'Activity) c'est comme un acteur sur scène. Le système peut lui dire à tout moment :
« T'es en pause. » → onPause()
« Tu passes en arrière-plan. » → onStop()
« On a besoin de ta mémoire, dégage. » → onDestroy()
Et ton app ? Elle a 3 secondes pour obéir. Sinon le système la tue, peu importe ce qu'elle faisait.
Pourquoi c'est utile :
Imagine 50 apps ouvertes. Tu scrolles TikTok. Une autre app a besoin de RAM pour afficher une grosse image. Android dit à TikTok "lâche ta mémoire" → TikTok obéit → l'autre app s'affiche. Si TikTok gardait tout pour elle, ton téléphone se transformerait en grille-pain 😭
Le piège que font tous les juniors :
Ils mettent leur code "important" dans onCreate() en pensant qu'il s'exécute "au démarrage de l'app". Faux. onCreate() s'exécute à chaque fois que l'Activity est recréée. Si t'as téléchargé une image de 20 Mo dans onCreate(), elle se retélécharge à chaque fois que le système détruit puis recrée ton Activity.
La bonne pratique :
State à sauvegarder → onSaveInstanceState() (le bundle survit à la mort)
Données lourdes → ViewModel (survit aux changements de config)
Téléchargements → WorkManager (survit même si l'app est tuée)
✅ Résultat : tu scrolles, tu quittes, tu reviens — ton app est exactement où tu l'as laissée.
💾 Enregistre ce post pour ne pas l'oublier.
#Android #MobileDev #Activity #DevTips #MetaCodeLearn
T'as déjà ouvert une app, switché sur WhatsApp, répondu à un message, et quand tu reviens sur l'app, elle est en mode "Loading… je retrouve mes petits" ?
C'est pas un bug. C'est le lifecycle d'une Activity.
Sur Android, ton écran (l'Activity) c'est comme un acteur sur scène. Le système peut lui dire à tout moment :
« T'es en pause. » → onPause()
« Tu passes en arrière-plan. » → onStop()
« On a besoin de ta mémoire, dégage. » → onDestroy()
Et ton app ? Elle a 3 secondes pour obéir. Sinon le système la tue, peu importe ce qu'elle faisait.
Pourquoi c'est utile :
Imagine 50 apps ouvertes. Tu scrolles TikTok. Une autre app a besoin de RAM pour afficher une grosse image. Android dit à TikTok "lâche ta mémoire" → TikTok obéit → l'autre app s'affiche. Si TikTok gardait tout pour elle, ton téléphone se transformerait en grille-pain 😭
Le piège que font tous les juniors :
Ils mettent leur code "important" dans onCreate() en pensant qu'il s'exécute "au démarrage de l'app". Faux. onCreate() s'exécute à chaque fois que l'Activity est recréée. Si t'as téléchargé une image de 20 Mo dans onCreate(), elle se retélécharge à chaque fois que le système détruit puis recrée ton Activity.
La bonne pratique :
State à sauvegarder → onSaveInstanceState() (le bundle survit à la mort)
Données lourdes → ViewModel (survit aux changements de config)
Téléchargements → WorkManager (survit même si l'app est tuée)
✅ Résultat : tu scrolles, tu quittes, tu reviens — ton app est exactement où tu l'as laissée.
💾 Enregistre ce post pour ne pas l'oublier.
#Android #MobileDev #Activity #DevTips #MetaCodeLearn
👏1
⚡ ASTUCE SQL — FILTER, l'arme secrète des agrégations conditionnelles (PostgreSQL)
T'as déjà écrit ça ?
SELECT
COUNT(*) FILTER (WHERE status = 'active') AS actives,
COUNT(*) FILTER (WHERE status = 'banned') AS banned
FROM users;
Ou encore :
SELECT
user_id,
SUM(amount) FILTER (WHERE type = 'purchase') AS total_achats,
SUM(amount) FILTER (WHERE type = 'refund') AS total_rembourses
FROM transactions
GROUP BY user_id;
Tu vois la différence ? Pas de CASE WHEN dans l'agrégat, pas de duplication de la colonne, pas de sous-requête qui rame. Juste FILTER.
C'est quoi en vrai ?
FILTER (WHERE condition) est une clause PostgreSQL (norme SQL standard) qui dit : « applique cette agrégation UNIQUEMENT aux lignes qui matchent la condition ».
Pourquoi c'est mieux que CASE WHEN ?
Compare les deux écritures pour le même résultat :
Cas 1 — FILTER (propre, rapide) :
SELECT
COUNT(*) FILTER (WHERE paid) AS paid_orders,
COUNT(*) FILTER (WHERE NOT paid) AS unpaid_orders
FROM orders;
Cas 2 — CASE WHEN (verbeux) :
SELECT
COUNT(CASE WHEN paid THEN 1 END) AS paid_orders,
COUNT(CASE WHEN NOT paid THEN 1 END) AS unpaid_orders
FROM orders;
Cas 3 — sous-requête (lourd) :
SELECT
(SELECT COUNT(*) FROM orders WHERE paid) AS paid_orders,
(SELECT COUNT(*) FROM orders WHERE NOT paid) AS unpaid_orders;
Cas 1 gagne. Plus lisible, plus rapide (un seul scan de la table), et zéro ambiguïté.
✅ Valeur : FILTER est standard SQL (SQL:2003), disponible dans PostgreSQL, SQLite 3.30+, et quelques autres. Sur MySQL par contre, faudra rester sur CASE WHEN.
💾 Enregistre ce post pour ne pas l'oublier.
#SQL #PostgreSQL #DevTips #WebDev #MetaCodeLearn
T'as déjà écrit ça ?
SELECT
COUNT(*) FILTER (WHERE status = 'active') AS actives,
COUNT(*) FILTER (WHERE status = 'banned') AS banned
FROM users;
Ou encore :
SELECT
user_id,
SUM(amount) FILTER (WHERE type = 'purchase') AS total_achats,
SUM(amount) FILTER (WHERE type = 'refund') AS total_rembourses
FROM transactions
GROUP BY user_id;
Tu vois la différence ? Pas de CASE WHEN dans l'agrégat, pas de duplication de la colonne, pas de sous-requête qui rame. Juste FILTER.
C'est quoi en vrai ?
FILTER (WHERE condition) est une clause PostgreSQL (norme SQL standard) qui dit : « applique cette agrégation UNIQUEMENT aux lignes qui matchent la condition ».
Pourquoi c'est mieux que CASE WHEN ?
Compare les deux écritures pour le même résultat :
Cas 1 — FILTER (propre, rapide) :
SELECT
COUNT(*) FILTER (WHERE paid) AS paid_orders,
COUNT(*) FILTER (WHERE NOT paid) AS unpaid_orders
FROM orders;
Cas 2 — CASE WHEN (verbeux) :
SELECT
COUNT(CASE WHEN paid THEN 1 END) AS paid_orders,
COUNT(CASE WHEN NOT paid THEN 1 END) AS unpaid_orders
FROM orders;
Cas 3 — sous-requête (lourd) :
SELECT
(SELECT COUNT(*) FROM orders WHERE paid) AS paid_orders,
(SELECT COUNT(*) FROM orders WHERE NOT paid) AS unpaid_orders;
Cas 1 gagne. Plus lisible, plus rapide (un seul scan de la table), et zéro ambiguïté.
✅ Valeur : FILTER est standard SQL (SQL:2003), disponible dans PostgreSQL, SQLite 3.30+, et quelques autres. Sur MySQL par contre, faudra rester sur CASE WHEN.
💾 Enregistre ce post pour ne pas l'oublier.
#SQL #PostgreSQL #DevTips #WebDev #MetaCodeLearn
❤1
💡 LE SAVIEZ-VOUS — Creeper, le premier virus de l'histoire (1971)
En 1971, un ingénieur américain du nom de Bob Thomas crée un programme qui se propage sur ARPANET (l'ancêtre d'Internet). À l'époque, ARPANET relie une vingtaine d'universités et labos aux US.
Le programme s'appelle Creeper. Et quand il infecte une machine, il affiche ce message :
"Creeper", c'est la première chose qu'on a appelée un "virus informatique". Sauf qu'à l'époque, c'était plus une preuve de concept qu'une attaque. Bob Thomas voulait juste montrer qu'un programme pouvait sauter d'une machine à une autre via le réseau.
La réplique ne tarde pas. Un autre ingénieur, Ray Tomlinson (le mec qui a inventé le @ dans les emails, au passage), crée Reaper — un programme qui se propage aussi, mais pour détruire Creeper.
Reaper est considéré comme le premier antivirus de l'histoire.
✅ Leçon : en 1971 déjà, la dynamique "attaque → défense" était en place. Rien de nouveau sous le soleil, juste des noms plus jolis.
💾 Enregistre ce post pour ne pas l'oublier.
#DevHistory #CyberSecurity #Virus #Programming #MetaCodeLearn
En 1971, un ingénieur américain du nom de Bob Thomas crée un programme qui se propage sur ARPANET (l'ancêtre d'Internet). À l'époque, ARPANET relie une vingtaine d'universités et labos aux US.
Le programme s'appelle Creeper. Et quand il infecte une machine, il affiche ce message :
"I'm the creeper, catch me if you can!"
"Creeper", c'est la première chose qu'on a appelée un "virus informatique". Sauf qu'à l'époque, c'était plus une preuve de concept qu'une attaque. Bob Thomas voulait juste montrer qu'un programme pouvait sauter d'une machine à une autre via le réseau.
La réplique ne tarde pas. Un autre ingénieur, Ray Tomlinson (le mec qui a inventé le @ dans les emails, au passage), crée Reaper — un programme qui se propage aussi, mais pour détruire Creeper.
Reaper est considéré comme le premier antivirus de l'histoire.
✅ Leçon : en 1971 déjà, la dynamique "attaque → défense" était en place. Rien de nouveau sous le soleil, juste des noms plus jolis.
💾 Enregistre ce post pour ne pas l'oublier.
#DevHistory #CyberSecurity #Virus #Programming #MetaCodeLearn
❤4
⚡ ASTUCE JAVASCRIPT — Promise.all vs Promise.allSettled vs Promise.any
T'as 3 URLs à fetch en parallèle. Tu prends laquelle ?
1️⃣ Promise.all — "toutes ou rien"
Cas d'usage : tu as besoin des 3 pour avancer (sinon ta feature est cassée).
2️⃣ Promise.allSettled — "toutes, peu importe le résultat"
Cas d'usage : dashboard, logs, batch jobs. Tu veux savoir ce qui a marché et ce qui a planté.
3️⃣ Promise.any — "la première qui réussit"
Cas d'usage : retry multi-sources (mirror CDN, fallback API).
Le piège classique :
Écrire Promise.all sur 50 appels indépendants. Si 1 seul timeout, les 49 autres résultats sont JETÉS — alors que tu pourrais afficher 49 widgets et 1 message d'erreur. C'est du gâchis. allSettledSolved ce problème.
✅ Résumé simple :
- Besoin de tout ? → Promise.all
- Besoin de savoir ce qui marche ? → Promise.allSettled
- Besoin du premier qui répond ? → Promise.any
💾 Enregistre ce post pour ne pas l'oublier.
#JavaScript #Promise #WebDev #DevTips #MetaCodeLearn
T'as 3 URLs à fetch en parallèle. Tu prends laquelle ?
1️⃣ Promise.all — "toutes ou rien"
const results = await Promise.all([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
]);
// Si 1 échoue → TOUT échoue (reject immédiat)
// results = [users, posts, comments]
Cas d'usage : tu as besoin des 3 pour avancer (sinon ta feature est cassée).
2️⃣ Promise.allSettled — "toutes, peu importe le résultat"
const results = await Promise.allSettled([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
]);
// Aucune reject globale, même si tout plante
// results = [
// { status: 'fulfilled', value: ... },
// { status: 'rejected', reason: ... },
// { status: 'fulfilled', value: ... }
// ]
Cas d'usage : dashboard, logs, batch jobs. Tu veux savoir ce qui a marché et ce qui a planté.
3️⃣ Promise.any — "la première qui réussit"
const result = await Promise.any([
fetch('https://cdn1.example.com/data'),
fetch('https://cdn2.example.com/data'),
fetch('https://cdn3.example.com/data')
]);
// Prend le PREMIER fulfilled, ignore les autres
// Si TOUS échouent → AggregateError
Cas d'usage : retry multi-sources (mirror CDN, fallback API).
Le piège classique :
Écrire Promise.all sur 50 appels indépendants. Si 1 seul timeout, les 49 autres résultats sont JETÉS — alors que tu pourrais afficher 49 widgets et 1 message d'erreur. C'est du gâchis. allSettledSolved ce problème.
✅ Résumé simple :
- Besoin de tout ? → Promise.all
- Besoin de savoir ce qui marche ? → Promise.allSettled
- Besoin du premier qui répond ? → Promise.any
💾 Enregistre ce post pour ne pas l'oublier.
#JavaScript #Promise #WebDev #DevTips #MetaCodeLearn
❤1
💡 LE SAVIEZ-VOUS — Therac-25 (1985) : 6 morts à cause d'une race condition
Entre 1985 et 1987, une machine médicale appelée Therac-25 envoie des doses de radiation 100 fois supérieures à la normale à 6 patients. Tous meurent dans des conditions atroces.
C'est quoi Therac-25 ? Une machine de radiothérapie qui traite des cancers. Ses concurrents (Therac-6 et Therac-20) tournent sur du hardware avec des sécurités physiques. Mais Therac-25 est la première à tout déléguer au logiciel.
Que s'est-il passé ?
Le logiciel de la machine a deux modes : "électron" (faible dose) et "X-ray" (haute dose). L'opérateur tape les paramètres sur un clavier. Quand il tape trop vite, le système reste bloqué sur le mode "électron"... mais sans placer le filtre de protection qui va avec.
Résultat : le bras est en mode "électron" mais la machine tourne en mode "X-ray" sans filtre. La dose qui sort est massive. Le patient reçoit l'équivalent de plusieurs mois de radiothérapie en quelques secondes.
C'est quoi le bug exactement ?
C'est une race condition. Deux Threads (les paramètres de l'utilisateur ET l'état du hardware) accèdent à la même variable partagée sans verrou. Si l'utilisateur clique plus vite que le thread de vérification met à jour l'état, le système passe en "prêt à tirer" alors que le hardware n'est pas en sécurité.
Pire : les ingénieurs ont débugué après le premier accident, mais n'ont pas compris que le bug venait du modèle concurrent. Ils ont juste ajouté des messages d'alerte. Trois autres patients sont morts dans les 6 mois qui ont suivi.
✅ Leçon pour nous, devs :
1. Une race condition, ça ne se voit pas en test normal. Faut stress-test, fuzzing, et model-checking pour les attraper.
2. "On ajoutera un message d'alerte" n'est jamais une solution à un bug de sécurité.
3. Quand la vie des gens dépend de ton code, les standards ne sont pas optionnels.
Ce bug a contribué à créer les normes de sécurité logicielle pour les dispositifs médicaux (IEC 62304). Si t'as écrit un jour du code "pour de vrai que le fier" qui touche à la santee ou à l'argent des gens — cette histoire te concerne.
💾 Enregistre ce post pour ne pas l'oublier.
#DevHistory #SoftwareEngineering #RaceCondition #Programming #MetaCodeLearn
Entre 1985 et 1987, une machine médicale appelée Therac-25 envoie des doses de radiation 100 fois supérieures à la normale à 6 patients. Tous meurent dans des conditions atroces.
C'est quoi Therac-25 ? Une machine de radiothérapie qui traite des cancers. Ses concurrents (Therac-6 et Therac-20) tournent sur du hardware avec des sécurités physiques. Mais Therac-25 est la première à tout déléguer au logiciel.
Que s'est-il passé ?
Le logiciel de la machine a deux modes : "électron" (faible dose) et "X-ray" (haute dose). L'opérateur tape les paramètres sur un clavier. Quand il tape trop vite, le système reste bloqué sur le mode "électron"... mais sans placer le filtre de protection qui va avec.
Résultat : le bras est en mode "électron" mais la machine tourne en mode "X-ray" sans filtre. La dose qui sort est massive. Le patient reçoit l'équivalent de plusieurs mois de radiothérapie en quelques secondes.
C'est quoi le bug exactement ?
C'est une race condition. Deux Threads (les paramètres de l'utilisateur ET l'état du hardware) accèdent à la même variable partagée sans verrou. Si l'utilisateur clique plus vite que le thread de vérification met à jour l'état, le système passe en "prêt à tirer" alors que le hardware n'est pas en sécurité.
Pire : les ingénieurs ont débugué après le premier accident, mais n'ont pas compris que le bug venait du modèle concurrent. Ils ont juste ajouté des messages d'alerte. Trois autres patients sont morts dans les 6 mois qui ont suivi.
✅ Leçon pour nous, devs :
1. Une race condition, ça ne se voit pas en test normal. Faut stress-test, fuzzing, et model-checking pour les attraper.
2. "On ajoutera un message d'alerte" n'est jamais une solution à un bug de sécurité.
3. Quand la vie des gens dépend de ton code, les standards ne sont pas optionnels.
Ce bug a contribué à créer les normes de sécurité logicielle pour les dispositifs médicaux (IEC 62304). Si t'as écrit un jour du code "pour de vrai que le fier" qui touche à la santee ou à l'argent des gens — cette histoire te concerne.
💾 Enregistre ce post pour ne pas l'oublier.
#DevHistory #SoftwareEngineering #RaceCondition #Programming #MetaCodeLearn
⚡ ASTUCE PYTHON — match/case, le pattern matching (Python 3.10+)
Python 3.10 a ajouté match/case. C'est un
Exemple basique :
OK, classique. Mais regarde ça :
Tu vois ? match déstructure le dict, capture les valeurs, ET supporte un guard (
Encore plus fort — matcher sur des classes :
Le __match_args__ permet à match de déstructurer les objets par leurs attributs. C'est le pattern matching d'Haskell, OCaml, Rust, Scala... maintenant en Python.
✅ Quand l'utiliser :
- Quand t'as une longue série de
- Quand tu veux du code qui se lit comme une spec : "si c'est UN click, FAIS X. Si UN scroll, FAIS Y."
⚠️ Quand NE PAS l'utiliser :
- Pour des checks de valeurs simples → un dict ou un set reste plus clair.
- Si t'es encore en Python <3.10 → oublie.
💾 Enregistre ce post pour ne pas l'oublier.
#Python #Python310 #PatternMatching #DevTips #MetaCodeLearn
Python 3.10 a ajouté match/case. C'est un
switch sous stéroïdes — il peut matcher sur la structure d'une donnée, pas juste sa valeur.Exemple basique :
status = 200
match status:
case 200:
print("OK")
case 404:
print("Not found")
case 500:
print("Server error")
case _:
print("Unknown")
OK, classique. Mais regarde ça :
def handle(event):
match event:
case {"type": "click", "x": x, "y": y}:
print(f"Click at ({x}, {y})")
case {"type": "keypress", "key": key}:
print(f"Key pressed: {key}")
case {"type": "scroll", "direction": d} if d in ("up", "down"):
print(f"Scroll {d}")
case _:
print("Unknown event")
Tu vois ? match déstructure le dict, capture les valeurs, ET supporte un guard (
if d in (...)).Encore plus fort — matcher sur des classes :
class Point:
__match_args__ = ("x", "y")
class Circle:
__match_args__ = ("center", "radius")
def describe(obj):
match obj:
case Point(0, 0):
return "Point at origin"
case Circle(center=Point(0, 0), radius=r):
return f"Circle r={r} centered at origin"
case Circle(radius=r) if r > 10:
return "Big circle"
case _:
return "Unknown"
print(describe(Point(0, 0)))
print(describe(Circle(Point(1, 1), 5)))
Le __match_args__ permet à match de déstructurer les objets par leurs attributs. C'est le pattern matching d'Haskell, OCaml, Rust, Scala... maintenant en Python.
✅ Quand l'utiliser :
- Quand t'as une longue série de
if/elif qui checkent la structure (API, événements, AST).- Quand tu veux du code qui se lit comme une spec : "si c'est UN click, FAIS X. Si UN scroll, FAIS Y."
⚠️ Quand NE PAS l'utiliser :
- Pour des checks de valeurs simples → un dict ou un set reste plus clair.
- Si t'es encore en Python <3.10 → oublie.
💾 Enregistre ce post pour ne pas l'oublier.
#Python #Python310 #PatternMatching #DevTips #MetaCodeLearn
💡 LE SAVIEZ-VOUS — Le miroir du télescope Hubble : le bug à 2,5 milliards de dollars (1990)
En avril 1990, la NASA lance le télescope spatial Hubble. Coût total : 2,5 milliards de dollars. À peine 2 mois après sa mise en orbite, les premières images arrivent... et elles sont floues. Le miroir principal est défectueux.
Que s'est-il passé ?
Pendant la fabrication du miroir principal (2,4 m de diamètre), un petit instrument de mesure — appelé un reflectometer — a été mal calibré. L'écart : 1,3 millimètre.
1,3 mm. C'est rien. Sauf que sur un télescope optique spatial, le résidu de fabrication tolère 50 ns de précis. 1,3 mm, c'est 25-26 fois la tolérance.
Le résultat : Hubble ne pouvait pas faire la mise au point correctement. Les images étaient aussi floues qu'un appareil photo avec une lentille de travers.
Comment la NASA a corrigé ?
Ils ont envoyé les astronautes de la navette spatiale Endeavour avec une pièce de remplacement : COSTAR (Corrective Optics Space Telescope Axial Replacement). En installant un miroir correctif (modif) devant les instruments, ils ont compensé le défaut du miroir principal. Mission terminée en décembre 1993. Hubble a ensuite livré les images les plus célèbres de l'histoire de l'astronomie.
✅ Leçon pour nous, devs :
1. Un bug d'unité (cm vs mm, secondes vs ms, ASCII vs UTF-8) peut tout faire planter. Toujours vérifier que tout le monde parle la même unité.
2. Une erreur de 1,3 mm au bon endroit peut coûter 2,5 milliards. Idem en prod : un bug de 1 ligne au mauvais endroit peut faire tomber un site à 10 M€/jour.
3. La calibration des outils de mesure compte autant que les outils eux-mêmes. Les tests unitaires passent, donc le code est correct ? Pas forcément.
Les rapports d'enquête de la NASA sont publics et téléchargeables — c'est un cas d'école dans les universités d'ingénierie. Si t'es dev, lis-le au moins une fois dans ta vie.
💾 Enregistre ce post pour ne pas l'oublier.
#DevHistory #SpaceEngineering #Bug #SoftwareEngineering #MetaCodeLearn
En avril 1990, la NASA lance le télescope spatial Hubble. Coût total : 2,5 milliards de dollars. À peine 2 mois après sa mise en orbite, les premières images arrivent... et elles sont floues. Le miroir principal est défectueux.
Que s'est-il passé ?
Pendant la fabrication du miroir principal (2,4 m de diamètre), un petit instrument de mesure — appelé un reflectometer — a été mal calibré. L'écart : 1,3 millimètre.
1,3 mm. C'est rien. Sauf que sur un télescope optique spatial, le résidu de fabrication tolère 50 ns de précis. 1,3 mm, c'est 25-26 fois la tolérance.
Le résultat : Hubble ne pouvait pas faire la mise au point correctement. Les images étaient aussi floues qu'un appareil photo avec une lentille de travers.
Comment la NASA a corrigé ?
Ils ont envoyé les astronautes de la navette spatiale Endeavour avec une pièce de remplacement : COSTAR (Corrective Optics Space Telescope Axial Replacement). En installant un miroir correctif (modif) devant les instruments, ils ont compensé le défaut du miroir principal. Mission terminée en décembre 1993. Hubble a ensuite livré les images les plus célèbres de l'histoire de l'astronomie.
✅ Leçon pour nous, devs :
1. Un bug d'unité (cm vs mm, secondes vs ms, ASCII vs UTF-8) peut tout faire planter. Toujours vérifier que tout le monde parle la même unité.
2. Une erreur de 1,3 mm au bon endroit peut coûter 2,5 milliards. Idem en prod : un bug de 1 ligne au mauvais endroit peut faire tomber un site à 10 M€/jour.
3. La calibration des outils de mesure compte autant que les outils eux-mêmes. Les tests unitaires passent, donc le code est correct ? Pas forcément.
Les rapports d'enquête de la NASA sont publics et téléchargeables — c'est un cas d'école dans les universités d'ingénierie. Si t'es dev, lis-le au moins une fois dans ta vie.
💾 Enregistre ce post pour ne pas l'oublier.
#DevHistory #SpaceEngineering #Bug #SoftwareEngineering #MetaCodeLearn
😍1
⚡ ASTUCE GIT — git merge vs git rebase (avec un dessin)
Tu travailles sur une branche
1️⃣ git merge — combine, garde l'historique brut
Tu vois un commit de merge (M). L'historique est COMPLET, mais aussi plus bruité. Si tout le monde merge main dans sa feature toutes les 2 heures, l'historique ressemble à une pelote de laine.
2️⃣ git rebase — rejoue tes commits par-dessus main
Pas de commit de merge. Tes commits D', E', F' sont de NOUVEAUX commits (avec des nouveaux hashes). L'historique est LINÉAIRE, propre, lisible. Mais : tu as "réécrit l'histoire".
⚠️ La règle d'or du rebase :
Ne JAMAIS rebase une branche partagée.
Si quelqu'un d'autre a déjà pull ta branche, et que tu rebases : tes commits changent de hash. Les collègues vont avoir des conflits dans tous les sens, et tu vas devenir leur pire ennemi de la semaine.
✅ Quand utiliser quoi ?
- merge sur main (ou n'importe quelle branche partagée) — toujours.
- rebase sur ta branche locale, AVANT de merger dans main, pour nettoyer ton historique.
- rebase sur une branche feature que TOI seul utilise.
La combo que les pros utilisent :
--force-with-lease vérifie que personne n'a push entre temps sur ta branche. Si oui, le push est refusé. C'est la version safe de --force.
💾 Enregistre ce post pour ne pas l'oublir.
#Git #DevTips #Programming #WebDev #MetaCodeLearn
Tu travailles sur une branche
feature/x. Tu veux récupérer les commits de main. Deux options :1️⃣ git merge — combine, garde l'historique brut
git checkout feature/x
git merge main
# Résultat :
# main: A---B---C
# \
# feature/x: D---E---F---M (M = merge commit)
Tu vois un commit de merge (M). L'historique est COMPLET, mais aussi plus bruité. Si tout le monde merge main dans sa feature toutes les 2 heures, l'historique ressemble à une pelote de laine.
2️⃣ git rebase — rejoue tes commits par-dessus main
git checkout feature/x
git rebase main
# Résultat :
# main: A---B---C
# \
# feature/x: D'---E'---F'
Pas de commit de merge. Tes commits D', E', F' sont de NOUVEAUX commits (avec des nouveaux hashes). L'historique est LINÉAIRE, propre, lisible. Mais : tu as "réécrit l'histoire".
⚠️ La règle d'or du rebase :
Ne JAMAIS rebase une branche partagée.
Si quelqu'un d'autre a déjà pull ta branche, et que tu rebases : tes commits changent de hash. Les collègues vont avoir des conflits dans tous les sens, et tu vas devenir leur pire ennemi de la semaine.
✅ Quand utiliser quoi ?
- merge sur main (ou n'importe quelle branche partagée) — toujours.
- rebase sur ta branche locale, AVANT de merger dans main, pour nettoyer ton historique.
- rebase sur une branche feature que TOI seul utilise.
La combo que les pros utilisent :
# Sur ta branche feature locale
git fetch origin
git rebase origin/main
# Puis tu push --force-with-lease (pas --force !)
git push --force-with-lease
# Enfin, merge dans main
git checkout main
git merge feature/x # fast-forward, pas de commit de merge
--force-with-lease vérifie que personne n'a push entre temps sur ta branche. Si oui, le push est refusé. C'est la version safe de --force.
💾 Enregistre ce post pour ne pas l'oublir.
#Git #DevTips #Programming #WebDev #MetaCodeLearn
❤1
⚡ ASTUCE WEB — CORS, enfin compris en 3 minutes
Tu ouvres la console : "Access to fetch at 'https://api.example.com' from origin 'https://myapp.com' has been blocked by CORS policy". Tu fixes ça comment ? Tu copies-colles un snippet StackOverflow. Mais qu'est-ce que ça veut dire, vraiment ?
Le problème :
Ton navigateur charge
Parce que si je vais sur
CORS = Cross-Origin Resource Sharing. C'est LE mécanisme qui dit : "OK, le navigateur, toi
Comment ça marche :
Quand ton frontend fait un fetch, le navigateur envoie une preflight request (OPTIONS) :
Le serveur répond :
Si Access-Control-Allow-Origin matche l'origine du frontend, le navigateur laisse passer la vraie requête. Sinon, bloqué.
Les 3 erreurs classiques et leurs fixes :
1️⃣ "No 'Access-Control-Allow-Origin' header is present"
Le serveur ne renvoie pas le header. Côté backend, ajoute :
2️⃣ "The value of the 'Access-Control-Allow-Origin' header is '*, which is not valid when credentials are included"
Tu as mis
3️⃣ "CORS policy: Method not allowed"
Tu envoies un POST mais le serveur n'autorise que GET. Ajoute la méthode dans
⚠️ La règle d'or :
NE JAMAIS désactiver CORS côté navigateur (il y a des extensions pour, mais en prod, jamais). CORS est une protection serveur. Le navigateur ne peut pas le bypass.
Le bon réflexe : configure CORS côté BACKEND. Si tu contrôles pas le backend, passe par un proxy (ex: ton serveur Next.js qui fait
💾 Enregistre ce post pour ne pas l'oublir.
#WebDev #CORS #JavaScript #DevTips #MetaCodeLearn
Tu ouvres la console : "Access to fetch at 'https://api.example.com' from origin 'https://myapp.com' has been blocked by CORS policy". Tu fixes ça comment ? Tu copies-colles un snippet StackOverflow. Mais qu'est-ce que ça veut dire, vraiment ?
Le problème :
Ton navigateur charge
https://myapp.com. Ton JS essaie de faire un fetch('https://api.example.com/users'). Pour des raisons de sécurité, le navigateur BLOQUE la requête par défaut. Pourquoi ?Parce que si je vais sur
https://mauvais-site.com et que mon JS peut faire un fetch('https://banque.com/compte/virements') avec mes cookies de session attachés automatiquement, c'est la catastrophe. C'est ce qu'on appelle une attaque CSRF.CORS = Cross-Origin Resource Sharing. C'est LE mécanisme qui dit : "OK, le navigateur, toi
https://mon-app.com, je t'autorise à me lire."Comment ça marche :
Quand ton frontend fait un fetch, le navigateur envoie une preflight request (OPTIONS) :
OPTIONS /users HTTP/1.1
Origin: https://mon-app.com
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Authorization
Le serveur répond :
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://mon-app.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Authorization
Access-Control-Max-Age: 86400
Si Access-Control-Allow-Origin matche l'origine du frontend, le navigateur laisse passer la vraie requête. Sinon, bloqué.
Les 3 erreurs classiques et leurs fixes :
1️⃣ "No 'Access-Control-Allow-Origin' header is present"
Le serveur ne renvoie pas le header. Côté backend, ajoute :
# Express.js
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://mon-app.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
2️⃣ "The value of the 'Access-Control-Allow-Origin' header is '*, which is not valid when credentials are included"
Tu as mis
Access-Control-Allow-Origin: * mais tu envoies des cookies / une Authorization. Le wildcard ne marche pas avec credentials. Tu DOIS spécifier l'origine exacte.3️⃣ "CORS policy: Method not allowed"
Tu envoies un POST mais le serveur n'autorise que GET. Ajoute la méthode dans
Access-Control-Allow-Methods.⚠️ La règle d'or :
NE JAMAIS désactiver CORS côté navigateur (il y a des extensions pour, mais en prod, jamais). CORS est une protection serveur. Le navigateur ne peut pas le bypass.
Le bon réflexe : configure CORS côté BACKEND. Si tu contrôles pas le backend, passe par un proxy (ex: ton serveur Next.js qui fait
fetch côté Node, où CORS n'existe pas).💾 Enregistre ce post pour ne pas l'oublir.
#WebDev #CORS #JavaScript #DevTips #MetaCodeLearn
❤1
🚀 LE SAVIEZ-VOUS — Mars Climate Orbiter (1999), $327M perdus à cause d'une unité
Décembre 1998. La NASA lance Mars Climate Orbiter, une sonde qui doit se mettre en orbite autour de Mars pour étudier le climat. Budget : 327 millions de dollars. 9 mois de voyage. 23 septembre 1999, jour J.
La sonde s'approche de Mars. Les ingénieurs corrigent sa trajectoire. Les calculs disent : "tu es trop bas". Ils corrigent. Trop bas encore. Ils corrigent. Trop bas.
La sonde entre dans l'atmosphère de Mars à 57 km d'altitude au lieu des 80 km prévus. Elle est désintégrée par les frottements atmosphériques. Mission terminée. Argent parti.
Que s'est-il passé ?
Deux équipes travaillaient sur la sonde :
- L'équipe du JPL (Jet Propulsion Laboratory) à Pasadena, qui pilotait la trajectoire, utilisait des newtons (unités SI, métriques).
- L'équipe Lockheed Martin Astronautics à Denver, qui avait écrit le logiciel de calcul de poussée, utilisait des pounds-force (système impérial, américain).
Le logiciel de Lockheed Martin renvoyait les valeurs de poussée en pounds-force. Le système du JPL les interprétait comme des newtons. Ratio d'erreur : 4,45.
Chaque petite correction de trajectoire, le système croyait appliquer 4,45 fois plus de poussée que la réalité. Pendant 9 mois, la sonde dérivait vers Mars. Aucun des deux systèmes n'a levé l'erreur.
Le code source Lockheed Martin utilisait une variable
Les leçons à retenir pour toi, dev en 2026 :
1️⃣ Les unités sont des types. Si ton langage te permet de typer (Rust, F#, TypeScript strict), utilise des types dédiés :
2️⃣ Les frontières d'équipe sont des pièges. Quand deux équipes ou deux services s'échangent des données, documente l'unité explicitement. Pas dans un coin de la doc. Dans le nom de la variable, dans le schema JSON, dans le commentaire d'API.
3️⃣ Teste les valeurs aberrantes. Si ton système de contrôle attend des valeurs de poussée entre 0 et 100 newtons, et qu'un jour il reçoit 0.5 ou 500, il faut crier fort. Le JPL avait un système de détection d'anomalies, mais il a été ignoré parce que les valeurs étaient "plausibles" individuellement.
Un seul caractère — lbf vs N — a coûté 327 millions de dollars et 10 ans de travail.
La prochaine fois que tu codes une API, que tu passes un nombre d'un service à un autre, ou que tu utilises une variable
💾 Enregistre ce post pour ne pas l'oublir.
#DevStory #MarsClimateOrbiter #NASA #Units #DevTips #MetaCodeLearn
Décembre 1998. La NASA lance Mars Climate Orbiter, une sonde qui doit se mettre en orbite autour de Mars pour étudier le climat. Budget : 327 millions de dollars. 9 mois de voyage. 23 septembre 1999, jour J.
La sonde s'approche de Mars. Les ingénieurs corrigent sa trajectoire. Les calculs disent : "tu es trop bas". Ils corrigent. Trop bas encore. Ils corrigent. Trop bas.
La sonde entre dans l'atmosphère de Mars à 57 km d'altitude au lieu des 80 km prévus. Elle est désintégrée par les frottements atmosphériques. Mission terminée. Argent parti.
Que s'est-il passé ?
Deux équipes travaillaient sur la sonde :
- L'équipe du JPL (Jet Propulsion Laboratory) à Pasadena, qui pilotait la trajectoire, utilisait des newtons (unités SI, métriques).
- L'équipe Lockheed Martin Astronautics à Denver, qui avait écrit le logiciel de calcul de poussée, utilisait des pounds-force (système impérial, américain).
Le logiciel de Lockheed Martin renvoyait les valeurs de poussée en pounds-force. Le système du JPL les interprétait comme des newtons. Ratio d'erreur : 4,45.
Chaque petite correction de trajectoire, le système croyait appliquer 4,45 fois plus de poussée que la réalité. Pendant 9 mois, la sonde dérivait vers Mars. Aucun des deux systèmes n'a levé l'erreur.
Le code source Lockheed Martin utilisait une variable
force_lbf. Le code JPL faisait acceleration = force / mass, en supposant que force était en newtons. Aucun type-check, aucune validation d'unité, aucun test de cohérence.Les leçons à retenir pour toi, dev en 2026 :
1️⃣ Les unités sont des types. Si ton langage te permet de typer (Rust, F#, TypeScript strict), utilise des types dédiés :
Newtons, PoundsForce, Meters, Seconds. Une multiplication entre un Newtons et un Meters ne devrait pas compiler.
// TypeScript avec branded types
type Newton = number & { readonly __brand: 'Newton' };
type PoundForce = number & { readonly __brand: 'PoundForce' };
const thrust: Newton = 10 as Newton;
const weight: PoundForce = 22 as PoundForce;
// Le compilateur t'empêche de mélanger.
2️⃣ Les frontières d'équipe sont des pièges. Quand deux équipes ou deux services s'échangent des données, documente l'unité explicitement. Pas dans un coin de la doc. Dans le nom de la variable, dans le schema JSON, dans le commentaire d'API.
{
"thrust_lbf": 22, // OK
"thrust": 22 // Ambigu, dangereux
}
3️⃣ Teste les valeurs aberrantes. Si ton système de contrôle attend des valeurs de poussée entre 0 et 100 newtons, et qu'un jour il reçoit 0.5 ou 500, il faut crier fort. Le JPL avait un système de détection d'anomalies, mais il a été ignoré parce que les valeurs étaient "plausibles" individuellement.
Un seul caractère — lbf vs N — a coûté 327 millions de dollars et 10 ans de travail.
La prochaine fois que tu codes une API, que tu passes un nombre d'un service à un autre, ou que tu utilises une variable
value ou amount sans contexte, souviens-toi de Mars.💾 Enregistre ce post pour ne pas l'oublir.
#DevStory #MarsClimateOrbiter #NASA #Units #DevTips #MetaCodeLearn
⚡ ASTUCE WEB — JWT décodé en 5 minutes (ce que c'est vraiment, et ce que c'est PAS)
Tu vois
JWT = JSON Web Token. C'est un standard (RFC 7519) pour transmettre une information entre deux parties. En général, c'est utilisé pour l'authentification.
Structure — 3 parties séparées par des points :
Chaque partie est en Base64. Tu peux DÉCODER le header et le payload (mais PAS la signature, sinon ça sert à rien) sur jwt.io. Allez, décode celui que t'as dans ton localStorage maintenant. Oui, ce que tu viens de faire est un peu flippant.
1️⃣ HEADER — algorithme + type
2️⃣ PAYLOAD — les claims (l'info)
⚠️ Tout ce qui est dans le payload est LISIBLE par tout le monde. C'est juste encodé, pas chiffré. Ne mets JAMAIS de mot de passe, d'email, ou de donnée sensible dedans.
3️⃣ SIGNATURE — la preuve d'intégrité
Pour HS256, c'est :
Le serveur signe avec un secret qu'il garde. Le client reçoit le token. Plus tard, le client renvoie le token, le serveur re-calcule la signature et compare. Si ça matche → le payload n'a pas été modifié.
Maintenant, les 4 pièges classiques :
❌ Piège 1 : mettre le JWT dans localStorage
Un JWT dans localStorage est accessible à n'importe quel script JS qui passe sur ta page. Si un XSS (Cross-Site Scripting) t'arrive, l'attaquant lit le token, l'envoie à son serveur, et il est connecté à ton compte. Préféré : cookie
❌ Piège 2 : algorithme "none"
Par défaut, certaines bibliothèques acceptent l'algorithme "none" — c'est-à-dire pas de signature. Un attaquant peut forger un token admin avec
❌ Piège 3 : JWT qui n'expire jamais
Si tu mets
❌ Piège 4 : ne pas révoquer un JWT
Un JWT est stateless par design. Le serveur ne tient pas de liste des tokens valides. Si un utilisateur change de mot de passe ou est banni, son ancien JWT reste valide jusqu'à expiration. Solutions :
- Stocker un
- Refresh tokens courts + DB check à chaque refresh.
- Au minimum, vérifier en DB à chaque requête critique (ce qui rend le JWT "stateful", mais c'est OK pour un site de e-commerce).
✅ Le bon flow :
⚠️ Dernier rappel : JWT n'est PAS un serveur de sessions. C'est un format de token. Tu peux l'utiliser pour des sessions, mais tu peux aussi l'utiliser pour des API entre services, des magic links email, des confirmations de paiement, etc. Chaque cas d'usage a ses propres règles.
💾 Enregistre ce post pour ne pas l'oublir.
#WebDev #JWT #Authentication #Security #DevTips #MetaCodeLearn
Tu vois
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWxpb3UiLCJyb2xlIjoiZGV2In0.kQ3... dans ton LocalStorage et tu fais "ouais c'est un token". Mais qu'est-ce qu'il y a DEDANS ? Et surtout : qu'est-ce que tu risques à mal l'utiliser ?JWT = JSON Web Token. C'est un standard (RFC 7519) pour transmettre une information entre deux parties. En général, c'est utilisé pour l'authentification.
Structure — 3 parties séparées par des points :
HEADER.PAYLOAD.SIGNATURE
Chaque partie est en Base64. Tu peux DÉCODER le header et le payload (mais PAS la signature, sinon ça sert à rien) sur jwt.io. Allez, décode celui que t'as dans ton localStorage maintenant. Oui, ce que tu viens de faire est un peu flippant.
1️⃣ HEADER — algorithme + type
{
"alg": "HS256",
"typ": "JWT"
}
2️⃣ PAYLOAD — les claims (l'info)
{
"sub": "aliou",
"role": "dev",
"iat": 1728000000, // issued at
"exp": 1728086400 // expiration (24h)
}
⚠️ Tout ce qui est dans le payload est LISIBLE par tout le monde. C'est juste encodé, pas chiffré. Ne mets JAMAIS de mot de passe, d'email, ou de donnée sensible dedans.
3️⃣ SIGNATURE — la preuve d'intégrité
Pour HS256, c'est :
HMAC_SHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret_server_only
)
Le serveur signe avec un secret qu'il garde. Le client reçoit le token. Plus tard, le client renvoie le token, le serveur re-calcule la signature et compare. Si ça matche → le payload n'a pas été modifié.
Maintenant, les 4 pièges classiques :
❌ Piège 1 : mettre le JWT dans localStorage
Un JWT dans localStorage est accessible à n'importe quel script JS qui passe sur ta page. Si un XSS (Cross-Site Scripting) t'arrive, l'attaquant lit le token, l'envoie à son serveur, et il est connecté à ton compte. Préféré : cookie
httpOnly + secure + SameSite=Strict. Le JS ne peut pas le lire, mais le navigateur l'envoie quand même.❌ Piège 2 : algorithme "none"
Par défaut, certaines bibliothèques acceptent l'algorithme "none" — c'est-à-dire pas de signature. Un attaquant peut forger un token admin avec
alg: "none", et le serveur l'accepte. Toujours verrouiller l'algorithme côté serveur.
// VULNÉRABLE
jwt.verify(token, secret);
// SAFE — algorithm explicite
jwt.verify(token, secret, { algorithms: ['HS256'] });
❌ Piège 3 : JWT qui n'expire jamais
Si tu mets
exp très loin dans le futur (ou absent), un token volé est valide pour des mois. Bonne pratique : 15 min à 1h pour un access token. Pour les sessions longues, utilise un refresh token séparé, stocké en cookie httpOnly et rotaté.❌ Piège 4 : ne pas révoquer un JWT
Un JWT est stateless par design. Le serveur ne tient pas de liste des tokens valides. Si un utilisateur change de mot de passe ou est banni, son ancien JWT reste valide jusqu'à expiration. Solutions :
- Stocker un
jti (JWT ID) unique par token, blacklisté en cas de révocation.- Refresh tokens courts + DB check à chaque refresh.
- Au minimum, vérifier en DB à chaque requête critique (ce qui rend le JWT "stateful", mais c'est OK pour un site de e-commerce).
✅ Le bon flow :
// 1. Login
POST /login { email, password }
→ 200 { accessToken: "eyJ..." } // 15 min
→ Set-Cookie: refreshToken=...; HttpOnly; Secure
// 2. Requête authentifiée
GET /api/me
Authorization: Bearer eyJ...
// 3. Quand l'access token expire
POST /refresh (cookie auto-envoyé)
→ 200 { accessToken: "eyJ...nouveau" }
⚠️ Dernier rappel : JWT n'est PAS un serveur de sessions. C'est un format de token. Tu peux l'utiliser pour des sessions, mais tu peux aussi l'utiliser pour des API entre services, des magic links email, des confirmations de paiement, etc. Chaque cas d'usage a ses propres règles.
💾 Enregistre ce post pour ne pas l'oublir.
#WebDev #JWT #Authentication #Security #DevTips #MetaCodeLearn
🚀 LE SAVIEZ-VOUS — Knight Capital (2012), $440M partis en fumée en 45 minutes
1er août 2012. Knight Capital Group, l'un des plus gros traders algorithmiques de Wall Street, déploie une nouvelle version de son logiciel de trading haute fréquence. C'est un mardi matin, 9h30 heure de New York. Le marché ouvre.
En 45 minutes, le logiciel va passer 4 millions d'ordres erronés sur le NYSE. Il va acheter massivement des actions au-dessus du prix du marché, et ne jamais les vendre. 440 millions de dollars de pertes. Une perte supérieure au bénéfice annuel de l'entreprise.
Knight Capital meurt presque ce jour-là. Elle sera rachetée en urgence quelques mois plus tard par un concurrent (Virtu Financial + Citadel) à un prix dérisoire. Société fondée en 1995, liquidée en 2012. 17 ans d'histoire, 1 600 employés, rayés de la carte en 45 minutes.
Que s'est-il passé ?
Knight Capital faisait tourner plusieurs versions de son moteur de trading en parallèle, sur des serveurs différents. Chaque version était identifiée par un "Power Peg" flag — un identifiant dans le code. La nouvelle version, déployée sur 7 des 8 serveurs, était numérotée SMARS-2012-01. Le 8e serveur, oublié, tournait encore sur une vieille version avec un code appelé Power Peg.
Le problème : le code Power Peg était un ancien test de stress jamais supprimé du code de production. Quand le marché a ouvert et que la nouvelle version a commencé à envoyer des ordres en masse, un sous-système de l'ancienne version, sur ce 8e serveur, a réagi aux ordres en cascade. Le test de stress est devenu un trader réel.
Le code de Power Peg disait essentiellement : "achète à l'offre, vend à la demande, et reverse immédiatement la position". Sauf qu'il ne savait pas qu'il était branché sur le vrai marché. Il a pris l'API pour un simulateur. Pendant 45 minutes, il a exécuté son algorithme de test sur le NYSE avec de l'argent réel.
Les leçons — 4, pas une :
1️⃣ Supprime le code mort en production
Power Peg était un code de test de stress, écrit en 2003. Il était commenté comme tel, mais il a été activé par accident. Le code mort est un risque dormant. À chaque release, vire ce qui ne sert plus.
2️⃣ Le déploiement doit être progressif et réversible
Knight a déployé la nouvelle version sur 7 serveurs en une seule fois. Pas de canary release, pas de feature flag, pas de kill switch rapide. Quand ça a commencé à mal tourner, ils n'avaient aucun moyen d'arrêter le 8e serveur sans relancer tout le cluster.
3️⃣ Les "tests" doivent tester le bon chemin
Power Peg avait été testé pendant des années. Mais il était testé en mode "simulateur" — avec un faux marché. Il n'avait jamais été testé en mode "production réelle". Le test passait parce qu'il utilisait des mocks qui ne correspondaient plus à la réalité du code de production.
Règle simple : un test qui passe avec un mock ne teste que ton mock. Teste contre l'API réelle, avec un environnement réel, avant chaque release.
4️⃣ Les alarmes doivent être humaines
Pendant 45 minutes, le système a généré des alertes sur le dashboard. Mais elles étaient noyées dans le bruit habituel du trading haute fréquence. Personne n'a réalisé pendant 30 minutes que c'était un bug, et non pas un comportement de marché extrême. Une alarme technique sans escalation humaine est inutile.
⚠️ La règle d'or du déploiement :
Un déploiement devrait toujours te donner le temps de l'arrêter.
Si tu ne peux pas annuler en moins de 5 minutes, c'est trop risqué. Un canary release, un kill switch, un rollback automatique, un monitoring avec une vraie escalade humaine — c'est la base. Pas du luxe.
Aujourd'hui, 12 ans après Knight Capital, la plupart des boîtes font toujours des déploiements qui ressemblent à celui-là : "on push sur tous les serveurs d'un coup, on verra si ça marche". Ne sois pas Knight Capital.
💾 Enregistre ce post pour ne pas l'oublir.
#DevStory #KnightCapital #Deployment #FeatureFlags #DevTips #MetaCodeLearn
1er août 2012. Knight Capital Group, l'un des plus gros traders algorithmiques de Wall Street, déploie une nouvelle version de son logiciel de trading haute fréquence. C'est un mardi matin, 9h30 heure de New York. Le marché ouvre.
En 45 minutes, le logiciel va passer 4 millions d'ordres erronés sur le NYSE. Il va acheter massivement des actions au-dessus du prix du marché, et ne jamais les vendre. 440 millions de dollars de pertes. Une perte supérieure au bénéfice annuel de l'entreprise.
Knight Capital meurt presque ce jour-là. Elle sera rachetée en urgence quelques mois plus tard par un concurrent (Virtu Financial + Citadel) à un prix dérisoire. Société fondée en 1995, liquidée en 2012. 17 ans d'histoire, 1 600 employés, rayés de la carte en 45 minutes.
Que s'est-il passé ?
Knight Capital faisait tourner plusieurs versions de son moteur de trading en parallèle, sur des serveurs différents. Chaque version était identifiée par un "Power Peg" flag — un identifiant dans le code. La nouvelle version, déployée sur 7 des 8 serveurs, était numérotée SMARS-2012-01. Le 8e serveur, oublié, tournait encore sur une vieille version avec un code appelé Power Peg.
Le problème : le code Power Peg était un ancien test de stress jamais supprimé du code de production. Quand le marché a ouvert et que la nouvelle version a commencé à envoyer des ordres en masse, un sous-système de l'ancienne version, sur ce 8e serveur, a réagi aux ordres en cascade. Le test de stress est devenu un trader réel.
Le code de Power Peg disait essentiellement : "achète à l'offre, vend à la demande, et reverse immédiatement la position". Sauf qu'il ne savait pas qu'il était branché sur le vrai marché. Il a pris l'API pour un simulateur. Pendant 45 minutes, il a exécuté son algorithme de test sur le NYSE avec de l'argent réel.
Les leçons — 4, pas une :
1️⃣ Supprime le code mort en production
Power Peg était un code de test de stress, écrit en 2003. Il était commenté comme tel, mais il a été activé par accident. Le code mort est un risque dormant. À chaque release, vire ce qui ne sert plus.
2️⃣ Le déploiement doit être progressif et réversible
Knight a déployé la nouvelle version sur 7 serveurs en une seule fois. Pas de canary release, pas de feature flag, pas de kill switch rapide. Quand ça a commencé à mal tourner, ils n'avaient aucun moyen d'arrêter le 8e serveur sans relancer tout le cluster.
3️⃣ Les "tests" doivent tester le bon chemin
Power Peg avait été testé pendant des années. Mais il était testé en mode "simulateur" — avec un faux marché. Il n'avait jamais été testé en mode "production réelle". Le test passait parce qu'il utilisait des mocks qui ne correspondaient plus à la réalité du code de production.
Règle simple : un test qui passe avec un mock ne teste que ton mock. Teste contre l'API réelle, avec un environnement réel, avant chaque release.
4️⃣ Les alarmes doivent être humaines
Pendant 45 minutes, le système a généré des alertes sur le dashboard. Mais elles étaient noyées dans le bruit habituel du trading haute fréquence. Personne n'a réalisé pendant 30 minutes que c'était un bug, et non pas un comportement de marché extrême. Une alarme technique sans escalation humaine est inutile.
⚠️ La règle d'or du déploiement :
Un déploiement devrait toujours te donner le temps de l'arrêter.
Si tu ne peux pas annuler en moins de 5 minutes, c'est trop risqué. Un canary release, un kill switch, un rollback automatique, un monitoring avec une vraie escalade humaine — c'est la base. Pas du luxe.
Aujourd'hui, 12 ans après Knight Capital, la plupart des boîtes font toujours des déploiements qui ressemblent à celui-là : "on push sur tous les serveurs d'un coup, on verra si ça marche". Ne sois pas Knight Capital.
💾 Enregistre ce post pour ne pas l'oublir.
#DevStory #KnightCapital #Deployment #FeatureFlags #DevTips #MetaCodeLearn
⚡ ASTUCE RÉSEAU — DNS, enfin compris en 3 minutes
Tu tapes
DNS = Domain Name System. C'est l'annuaire d'Internet. Il traduit un nom lisible par un humain (
Sans DNS, il faudrait mémoriser des milliards d'adresses IP. Avec DNS, tu mémorises des noms. Le DNS fait le reste.
Le parcours complet d'une requête DNS — étape par étape :
1️⃣ Ton navigateur : il a peut-être l'IP en cache (de ta dernière visite). Si oui, 0 ms.
2️⃣ Cache OS : sinon, l'OS a peut-être l'IP (via
3️⃣ Résolveur récursif : le serveur DNS reçoit la requête. Il regarde son cache. Sinon, il descend la chaîne.
4️⃣ Serveur racine (.) : "Je connais pas github.com, mais je connais qui s'occupe du
5️⃣ Serveur TLD (.com) : "Je connais pas github.com, mais je connais son serveur autoritatif."
6️⃣ Serveur autoritatif : "L'IP de github.com, c'est
7️⃣ Le navigateur : reçoit l'IP, ouvre une connexion TCP, fait un GET / sur HTTPS, charge la page.
Tout ça, c'est entre 20 et 200 ms.
Maintenant les 5 concepts à garder en tête :
1️⃣ TTL (Time To Live)
Quand un serveur autoritatif renvoie l'IP, il indique combien de temps le résolveur doit la stocker (300s, 1h, 24h). Si tu changes l'IP de ton site et que ton TTL est à 86400 (24h), les utilisateurs continueront à voir l'ancienne IP pendant 24h. Avant une migration, baisse le TTL à 300 secondes.
2️⃣ Types d'enregistrements
3️⃣ CNAME vs A record
Tu veux pointer
Le résolveur suit la chaîne : blog.example.com → aliou.github.io → A record → IP.
Un CNAME ne peut pas coexister avec d'autres records au même niveau. Si tu mets un CNAME sur
4️⃣ DNS over HTTPS (DoH)
Le DNS classique est en clair. Ton FAI voit toutes tes requêtes.
5️⃣ Split-horizon DNS
Ta boîte a
Commande utile :
Tu vois le TTL, le record type, l'IP, le temps de réponse, le serveur utilisé. Si ton site ne marche pas après un changement DNS,
💾 Enregistre ce post pour ne pas l'oublir.
#DevTips #DNS #Networking #WebDev #MetaCodeLearn
Tu tapes
github.com dans ton navigateur. Il t'affiche une page. Mais entre les deux, il se passe un truc que 90% des devs ne comprennent pas vraiment.DNS = Domain Name System. C'est l'annuaire d'Internet. Il traduit un nom lisible par un humain (
github.com) en une adresse IP compréhensible par une machine (140.82.121.4).Sans DNS, il faudrait mémoriser des milliards d'adresses IP. Avec DNS, tu mémorises des noms. Le DNS fait le reste.
Le parcours complet d'une requête DNS — étape par étape :
1️⃣ Ton navigateur : il a peut-être l'IP en cache (de ta dernière visite). Si oui, 0 ms.
2️⃣ Cache OS : sinon, l'OS a peut-être l'IP (via
/etc/resolv.conf, qui pointe vers ton serveur DNS — FAI, ou 8.8.8.8, ou 1.1.1.1).3️⃣ Résolveur récursif : le serveur DNS reçoit la requête. Il regarde son cache. Sinon, il descend la chaîne.
4️⃣ Serveur racine (.) : "Je connais pas github.com, mais je connais qui s'occupe du
.com."5️⃣ Serveur TLD (.com) : "Je connais pas github.com, mais je connais son serveur autoritatif."
6️⃣ Serveur autoritatif : "L'IP de github.com, c'est
140.82.121.4."7️⃣ Le navigateur : reçoit l'IP, ouvre une connexion TCP, fait un GET / sur HTTPS, charge la page.
Tout ça, c'est entre 20 et 200 ms.
Maintenant les 5 concepts à garder en tête :
1️⃣ TTL (Time To Live)
Quand un serveur autoritatif renvoie l'IP, il indique combien de temps le résolveur doit la stocker (300s, 1h, 24h). Si tu changes l'IP de ton site et que ton TTL est à 86400 (24h), les utilisateurs continueront à voir l'ancienne IP pendant 24h. Avant une migration, baisse le TTL à 300 secondes.
github.com. 300 IN A 140.82.121.4
↑
TTL en secondes
2️⃣ Types d'enregistrements
A github.com → 140.82.121.4 (IPv4)
AAAA github.com → 2606:4700::6812:... (IPv6)
CNAME www.github.com → github.com (alias)
MX github.com → mail.github.com (mail)
TXT github.com → "v=spf1 include:..." (vérif SPF)
NS github.com → ns-1283.awsdns-32.org (autoritatif)
3️⃣ CNAME vs A record
Tu veux pointer
blog.example.com vers un site sur GitHub Pages :
blog.example.com. CNAME aliou.github.io.
Le résolveur suit la chaîne : blog.example.com → aliou.github.io → A record → IP.
Un CNAME ne peut pas coexister avec d'autres records au même niveau. Si tu mets un CNAME sur
example.com, tu ne peux pas mettre de MX ou NS dessus. Limitation du protocole.4️⃣ DNS over HTTPS (DoH)
Le DNS classique est en clair. Ton FAI voit toutes tes requêtes.
1.1.1.1 avec DoH (https://1.1.1.1/dns-query) chiffre ça. Firefox et Chrome supportent DoH nativement.5️⃣ Split-horizon DNS
Ta boîte a
api.example.com. Côté interne (VPN) : 10.0.0.5. Côté public : 52.84.150.50. Même nom, IP différente selon d'où vient la requête. C'est ce que font toutes les entreprises.Commande utile :
dig est ton meilleur ami pour débugger.
$ dig github.com
;; ANSWER SECTION:
github.com. 300 IN A 140.82.121.4
;; Query time: 23 msec
;; SERVER: 1.1.1.1#53
Tu vois le TTL, le record type, l'IP, le temps de réponse, le serveur utilisé. Si ton site ne marche pas après un changement DNS,
dig te dit tout.💾 Enregistre ce post pour ne pas l'oublir.
#DevTips #DNS #Networking #WebDev #MetaCodeLearn