Entraînement Practice
Flashcards pour répéter tes réponses à voix haute, QCM pour vérifier que c'est acquis. Comme en entretien : réponds avant de révéler. Flashcards to rehearse answers out loud, quizzes to check they stuck. Like a real interview: answer before revealing.
Jour 15 Day 15 Observabilité : logs, metrics & traces Observability: logs, metrics & traces
Flashcards Flashcards
Quelle est la différence entre monitoring et observabilité ? What is the difference between monitoring and observability?
Le monitoring vérifie des conditions connues d'avance (seuils, dashboards prédéfinis) et dit QUE ça casse. L'observabilité est la capacité à répondre à des questions non anticipées à partir des données émises par le système (logs, metrics, traces) : elle permet de comprendre POURQUOI. Monitoring checks conditions known in advance (thresholds, predefined dashboards) and tells you THAT something broke. Observability is the ability to answer unanticipated questions from the data the system emits (logs, metrics, traces): it lets you understand WHY.
Quels sont les trois piliers de l'observabilité et leurs forces/faiblesses ? What are the three pillars of observability and their strengths/weaknesses?
Logs : événements discrets riches en contexte, chers en volume. Metrics : agrégats numériques pas chers, parfaits pour alerter, pauvres en contexte. Traces : parcours d'une requête à travers les services en spans. Leur vraie force : la corrélation par trace ID. Logs: discrete events rich in context, expensive in volume. Metrics: cheap numeric aggregates, perfect for alerting, poor in context. Traces: a request's journey across services in spans. Their real power: correlation via trace ID.
Pourquoi des logs structurés en JSON plutôt que du texte libre ? Why structured JSON logs rather than free text?
On peut filtrer, agréger et chercher par champ (level, route, user_id, duration_ms) au lieu de grepper du texte. Avec un identifiant de corrélation (request/trace ID) propagé entre services, on reconstitue le parcours complet d'une requête dans toute la stack. You can filter, aggregate and search by field (level, route, user_id, duration_ms) instead of grepping text. With a correlation identifier (request/trace ID) propagated between services, you can reconstruct a request's full journey through the stack.
Que sont les méthodes RED et USE ? What are the RED and USE methods?
RED, pour les services : Rate (requêtes/s), Errors (taux d'erreur), Duration (latence en percentiles p50/p95/p99). USE, pour les ressources : Utilization, Saturation, Errors. Deux grilles standard pour construire dashboards et alertes. RED, for services: Rate (requests/s), Errors (error rate), Duration (latency in p50/p95/p99 percentiles). USE, for resources: Utilization, Saturation, Errors. Two standard grids for building dashboards and alerts.
Comment fonctionne une trace distribuée ? How does a distributed trace work?
Une trace est un arbre de spans, chacun représentant une opération (appel HTTP, requête SQL) avec durée, attributs et parent. La context propagation transporte le trace ID et le span ID parent dans les headers HTTP (W3C traceparent) de service en service, permettant de reconstituer l'arbre complet. A trace is a tree of spans, each representing an operation (HTTP call, SQL query) with duration, attributes and a parent. Context propagation carries the trace ID and parent span ID in HTTP headers (W3C traceparent) from service to service, allowing the full tree to be reconstructed.
Qu'est-ce qu'OpenTelemetry et son argument clé ? What is OpenTelemetry and its key argument?
Le standard CNCF vendor-neutral pour générer et exporter logs, metrics et traces : SDK par langage, auto-instrumentation, et un Collector qui reçoit, transforme et exporte. On instrumente une fois et on change de backend (Jaeger, Prometheus, Datadog…) sans toucher au code : pas de lock-in. The vendor-neutral CNCF standard for generating and exporting logs, metrics and traces: per-language SDKs, auto-instrumentation, and a Collector that receives, transforms and exports. Instrument once and switch backends (Jaeger, Prometheus, Datadog…) without touching the code: no lock-in.
SLI et SLO : définis-les en deux phrases. SLI and SLO: define them in two sentences.
Un SLI est une mesure de ce que vivent les utilisateurs (ex. proportion de requêtes servies en moins de 300 ms). Un SLO est l'objectif qu'on s'engage à tenir sur ce SLI (ex. 99,9 % sur 30 jours) — le budget d'erreur qui en découle arbitre entre fiabilité et vitesse de déploiement. An SLI is a measurement of what users experience (e.g. proportion of requests served under 300 ms). An SLO is the target you commit to on that SLI (e.g. 99.9% over 30 days) — the resulting error budget arbitrates between reliability and deployment speed.
Pourquoi alerter sur les symptômes plutôt que sur les causes ? Why alert on symptoms rather than causes?
Les utilisateurs subissent les symptômes (erreurs, latence), pas les causes (CPU haut). Un CPU à 95 % avec des utilisateurs heureux ne justifie pas de réveiller quelqu'un ; un taux d'erreur à 5 % si. Alerter sur les causes génère de l'alert fatigue ; les causes se consultent dans les dashboards après l'alerte. Users suffer symptoms (errors, latency), not causes (high CPU). A CPU at 95% with happy users doesn't justify waking someone up; a 5% error rate does. Alerting on causes generates alert fatigue; causes get consulted in dashboards after the alert.
QCM Quiz
Quel pilier est le moins cher à stocker et le plus adapté aux alertes ? Which pillar is the cheapest to store and best suited for alerting?
Une metric est une série de nombres agrégés : quelques octets par point, évaluable en continu par le moteur d'alerting. Logs et traces sont riches mais volumineux — ils servent au diagnostic, pas au déclenchement. A metric is a series of aggregated numbers: a few bytes per point, continuously evaluable by the alerting engine. Logs and traces are rich but bulky — they serve diagnosis, not triggering.
Pourquoi ne jamais mettre user_id en label d'une metric Prometheus ? Why should you never put user_id as a Prometheus metric label?
Chaque combinaison de valeurs de labels est une série distincte en mémoire : un million d'utilisateurs = un million de séries par metric. Les labels doivent avoir des valeurs bornées (status code, endpoint) ; les IDs uniques vont dans les logs et traces. Each combination of label values is a distinct series in memory: a million users = a million series per metric. Labels must have bounded values (status code, endpoint); unique IDs belong in logs and traces.
Comment le contexte d'une trace se propage-t-il entre deux services HTTP ? How does trace context propagate between two HTTP services?
La context propagation est faite par l'instrumentation : le client injecte le header traceparent, le serveur suivant le lit et crée ses spans comme enfants. Le Collector reçoit les spans exportés, il n'intercepte pas le trafic. Context propagation is done by the instrumentation: the client injects the traceparent header, the next server reads it and creates its spans as children. The Collector receives exported spans; it doesn't intercept traffic.
Latence moyenne à 80 ms mais des plaintes d'utilisateurs : que regarder d'abord ? Average latency at 80 ms but users are complaining: what do you look at first?
99 requêtes à 50 ms + 1 à 5 s donnent une moyenne correcte et 1 % d'utilisateurs furieux — souvent les plus actifs. Les percentiles décrivent l'expérience réelle ; c'est pour ça que les SLO se définissent sur des percentiles. 99 requests at 50 ms + 1 at 5 s give a decent average and 1% of furious users — often the most active. Percentiles describe the real experience; that's why SLOs are defined on percentiles.
Quel est le principal argument d'OpenTelemetry face aux SDK propriétaires (Datadog, New Relic…) ? What is OpenTelemetry's main argument versus proprietary SDKs (Datadog, New Relic…)?
OTel standardise l'instrumentation et l'export (via le Collector) : le backend devient interchangeable, fini le lock-in par le code instrumenté. OTel ne stocke rien lui-même : il génère et transporte les signaux vers un backend. OTel standardizes instrumentation and export (via the Collector): the backend becomes interchangeable, ending lock-in through instrumented code. OTel stores nothing itself: it generates and transports signals to a backend.
Une équipe reçoit 40 alertes par jour et les acquitte sans agir. Quel est le vrai problème ? A team receives 40 alerts a day and acknowledges them without acting. What is the real problem?
Une alerte acquittée sans action est une alerte inutile qui entraîne l'équipe à ignorer les notifications. Remède : alerter sur les symptômes (SLI/SLO), supprimer ou revoir chaque alerte non actionnable — pas ajouter du monde ni des seuils plus fins. An alert acknowledged without action is a useless alert training the team to ignore notifications. Remedy: alert on symptoms (SLI/SLO), delete or rework every non-actionable alert — not adding people or tighter thresholds.
Jour 14 Day 14 MCP : le Model Context Protocol MCP: the Model Context Protocol
Flashcards Flashcards
Quel problème MCP résout-il ? What problem does MCP solve?
L'intégration N×M : chaque application LLM devait écrire un connecteur custom pour chaque service. MCP standardise le protocole entre les deux : un serveur écrit une fois fonctionne avec tous les hosts compatibles — on passe de N×M à N+M connecteurs. N×M integration: every LLM application had to write a custom connector for every service. MCP standardizes the protocol between the two: a server written once works with every compatible host — going from N×M to N+M connectors.
Quels sont les trois rôles de l'architecture MCP ? What are the three roles in the MCP architecture?
Le host (l'application LLM : Claude Desktop, un IDE), qui orchestre ; le client (la connexion 1-à-1 vers un serveur, à l'intérieur du host) ; le serveur (le programme qui expose tools, resources et prompts). Un host connecté à trois serveurs maintient trois clients. The host (the LLM application: Claude Desktop, an IDE), which orchestrates; the client (the 1-to-1 connection to a server, inside the host); the server (the program exposing tools, resources and prompts). A host connected to three servers maintains three clients.
Tools, resources, prompts : qui contrôle quoi ? Tools, resources, prompts: who controls what?
Tools : le modèle décide de les appeler (avec approbation utilisateur) — ex. create_issue. Resources : l'application choisit les données à attacher au contexte — ex. contenu de fichier. Prompts : templates déclenchés explicitement par l'utilisateur — ex. slash commands. Tools: the model decides to call them (with user approval) — e.g. create_issue. Resources: the application chooses the data to attach to the context — e.g. file contents. Prompts: templates explicitly triggered by the user — e.g. slash commands.
Sur quoi repose la communication MCP et quels sont les deux transports standard ? What does MCP communication run on, and what are the two standard transports?
Sur JSON-RPC 2.0, avec une poignée de main initialize qui négocie version et capacités. Transports : stdio (le host lance le serveur en sous-processus, communication stdin/stdout, idéal en local) et HTTP streamable (endpoint distant avec streaming, qui remplace l'ancien HTTP+SSE). On JSON-RPC 2.0, with an initialize handshake negotiating version and capabilities. Transports: stdio (the host launches the server as a subprocess, stdin/stdout communication, ideal locally) and streamable HTTP (a remote endpoint with streaming, replacing the older HTTP+SSE).
Quelle différence entre MCP et le function calling classique ? What's the difference between MCP and classic function calling?
Le function calling est le mécanisme par lequel le modèle génère des appels de fonctions, mais chaque intégration reste du code custom dans une seule app. MCP standardise la couche au-dessus : découverte dynamique (tools/list), transport, cycle de vie — un serveur MCP est réutilisable par n'importe quel host. Function calling is the mechanism by which the model generates function calls, but each integration remains custom code inside a single app. MCP standardizes the layer above: dynamic discovery (tools/list), transport, lifecycle — an MCP server is reusable by any host.
Qu'est-ce que la prompt injection indirecte via un outil MCP ? What is indirect prompt injection through an MCP tool?
Du contenu externe rapporté par un outil (page web, issue GitHub, email) contient des instructions malveillantes que le modèle risque de suivre — ex. exfiltrer des secrets via un autre outil. Le trio dangereux : données privées + contenu non fiable + canal de sortie externe. External content brought back by a tool (web page, GitHub issue, email) contains malicious instructions the model may follow — e.g. exfiltrating secrets through another tool. The dangerous trio: private data + untrusted content + an external output channel.
Quelles parades de sécurité citer pour un déploiement MCP ? Which security countermeasures should you cite for an MCP deployment?
Principe du moindre privilège (tokens à permissions minimales, serveurs read-only si possible), human-in-the-loop pour les actions sensibles, audit des serveurs tiers avant installation (ils exécutent du code localement), et isolation des serveurs à risque. Principle of least privilege (minimally-scoped tokens, read-only servers when possible), human-in-the-loop for sensitive actions, auditing third-party servers before installing them (they run code locally), and isolating risky servers.
Pourquoi MCP est-il un bon sujet d'entretien en 2026, et comment en parler intelligemment ? Why is MCP a good interview topic in 2026, and how do you discuss it intelligently?
Adopté au-delà d'Anthropic (OpenAI, Google DeepMind, Microsoft, les IDE), c'est le standard de facto des agents. Un stagiaire marque des points en citant un usage concret (serveur GitHub/Postgres dans un IDE) ou un mini-serveur écrit avec le SDK, plus les limites : coût en tokens, risques d'injection. Adopted beyond Anthropic (OpenAI, Google DeepMind, Microsoft, IDEs), it's the de facto agent standard. An intern scores points by citing concrete usage (a GitHub/Postgres server in an IDE) or a mini-server written with the SDK, plus the limits: token cost, injection risks.
QCM Quiz
MCP transforme le problème d'intégration N×M en : MCP turns the N×M integration problem into:
Chaque application implémente le protocole une fois (côté client), chaque service est encapsulé une fois (côté serveur) : N+M composants au lieu de N×M intégrations custom. C'est l'analogie USB-C. Each application implements the protocol once (client side), each service is wrapped once (server side): N+M components instead of N×M custom integrations. That's the USB-C analogy.
Dans MCP, qui décide d'appeler un tool ? In MCP, who decides to call a tool?
Les tools sont contrôlés par le modèle (avec garde-fou humain). Ce sont les resources qui sont contrôlées par l'application, et les prompts par l'utilisateur — la séparation des trois est un choix de design du protocole. Tools are model-controlled (with a human guardrail). Resources are application-controlled and prompts user-controlled — the three-way separation is a deliberate protocol design choice.
Quel transport utilise un serveur MCP lancé localement par Claude Desktop ? Which transport does an MCP server launched locally by Claude Desktop use?
En local, le host lance le serveur comme sous-processus et échange des messages JSON-RPC sur stdin/stdout : simple, pas de port réseau. Pour les serveurs distants ou partagés, c'est le transport HTTP streamable. Locally, the host launches the server as a subprocess and exchanges JSON-RPC messages over stdin/stdout: simple, no network port. For remote or shared servers, it's the streamable HTTP transport.
Quelle est LA différence clé entre un serveur MCP et du function calling codé dans une app ? What is THE key difference between an MCP server and function calling coded into an app?
C'est la standardisation qui change tout : découverte dynamique, transport commun, réutilisabilité entre apps. MCP n'améliore pas le raisonnement du modèle, et un serveur MCP wrappe généralement une API existante. Standardization is what changes everything: dynamic discovery, common transport, reusability across apps. MCP doesn't improve the model's reasoning, and an MCP server usually wraps an existing API.
Un serveur MCP de lecture d'emails + un outil d'envoi de messages + accès à des documents privés. Quel est le risque principal ? An email-reading MCP server + a message-sending tool + access to private documents. What is the main risk?
C'est le trio dangereux : contenu non fiable (emails entrants) + données privées + canal de sortie (envoi). Un email piégé contenant des instructions peut détourner le modèle. Parades : moindre privilège et approbation humaine des envois. That's the dangerous trio: untrusted content (incoming emails) + private data + an output channel (sending). A booby-trapped email containing instructions can hijack the model. Countermeasures: least privilege and human approval of sends.
Pourquoi éviter de brancher 15 serveurs MCP « au cas où » ? Why avoid plugging in 15 MCP servers "just in case"?
Les définitions d'outils s'ajoutent au contexte à chaque requête, et un choix parmi 50 outils est moins fiable qu'un choix parmi 5. Pas de limite protocolaire ni de « port stdio » : c'est un arbitrage coût/pertinence. Tool definitions are added to the context on every request, and choosing among 50 tools is less reliable than among 5. No protocol limit and no "stdio port": it's a cost/relevance trade-off.
Jour 13 Day 13 Kubernetes : l'orchestration expliquée Kubernetes: orchestration explained
Flashcards Flashcards
Qu'apporte Kubernetes par rapport à Docker Compose ? What does Kubernetes bring over Docker Compose?
Compose démarre une stack sur une seule machine. K8s ajoute le multi-machines, la boucle de réconciliation (self-healing automatique), le scaling déclaratif, les rolling updates avec rollback, et le service discovery/load balancing intégrés — au prix d'une complexité opérationnelle bien supérieure. Compose starts a stack on a single machine. K8s adds multi-machine support, the reconciliation loop (automatic self-healing), declarative scaling, rolling updates with rollback, and built-in service discovery/load balancing — at the cost of far greater operational complexity.
Quels sont les composants du control plane et leur rôle ? What are the control plane components and their roles?
kube-apiserver (point d'entrée unique, valide et persiste les objets), etcd (base clé-valeur stockant tout l'état du cluster), kube-scheduler (choisit le node de chaque nouveau Pod), controller manager (fait tourner les boucles de réconciliation). kube-apiserver (single entry point, validates and persists objects), etcd (key-value store holding the entire cluster state), kube-scheduler (picks the node for each new Pod), controller manager (runs the reconciliation loops).
Que font kubelet et kube-proxy sur un worker node ? What do kubelet and kube-proxy do on a worker node?
kubelet surveille l'API server, lance les conteneurs des Pods assignés au node via le container runtime (containerd) et remonte leur état. kube-proxy programme les règles réseau (iptables/IPVS) pour que les Services routent vers les bons Pods. kubelet watches the API server, starts the containers of Pods assigned to the node through the container runtime (containerd) and reports their status. kube-proxy programs the network rules (iptables/IPVS) so Services route to the right Pods.
Explique la chaîne Deployment → ReplicaSet → Pod. Explain the Deployment → ReplicaSet → Pod chain.
Le Deployment gère les versions et les rolling updates (nouveau ReplicaSet monté progressivement, ancien descendu, rollback possible). Le ReplicaSet maintient le nombre de réplicas demandé. Le Pod est la plus petite unité : un ou plusieurs conteneurs partageant IP et volumes, éphémère par conception. The Deployment manages versions and rolling updates (new ReplicaSet scaled up progressively, old one scaled down, rollback possible). The ReplicaSet maintains the requested replica count. The Pod is the smallest unit: one or more containers sharing IP and volumes, ephemeral by design.
Quels sont les trois types de Service principaux et leurs usages ? What are the three main Service types and their uses?
ClusterIP : IP virtuelle interne au cluster (le défaut, pour le trafic entre services). NodePort : ouvre un port sur chaque node (tests, on-prem sans LB). LoadBalancer : provisionne un load balancer cloud avec IP publique — en pratique un seul, devant un Ingress qui route vers N services ClusterIP. ClusterIP: cluster-internal virtual IP (the default, for service-to-service traffic). NodePort: opens a port on every node (testing, on-prem without a LB). LoadBalancer: provisions a cloud load balancer with a public IP — in practice just one, in front of an Ingress routing to N ClusterIP services.
Liveness vs readiness probe : quelle différence et quel piège ? Liveness vs readiness probe: what's the difference and the trap?
Liveness : le process est-il vivant ? Échec → restart du conteneur. Readiness : peut-il recevoir du trafic ? Échec → retiré des endpoints du Service, sans restart. Piège : tester une dépendance externe (DB) dans la liveness → restarts en boucle quand la dépendance a un souci. Liveness: is the process alive? Failure → container restart. Readiness: can it receive traffic? Failure → removed from the Service's endpoints, no restart. Trap: testing an external dependency (DB) in the liveness probe → restart loops whenever the dependency has an issue.
À quoi servent requests et limits ? What are requests and limits for?
requests = ressources garanties, utilisées par le scheduler pour placer le Pod. limits = plafond : CPU throttlé au-delà, dépassement mémoire → OOMKilled. Sans requests le scheduling est aveugle ; sans limits un Pod peut affamer le node. requests = guaranteed resources, used by the scheduler to place the Pod. limits = ceiling: CPU is throttled beyond it, exceeding memory → OOMKilled. Without requests scheduling is blind; without limits one Pod can starve the node.
Quand Kubernetes est-il overkill ? When is Kubernetes overkill?
Pour un projet à un ou deux services sur un seul serveur : un VPS avec Docker Compose ou un PaaS suffit, avec une fraction de la complexité. K8s se justifie avec plusieurs machines, des besoins réels de scaling/haute dispo, et une équipe capable de l'opérer. For a project with one or two services on a single server: a VPS with Docker Compose or a PaaS is enough, at a fraction of the complexity. K8s is justified with multiple machines, real scaling/high-availability needs, and a team able to operate it.
QCM Quiz
Où est stocké tout l'état du cluster Kubernetes ? Where is the entire Kubernetes cluster state stored?
etcd est la base clé-valeur distribuée du control plane : tous les objets (Deployments, Services, Secrets…) y sont persistés via l'API server. La perdre sans backup, c'est perdre le cluster. etcd is the control plane's distributed key-value store: every object (Deployments, Services, Secrets…) is persisted there through the API server. Losing it without a backup means losing the cluster.
Un Pod crashe. Qui le recrée ? A Pod crashes. Who recreates it?
Le ReplicaSet controller compare en permanence réplicas observés et désirés : 2 au lieu de 3 → il crée un Pod. Le scheduler intervient ensuite seulement pour placer ce nouveau Pod sur un node. The ReplicaSet controller continuously compares observed and desired replicas: 2 instead of 3 → it creates a Pod. The scheduler only steps in afterwards to place that new Pod on a node.
Pourquoi les Secrets Kubernetes ne sont-ils pas sécurisés par défaut ? Why aren't Kubernetes Secrets secure by default?
base64 est un encodage réversible en une commande, pas du chiffrement. Il faut activer l'encryption at rest d'etcd, restreindre l'accès par RBAC, et idéalement utiliser un gestionnaire externe (Vault, secrets du cloud). base64 is an encoding reversible in one command, not encryption. You need etcd encryption at rest, RBAC-restricted access, and ideally an external manager (Vault, cloud secrets).
Que se passe-t-il quand un conteneur dépasse sa limit mémoire ? What happens when a container exceeds its memory limit?
Contrairement au CPU (compressible, donc throttlé), la mémoire ne se throttle pas : dépassement = OOMKilled par le noyau, puis restart selon la restartPolicy. D'où l'importance de dimensionner les limits avec de vraies mesures. Unlike CPU (compressible, therefore throttled), memory can't be throttled: exceeding it = OOMKilled by the kernel, then restarted per the restartPolicy. Hence the importance of sizing limits from real measurements.
Quel objet permet de router api.exemple.com et www.exemple.com vers deux services différents avec une seule IP publique ? Which object routes api.example.com and www.example.com to two different services with a single public IP?
L'Ingress fait du routage HTTP par host/path et de la terminaison TLS derrière un seul point d'entrée. Deux LoadBalancer fonctionneraient mais coûteraient une IP publique chacun. The Ingress does HTTP host/path routing and TLS termination behind a single entry point. Two LoadBalancers would work but would each cost a public IP.
Une readiness probe échoue sur un Pod. Que fait Kubernetes ? A readiness probe fails on a Pod. What does Kubernetes do?
Readiness = aptitude à recevoir du trafic : en échec, le Pod est simplement sorti du load balancing jusqu'à ce que la probe repasse au vert. C'est la liveness qui déclenche un restart. Readiness = ability to receive traffic: on failure, the Pod is simply pulled out of load balancing until the probe goes green again. It's the liveness probe that triggers a restart.
Jour 12 Day 12 TypeScript : le typage qui change tout TypeScript: typing that changes everything
Flashcards Flashcards
Que devient le typage TypeScript à l'exécution ? What happens to TypeScript's typing at runtime?
Il disparaît entièrement : `tsc` efface les annotations et émet du JavaScript pur. La vérification est uniquement statique — aucune donnée n'est validée au runtime, d'où le besoin de validation aux frontières (zod) pour les entrées externes. It disappears entirely: `tsc` erases the annotations and emits plain JavaScript. Checking is static only — no data is validated at runtime, hence the need for boundary validation (zod) on external input.
Qu'est-ce que le typage structurel de TypeScript ? What is TypeScript's structural typing?
Deux types sont compatibles si leurs structures le sont, peu importe leur nom (duck typing vérifié statiquement). Un objet avec les bonnes propriétés est assignable à une interface même s'il n'a jamais été déclaré comme telle — contrairement au typage nominal de Java/C#. Two types are compatible if their structures are, regardless of their names (statically checked duck typing). An object with the right properties is assignable to an interface even if it was never declared as one — unlike Java/C#'s nominal typing.
Quelle est la différence entre `any` et `unknown` ? What's the difference between `any` and `unknown`?
`any` désactive toute vérification et se propage à tout ce qu'il touche. `unknown` accepte n'importe quelle valeur mais interdit tout usage tant qu'on n'a pas rétréci le type (typeof, type guard, validation). Aux frontières : `unknown`, jamais `any`. `any` disables all checking and spreads to everything it touches. `unknown` accepts any value but forbids any use until the type has been narrowed (typeof, type guard, validation). At the boundaries: `unknown`, never `any`.
Qu'est-ce que le narrowing ? What is narrowing?
Le rétrécissement d'un type union au fil du contrôle de flot : après `if (typeof x === "string")`, `x` est un `string` dans la branche. Outils : `typeof`, `instanceof`, `in`, champ discriminant d'une discriminated union, type guards personnalisés (`x is User`). Shrinking a union type through control flow: after `if (typeof x === "string")`, `x` is a `string` inside the branch. Tools: `typeof`, `instanceof`, `in`, the discriminant field of a discriminated union, custom type guards (`x is User`).
Interface vs type : quand utiliser quoi ? Interface vs type: when to use which?
Quasi interchangeables pour un objet. `interface` : declaration merging et `extends`, bien pour les formes d'objets publiques. `type` : unions, intersections, tuples, mapped types. Le choix relève surtout de la convention d'équipe. Nearly interchangeable for an object. `interface`: declaration merging and `extends`, good for public object shapes. `type`: unions, intersections, tuples, mapped types. The choice is mostly team convention.
Donne un exemple de générique avec contrainte et explique ce qu'il garantit. Give an example of a constrained generic and explain what it guarantees.
`function getProp<T, K extends keyof T>(obj: T, key: K): T[K]` : `K` doit être une clé existante de `T`, donc demander une propriété inexistante est une erreur de compilation, et le type de retour est exactement celui de la propriété demandée. `function getProp<T, K extends keyof T>(obj: T, key: K): T[K]`: `K` must be an existing key of `T`, so asking for a nonexistent property is a compile error, and the return type is exactly that of the requested property.
Cite quatre utility types et leur usage typique. Name four utility types and their typical use.
`Partial<T>` : tout optionnel (payload PATCH). `Pick<T, K>` : ne garder que certaines clés. `Omit<T, K>` : tout sauf certaines clés (DTO sans `password`). `Record<K, V>` : dictionnaire typé (`Record<string, number>`). `Partial<T>`: everything optional (PATCH payload). `Pick<T, K>`: keep only certain keys. `Omit<T, K>`: everything except certain keys (DTO without `password`). `Record<K, V>`: typed dictionary (`Record<string, number>`).
Pourquoi valider une réponse d'API avec zod alors qu'elle est déjà typée ? Why validate an API response with zod when it's already typed?
Parce que le type est une annotation de compilation, pas une garantie : le serveur peut renvoyer n'importe quoi. `schema.parse(data)` valide réellement au runtime, et `z.infer<typeof schema>` dérive le type statique du schéma — une seule source de vérité pour les deux niveaux. Because the type is a compile-time annotation, not a guarantee: the server can return anything. `schema.parse(data)` actually validates at runtime, and `z.infer<typeof schema>` derives the static type from the schema — one source of truth for both levels.
QCM Quiz
Quel est le principal danger de `any` ? What is the main danger of `any`?
`any` court-circuite le compilateur silencieusement et contamine la chaîne d'appels. Aucun impact runtime : les types sont effacés. `noImplicitAny` (strict mode) aide à le traquer. `any` silently bypasses the compiler and contaminates the call chain. No runtime impact: types are erased. `noImplicitAny` (strict mode) helps track it down.
Pourquoi un objet `{ name: "Ana", age: 30 }` est-il assignable à `interface Person { name: string }` ? Why is an object `{ name: "Ana", age: 30 }` assignable to `interface Person { name: string }`?
Typage structurel : la compatibilité se juge sur la forme, pas sur une déclaration `implements`. Nuance : un littéral d'objet passé directement subit l'excess property check, qui refuse les propriétés inconnues. Structural typing: compatibility is judged on shape, not on an `implements` declaration. Nuance: an object literal passed directly triggers the excess property check, which rejects unknown properties.
Que fait `strictNullChecks` ? What does `strictNullChecks` do?
Sans strictNullChecks, `null`/`undefined` sont assignables partout et les erreurs "cannot read property of undefined" passent. Avec, un `string | null` force le narrowing avant usage. Aucune vérification runtime : tout est statique. Without strictNullChecks, `null`/`undefined` are assignable everywhere and "cannot read property of undefined" errors slip through. With it, a `string | null` forces narrowing before use. No runtime checks: it's all static.
Quel utility type pour un DTO utilisateur sans le champ password ? Which utility type for a user DTO without the password field?
`Omit` retire des clés d'un type. `Pick<User, "password">` ferait l'inverse (ne garder que password), `Partial` rendrait tout optionnel sans rien retirer, et `Record` construit un dictionnaire. `Omit` removes keys from a type. `Pick<User, "password">` would do the opposite (keep only password), `Partial` would make everything optional without removing anything, and `Record` builds a dictionary.
Que signifie `data as User` sur une réponse d'API ? What does `data as User` mean on an API response?
`as` ne convertit ni ne valide rien : c'est une promesse faite au compilateur. Si le serveur renvoie autre chose, le bug explosera plus loin. La validation réelle passe par un schéma runtime comme zod. `as` neither converts nor validates anything: it's a promise made to the compiler. If the server returns something else, the bug blows up later. Real validation goes through a runtime schema like zod.
Après `if (typeof x === "string")` sur un `x: string | number`, quel est le type de x dans la branche else ? After `if (typeof x === "string")` on an `x: string | number`, what is the type of x in the else branch?
Le narrowing fonctionne dans les deux sens : la branche if élimine `number`, donc la branche else élimine `string`. Le compilateur suit le contrôle de flot pour rétrécir l'union des deux côtés. Narrowing works both ways: the if branch eliminates `number`, so the else branch eliminates `string`. The compiler follows control flow to shrink the union on both sides.
Jour 11 Day 11 Microservices vs monolithe Microservices vs monolith
Flashcards Flashcards
Pourquoi le monolithe est-il souvent le bon choix en début de projet ? Why is the monolith often the right choice early in a project?
Un appel de fonction est infiniment plus simple qu'un appel réseau : pas de latence ni de panne partielle, une transaction ACID couvre tout, un seul déploiement, une stack trace pour debugger. En début de projet, la vitesse d'itération prime et les frontières de domaines sont encore inconnues — les microservices les figeraient trop tôt. A function call is infinitely simpler than a network call: no latency or partial failure, one ACID transaction covers everything, one deployment, one stack trace for debugging. Early on, iteration speed rules and domain boundaries are still unknown — microservices would freeze them too early.
Qu'est-ce qu'un monolithe modulaire ? What is a modular monolith?
Un seul déployable, mais des modules internes aux frontières nettes : chaque module n'est accessible que par son interface publique (billing ne touche pas aux tables de users). On garde la simplicité opérationnelle du monolithe tout en préparant une éventuelle extraction future — un déménagement plutôt qu'une réécriture. A single deployable, but internal modules with clean boundaries: each module is only reachable through its public interface (billing never touches users' tables). You keep the monolith's operational simplicity while preparing a possible future extraction — a move rather than a rewrite.
Quelles sont les trois vraies promesses des microservices ? What are the three real promises of microservices?
1) Déploiement indépendant : chaque équipe déploie sans attendre les autres — la promesse centrale. 2) Scaling ciblé : répliquer un seul service sous charge (surtout utile pour des besoins asymétriques : GPU, mémoire, langage). 3) Ownership d'équipe : chaque équipe possède ses services de bout en bout — la loi de Conway appliquée volontairement. 1) Independent deployment: each team deploys without waiting for the others — the central promise. 2) Targeted scaling: replicating one service under load (mostly useful for asymmetric needs: GPU, memory, language). 3) Team ownership: each team owns its services end to end — Conway's law applied deliberately.
Qu'est-ce qu'un distributed monolith ? What is a distributed monolith?
L'anti-pattern n°1 : des services séparés par le réseau mais couplés au point de devoir se déployer ensemble (base partagée, API fragiles, chaînes d'appels synchrones). On paie tous les coûts du distribué — latence, pannes partielles, complexité ops — sans le bénéfice central du déploiement indépendant. The number one anti-pattern: services separated by the network but so coupled they must deploy together (shared database, fragile APIs, chains of synchronous calls). You pay every cost of distribution — latency, partial failures, ops complexity — without the central benefit of independent deployment.
Pourquoi le pattern database-per-service est-il une condition de l'indépendance ? Why is the database-per-service pattern a condition for independence?
Deux services qui partagent une base sont couplés par le schéma : un ALTER TABLE de l'un casse l'autre, et les déploiements redeviennent coordonnés. Chaque service possède sa base ; les autres n'y accèdent que via son API. Le prix : plus de JOIN cross-services ni de transaction ACID globale. Two services sharing a database are coupled through the schema: one's ALTER TABLE breaks the other, and deployments become coordinated again. Each service owns its database; others only access it through its API. The price: no more cross-service JOINs or global ACID transactions.
Explique le pattern saga en deux phrases. Explain the saga pattern in two sentences.
Une saga remplace la transaction distribuée impossible par une séquence de transactions locales, une par service. Si une étape échoue, des transactions de compensation défont les étapes précédentes (annuler la réservation, rembourser le paiement) — orchestrées par un coordinateur ou chorégraphiées par une chaîne d'événements. A saga replaces the impossible distributed transaction with a sequence of local transactions, one per service. If a step fails, compensating transactions undo the previous steps (cancel the reservation, refund the payment) — orchestrated by a coordinator or choreographed through a chain of events.
Communication synchrone vs asynchrone entre services : les compromis ? Synchronous vs asynchronous communication between services: the trade-offs?
Synchrone (REST, gRPC) : simple à raisonner, réponse immédiate, mais couplage temporel — les latences s'additionnent et les pannes se propagent en cascade. Asynchrone (événements via Kafka/RabbitMQ) : découplage, absorption des pics, mais cohérence à terme et debugging plus difficile. Règle pratique : synchrone pour les queries client, asynchrone entre services quand c'est possible. Synchronous (REST, gRPC): easy to reason about, immediate answer, but temporal coupling — latencies add up and failures cascade. Asynchronous (events via Kafka/RabbitMQ): decoupling, burst absorption, but eventual consistency and harder debugging. Practical rule: synchronous for client-facing queries, asynchronous between services whenever possible.
Qu'est-ce que la stratégie strangler fig ? What is the strangler fig strategy?
La migration progressive d'un monolithe : on extrait une capacité à la fois, un proxy ou une gateway route progressivement le trafic vers le nouveau service, et le monolithe rétrécit petit à petit. À l'opposé du big bang rewrite. Chaque extraction doit se justifier seule — commencer par le meilleur ratio douleur/risque. Progressive migration of a monolith: extract one capability at a time, a proxy or gateway gradually routes traffic to the new service, and the monolith shrinks bit by bit. The opposite of a big-bang rewrite. Each extraction must justify itself — start with the best pain-to-risk ratio.
QCM Quiz
Quelle est la promesse CENTRALE des microservices, celle sans laquelle le découpage perd son sens ? What is the CENTRAL promise of microservices, without which the split loses its meaning?
Si les services doivent se déployer ensemble, on a un distributed monolith. Le réseau dégrade les performances (latence), il ne les améliore pas, et le code total augmente (gestion des pannes, sérialisation, ops). If services must deploy together, you have a distributed monolith. The network degrades performance (latency), it doesn't improve it, and total code increases (failure handling, serialization, ops).
Une équipe de 3 développeurs lance un produit avec 8 microservices. Quel est le problème principal ? A 3-developer team launches a product with 8 microservices. What is the main problem?
Trois devs n'ont pas de problème de coordination inter-équipes à résoudre : ils héritent du réseau, de l'observabilité et des N pipelines sans aucun gain de déploiement indépendant. Un monolithe modulaire irait plus vite. Three devs have no inter-team coordination problem to solve: they inherit the network, observability and N pipelines with zero independent-deployment gain. A modular monolith would move faster.
Deux microservices lisent et écrivent directement dans la même base PostgreSQL. Quelle en est la conséquence ? Two microservices read and write directly to the same PostgreSQL database. What is the consequence?
C'est le chemin le plus court vers le distributed monolith : le schéma devient une API implicite entre les deux services. Database-per-service existe précisément pour préserver le déploiement indépendant. (Au contraire, la base partagée PERMET les transactions ACID communes — c'est l'indépendance qu'elle détruit.) It's the shortest road to the distributed monolith: the schema becomes an implicit API between the two services. Database-per-service exists precisely to preserve independent deployment. (If anything, a shared database ENABLES common ACID transactions — what it destroys is independence.)
Dans une saga, que se passe-t-il quand une étape intermédiaire échoue ? In a saga, what happens when an intermediate step fails?
Il n'existe pas de rollback global : chaque transaction locale est déjà commitée dans sa base. La saga définit donc pour chaque étape une compensation métier (annuler la réservation, rembourser) exécutée en cas d'échec en aval. There is no global rollback: each local transaction is already committed in its own database. The saga therefore defines a business compensation for each step (cancel the reservation, refund) executed when a later step fails.
Quel symptôme indique le mieux qu'il est temps d'envisager d'extraire des services d'un monolithe ? Which symptom best indicates it's time to consider extracting services from a monolith?
Le signal pertinent est organisationnel (loi de Conway) : des équipes couplées par le déployable unique. La taille du code ou de la base ne dit rien en soi, et la mode des concurrents encore moins. La douleur d'abord, le découpage ensuite — via strangler fig. The relevant signal is organizational (Conway's law): teams coupled by the single deployable. Code or database size says nothing by itself, and competitors' fashion even less. Pain first, split second — via strangler fig.
Quel est le rôle d'une API gateway dans une architecture microservices ? What is the role of an API gateway in a microservices architecture?
La gateway découple les clients de la topologie interne : ils appellent un point unique qui route, authentifie, limite le débit et agrège. Elle ne gère ni transactions (saga), ni schémas (database-per-service), ni messaging (broker). The gateway decouples clients from the internal topology: they call a single point that routes, authenticates, rate-limits and aggregates. It handles neither transactions (saga), nor schemas (database-per-service), nor messaging (broker).
Jour 10 Day 10 Tester son code : de l'unitaire au E2E Testing your code: from unit to E2E
Flashcards Flashcards
Décris la pyramide de tests et sa logique. Describe the test pyramid and its logic.
Beaucoup de tests unitaires (rapides, isolés, précis dans leur diagnostic), moins de tests d'intégration (plusieurs composants avec de vraies dépendances), très peu de E2E (l'application pilotée comme un utilisateur). Plus on monte, plus le test est réaliste mais lent, cher à maintenir et vague quand il échoue. Many unit tests (fast, isolated, precise in their diagnosis), fewer integration tests (several components with real dependencies), very few E2E tests (the app driven like a user). The higher you climb, the more realistic the test but the slower, more expensive to maintain and vaguer when it fails.
Qu'est-ce que le pattern AAA dans un test unitaire ? What is the AAA pattern in a unit test?
Arrange : préparer les données et l'objet testé. Act : appeler la fonction testée. Assert : vérifier le résultat observable. Cette structure en trois blocs rend le test lisible et garantit qu'il vérifie un comportement précis, avec idéalement une seule raison d'échouer. Arrange: prepare the data and the object under test. Act: call the function being tested. Assert: verify the observable result. This three-block structure keeps the test readable and ensures it verifies one precise behavior, ideally with a single reason to fail.
Différencie stub, mock, spy et fake. Differentiate stub, mock, spy and fake.
Stub : renvoie des réponses préprogrammées (fournit un état au test). Mock : porte des attentes sur les interactions, le test échoue si l'appel attendu ne se produit pas (vérifie un comportement). Spy : enregistre les appels reçus sans changer le comportement. Fake : implémentation réelle mais simplifiée, comme un repository en mémoire. Stub: returns pre-programmed answers (provides state to the test). Mock: carries expectations about interactions, the test fails if the expected call doesn't happen (verifies behavior). Spy: records received calls without changing behavior. Fake: a real but simplified implementation, like an in-memory repository.
Qu'est-ce que le cycle TDD et qu'apporte-t-il concrètement ? What is the TDD cycle and what does it concretely bring?
Red : écrire un test qui échoue. Green : écrire le code minimal qui le fait passer. Refactor : nettoyer avec les tests au vert. Apports : l'API se conçoit du point de vue de l'appelant, le code est testable par construction, et chaque refactoring est protégé par le filet de tests existant. Red: write a failing test. Green: write the minimal code that makes it pass. Refactor: clean up with tests green. Benefits: the API is designed from the caller's point of view, the code is testable by construction, and every refactoring is protected by the existing safety net.
Pourquoi un test unitaire doit-il être déterministe, et quels sont les ennemis classiques ? Why must a unit test be deterministic, and what are the classic enemies?
Un test non déterministe (flaky) détruit la confiance dans la suite : on relance sans lire, un vrai bug finit par passer. Ennemis classiques : Date.now() et l'horloge, Math.random(), les timeouts et sleeps, l'ordre d'itération non garanti, les dépendances entre tests. Solution : injecter le temps et l'aléa comme des dépendances. A non-deterministic (flaky) test destroys trust in the suite: people re-run without reading, and a real bug eventually slips through. Classic enemies: Date.now() and the clock, Math.random(), timeouts and sleeps, unspecified iteration order, inter-test dependencies. Solution: inject time and randomness as dependencies.
À quoi sert Testcontainers ? What is Testcontainers for?
À lancer de vraies dépendances (Postgres, Redis, Kafka…) dans des conteneurs Docker jetables le temps d'une suite de tests d'intégration. On teste les vraies requêtes SQL, contraintes et transactions au lieu de mocker le driver — quelques secondes de démarrage contre un réalisme incomparable. Starting real dependencies (Postgres, Redis, Kafka…) in throwaway Docker containers for the duration of an integration test suite. You test real SQL queries, constraints and transactions instead of mocking the driver — a few seconds of startup for incomparable realism.
Pourquoi la couverture de code est-elle une métrique piégeuse ? Why is code coverage a treacherous metric?
Elle mesure les lignes exécutées, pas les comportements vérifiés : un test sans assertion donne 100 % de couverture et 0 % de valeur. Loi de Goodhart : en cible, elle pousse à écrire des tests pour couvrir plutôt que pour vérifier. Utile en tendance et pour repérer les zones mortes ; le mutation testing mesure mieux la qualité des assertions. It measures executed lines, not verified behaviors: an assertion-free test yields 100% coverage and 0% value. Goodhart's law: as a target, it pushes people to write tests to cover rather than to verify. Useful as a trend and to spot dead zones; mutation testing measures assertion quality better.
Comment réduire la flakiness des tests E2E ? How do you reduce E2E test flakiness?
Attendre des conditions, jamais des durées (auto-waiting de Playwright, attentes explicites sur l'état) ; isoler les données de chaque test ; utiliser des sélecteurs stables (data-testid plutôt que des classes CSS) ; limiter le E2E aux parcours critiques. Un sleep(2000) est presque toujours un futur test flaky. Wait for conditions, never durations (Playwright's auto-waiting, explicit waits on state); isolate each test's data; use stable selectors (data-testid rather than CSS classes); limit E2E to critical journeys. A sleep(2000) is almost always a future flaky test.
QCM Quiz
Quelle est la différence fondamentale entre un mock et un stub ? What is the fundamental difference between a mock and a stub?
Stub = état (alimenter le test en données), mock = comportement (le test échoue si l'appel attendu manque). La « vraie implémentation simplifiée », c'est le fake. Stub = state (feeding the test data), mock = behavior (the test fails if the expected call is missing). The "real simplified implementation" is the fake.
Dans le cycle TDD, que signifie l'étape « red » ? In the TDD cycle, what does the "red" step mean?
Red-green-refactor : le test écrit avant le code doit échouer — sinon il ne prouve rien. On écrit ensuite le code minimal qui le fait passer (green), puis on nettoie (refactor). Red-green-refactor: the test written before the code must fail — otherwise it proves nothing. Then you write the minimal code to pass it (green), then clean up (refactor).
Un refactoring interne (sans changement de comportement) casse 15 tests unitaires. Qu'est-ce que ça révèle ? An internal refactoring (no behavior change) breaks 15 unit tests. What does that reveal?
Si le comportement observable n'a pas changé, des tests qui cassent testaient le « comment » (appels internes, état privé) et non le « quoi ». Symptôme fréquent de l'abus de mocks — en ajouter aggraverait le problème. If observable behavior hasn't changed, breaking tests were testing the "how" (internal calls, private state) rather than the "what". A frequent symptom of mock overuse — adding more would make it worse.
Pour tester une requête SQL complexe avec jointures et contraintes, quelle approche est la plus fiable ? To test a complex SQL query with joins and constraints, which approach is most reliable?
Mocker le driver ou stubber les résultats teste votre imagination : le test passe même si la requête est fausse. Un vrai Postgres jetable valide la syntaxe, les jointures et les contraintes. Le E2E le ferait aussi, mais lentement et avec un diagnostic vague. Mocking the driver or stubbing results tests your imagination: the test passes even if the query is wrong. A real throwaway Postgres validates syntax, joins and constraints. E2E would too, but slowly and with vague diagnosis.
Pourquoi un test sans assertion est-il dangereux ? Why is an assertion-free test dangerous?
Exécuter du code n'est pas le vérifier : le test passe toujours, la couverture monte, et l'équipe croit la zone testée. C'est le cœur du piège de la couverture comme objectif. Executing code is not verifying it: the test always passes, coverage rises, and the team believes the area is tested. That's the heart of the coverage-as-target trap.
Quel remplacement corrige le mieux un `sleep(2000)` dans un test Playwright flaky ? Which replacement best fixes a `sleep(2000)` in a flaky Playwright test?
Une durée fixe est soit trop courte (flaky) soit trop longue (suite lente) — et souvent les deux selon la machine. On attend l'état attendu : Playwright fait ce polling nativement via ses assertions et son auto-waiting. Le retry masque le problème. A fixed duration is either too short (flaky) or too long (slow suite) — often both depending on the machine. Wait for the expected state: Playwright polls natively through its assertions and auto-waiting. Retries mask the problem.
Jour 9 Day 9 WebSockets & le temps réel WebSockets & real-time
Flashcards Flashcards
Quelle limite fondamentale de HTTP les WebSockets résolvent-elles ? What fundamental HTTP limitation do WebSockets solve?
HTTP est requête/réponse : le serveur ne peut pas envoyer de données de sa propre initiative. Le WebSocket établit une connexion TCP persistante et full-duplex : les deux côtés émettent quand ils veulent, avec quelques octets d'overhead par message. HTTP is request/response: the server cannot send data on its own initiative. WebSocket establishes a persistent, full-duplex TCP connection: both sides send whenever they want, with a few bytes of overhead per message.
Décris le handshake WebSocket. Describe the WebSocket handshake.
Le client envoie un GET HTTP avec `Upgrade: websocket`, `Connection: Upgrade` et un nonce `Sec-WebSocket-Key`. Le serveur répond `101 Switching Protocols` avec `Sec-WebSocket-Accept` (SHA-1 du nonce + GUID fixe). La connexion TCP est ensuite réutilisée pour des frames full-duplex. Démarrer en HTTP permet de traverser les proxies et de partager le port 443. The client sends an HTTP GET with `Upgrade: websocket`, `Connection: Upgrade` and a `Sec-WebSocket-Key` nonce. The server answers `101 Switching Protocols` with `Sec-WebSocket-Accept` (SHA-1 of the nonce + a fixed GUID). The TCP connection is then reused for full-duplex frames. Starting as HTTP gets through proxies and shares port 443.
Compare short polling, long polling et SSE. Compare short polling, long polling and SSE.
Short polling : requête toutes les X secondes, simple mais latence moyenne X/2 et requêtes vides. Long polling : le serveur garde la requête ouverte jusqu'à avoir une donnée, latence quasi nulle mais une reconnexion par message. SSE : flux HTTP `text/event-stream` unidirectionnel serveur → client, avec reconnexion automatique native via EventSource — souvent suffisant pour notifications et dashboards. Short polling: a request every X seconds, simple but average latency of X/2 and empty requests. Long polling: the server holds the request open until it has data, near-zero latency but one reconnection per message. SSE: a unidirectional server → client `text/event-stream` HTTP flow, with native automatic reconnection via EventSource — often enough for notifications and dashboards.
À quoi servent les frames ping/pong ? What are ping/pong frames for?
De heartbeat : proxies, NAT et firewalls coupent silencieusement les connexions TCP inactives (souvent après 30-60 s). Le serveur envoie un ping périodique ; sans pong en retour, la connexion est considérée morte et nettoyée. Sans heartbeat, on accumule des connexions zombies et le client croit être connecté à tort. Heartbeat: proxies, NAT and firewalls silently drop idle TCP connections (often after 30-60 s). The server sends a periodic ping; without a pong back, the connection is considered dead and cleaned up. Without a heartbeat you accumulate zombie connections and the client wrongly believes it's connected.
Comment scaler des WebSockets sur plusieurs instances ? How do you scale WebSockets across several instances?
Deux briques : des sticky sessions au load balancer (la connexion, stateful, doit vivre sur une instance stable) et un pub/sub type Redis entre les instances — celle qui reçoit un message le publie sur un channel, toutes les instances abonnées le relaient à leurs propres clients connectés. C'est ce qu'implémente l'adapter Redis de socket.io. Two building blocks: sticky sessions at the load balancer (the connection is stateful and must live on a stable instance) and a Redis-style pub/sub between instances — the one receiving a message publishes it on a channel, and every subscribed instance relays it to its own connected clients. That's what socket.io's Redis adapter implements.
Qu'apporte socket.io par rapport au WebSocket natif, et à quel prix ? What does socket.io add over native WebSocket, and at what cost?
Apports : reconnexion automatique, rooms, namespaces, acknowledgements, fallback en long polling et adapter Redis pour le multi-instance. Prix : un protocole propriétaire (incompatible avec un client ou serveur WebSocket brut) et une dépendance des deux côtés. Aujourd'hui, ce sont surtout les rooms et l'adapter qui le justifient, plus le fallback. Additions: automatic reconnection, rooms, namespaces, acknowledgements, long-polling fallback and a Redis adapter for multi-instance. Cost: a proprietary protocol (incompatible with a raw WebSocket client or server) and a dependency on both sides. Today, rooms and the adapter justify it more than the fallback does.
Comment authentifier une connexion WebSocket depuis un navigateur ? How do you authenticate a WebSocket connection from a browser?
L'API WebSocket du navigateur n'autorise pas de headers custom. Options : cookie de session envoyé au handshake (en vérifiant impérativement le header Origin), token court-vécu en query string (attention aux logs serveur) ou message d'authentification juste après l'ouverture. L'identité est ensuite attachée à la connexion. The browser's WebSocket API doesn't allow custom headers. Options: session cookie sent at the handshake (imperatively checking the Origin header), a short-lived token in the query string (beware server logs) or an authentication message right after opening. Identity is then attached to the connection.
Qu'est-ce que le cross-site WebSocket hijacking et comment s'en protéger ? What is cross-site WebSocket hijacking and how do you defend against it?
Les WebSockets ne sont pas soumis au CORS : un site malveillant peut ouvrir une connexion vers votre serveur, et le navigateur y joint les cookies de session. Si le serveur ne vérifie pas le header Origin contre une allowlist, l'attaquant obtient une connexion authentifiée au nom de la victime. Protection : valider Origin au handshake (et/ou utiliser des tokens plutôt que le cookie seul). WebSockets are not subject to CORS: a malicious site can open a connection to your server, and the browser attaches the session cookies. If the server doesn't check the Origin header against an allowlist, the attacker gets an authenticated connection on the victim's behalf. Defense: validate Origin at the handshake (and/or use tokens rather than the cookie alone).
QCM Quiz
Quel code de statut HTTP conclut un handshake WebSocket réussi ? Which HTTP status code concludes a successful WebSocket handshake?
Le serveur accepte l'upgrade avec 101 Switching Protocols et le header Sec-WebSocket-Accept. 426 est au contraire l'erreur renvoyée quand le serveur exige un upgrade que le client n'a pas proposé. The server accepts the upgrade with 101 Switching Protocols and the Sec-WebSocket-Accept header. 426 is the opposite: the error returned when the server requires an upgrade the client didn't offer.
Pour pousser des notifications serveur → client sans que le client n'émette, quel est le choix le plus simple et suffisant ? To push server → client notifications with no client-side sending, what is the simplest sufficient choice?
Le flux est unidirectionnel : SSE suffit, avec EventSource qui gère reconnexion et reprise (Last-Event-ID) sans code. Le WebSocket ajouterait heartbeat et reconnexion manuelle pour rien. The flow is unidirectional: SSE is enough, with EventSource handling reconnection and resumption (Last-Event-ID) without code. A WebSocket would add heartbeat and manual reconnection for nothing.
Sur un chat à 3 instances derrière un load balancer, pourquoi faut-il un pub/sub Redis ? In a chat running on 3 instances behind a load balancer, why do you need a Redis pub/sub?
Le WebSocket est stateful : l'instance A ne connaît que ses propres connexions. Elle publie le message sur un channel Redis, et B et C le relaient à leurs clients. La persistance de l'historique est un problème séparé (base de données). WebSocket is stateful: instance A only knows its own connections. It publishes the message on a Redis channel, and B and C relay it to their clients. Persisting history is a separate problem (database).
Pourquoi la reconnexion client doit-elle utiliser un backoff exponentiel avec jitter ? Why must client reconnection use exponential backoff with jitter?
Une reconnexion immédiate en boucle transforme chaque incident en auto-DDoS : des milliers de clients synchronisés reviennent au même instant. Le backoff espace les tentatives, le jitter les désynchronise. La RFC ne dit rien du comportement de reconnexion. Immediate reconnection in a loop turns every incident into a self-inflicted DDoS: thousands of synchronized clients return at the same instant. Backoff spaces the attempts, jitter desynchronizes them. The RFC says nothing about reconnection behavior.
Un client WebSocket natif (API du navigateur) peut-il se connecter à un serveur socket.io ? Can a native WebSocket client (browser API) connect to a socket.io server?
socket.io encapsule ses messages (Engine.IO + son propre framing) : un client brut recevra des données incompréhensibles et échouera au handshake applicatif. Client et serveur doivent parler socket.io tous les deux. socket.io wraps its messages (Engine.IO + its own framing): a raw client receives unintelligible data and fails the application-level handshake. Client and server must both speak socket.io.
Pourquoi un serveur WebSocket doit-il vérifier le header Origin au handshake ? Why must a WebSocket server check the Origin header at the handshake?
C'est le cross-site WebSocket hijacking : le navigateur joint les cookies au handshake quel que soit le site qui l'initie. Seule la validation d'Origin côté serveur (ou une auth par token) bloque l'attaque. Hors navigateur, Origin est falsifiable, mais ce n'est pas le scénario visé. That's cross-site WebSocket hijacking: the browser attaches cookies to the handshake regardless of which site initiates it. Only server-side Origin validation (or token auth) blocks the attack. Outside browsers Origin can be forged, but that's not the targeted scenario.
Jour 8 Day 8 CI/CD & l'automatisation des déploiements CI/CD & deployment automation
Flashcards Flashcards
Quelle est la différence entre continuous delivery et continuous deployment ? What is the difference between continuous delivery and continuous deployment?
Delivery : chaque commit vert produit un artefact déployable, mais un humain décide quand déployer en prod. Deployment : tout commit vert sur la branche principale part en prod automatiquement, sans intervention. La différence tient en une phrase : qui appuie sur le bouton. Delivery: every green commit produces a deployable artifact, but a human decides when to ship to production. Deployment: every green commit on the main branch ships to production automatically, no intervention. The difference fits in one sentence: who presses the button.
Pourquoi met-on le lint et l'analyse statique en premier dans un pipeline ? Why do lint and static analysis come first in a pipeline?
Principe du fail-fast : ce sont les vérifications les moins chères (quelques secondes). Autant échouer en 30 secondes sur un problème de formatage ou de typage qu'attendre 10 minutes de tests pour le découvrir. On ordonne le pipeline du moins cher au plus cher. Fail-fast principle: they are the cheapest checks (a few seconds). Better to fail in 30 seconds on a formatting or typing issue than to wait through 10 minutes of tests to find out. You order the pipeline from cheapest to most expensive.
Qu'est-ce qu'un runner dans GitHub Actions ou GitLab CI ? What is a runner in GitHub Actions or GitLab CI?
La machine qui exécute les jobs : hébergée par la plateforme (VM éphémère et vierge à chaque job) ou auto-hébergée (self-hosted) quand on a besoin de GPU, d'un réseau privé ou de matériel spécifique. Comme l'environnement repart de zéro, le cache est essentiel pour la vitesse. The machine that executes jobs: hosted by the platform (ephemeral, clean VM per job) or self-hosted when you need GPUs, a private network or specific hardware. Since the environment starts from scratch, caching is essential for speed.
Pourquoi ne faut-il pas rebuilder l'artefact entre staging et prod ? Why should you not rebuild the artifact between staging and production?
Deux builds ne sont jamais garantis identiques : une dépendance peut avoir été mise à jour entre-temps, ce qui invalide tout ce qui a été testé en staging. On construit une seule fois (image taguée par SHA de commit) et on promeut ce même artefact immuable d'un environnement à l'autre. Two builds are never guaranteed identical: a dependency may have been updated in between, invalidating everything tested in staging. You build once (image tagged with the commit SHA) and promote that same immutable artifact from one environment to the next.
Rolling, blue-green, canary : résume les trois stratégies de déploiement. Rolling, blue-green, canary: summarize the three deployment strategies.
Rolling : on remplace les instances une par une, zéro interruption mais deux versions coexistent (rétro-compatibilité obligatoire). Blue-green : deux environnements complets, bascule totale du trafic, rollback instantané mais infra doublée. Canary : la nouvelle version reçoit 1-5 % du trafic, on surveille les métriques avant d'élargir — le meilleur contrôle du rayon d'impact. Rolling: replace instances one by one, zero downtime but two versions coexist (backward compatibility required). Blue-green: two full environments, full traffic switch, instant rollback but doubled infrastructure. Canary: the new version gets 1-5% of traffic, you watch metrics before widening — the best blast-radius control.
Qu'est-ce que le trunk-based development et quel rôle jouent les feature flags ? What is trunk-based development and what role do feature flags play?
Tout le monde merge fréquemment sur main via des branches très courtes (moins de 1-2 jours). Le code inachevé part en prod désactivé derrière un feature flag, ce qui sépare le déploiement (le code est sur les serveurs) de la release (il est activé pour les utilisateurs). Couper un flag prend des secondes. Everyone merges to main frequently through very short-lived branches (under 1-2 days). Unfinished code ships to production disabled behind a feature flag, separating deployment (code is on the servers) from release (it's enabled for users). Killing a flag takes seconds.
Pourquoi les migrations de base de données compliquent-elles le rollback ? Why do database migrations complicate rollbacks?
Redéployer l'artefact précédent est trivial, mais une migration qui a supprimé ou transformé des données ne se rejoue pas à l'envers. D'où le pattern expand/contract : ajouter la nouvelle colonne, faire cohabiter les deux versions, puis supprimer l'ancienne colonne dans un déploiement ultérieur — chaque version du code fonctionne avec le schéma d'avant et d'après. Redeploying the previous artifact is trivial, but a migration that dropped or transformed data cannot be replayed backwards. Hence the expand/contract pattern: add the new column, let both versions coexist, then drop the old column in a later deployment — each code version works with the schema before and after.
Comment une plateforme CI protège-t-elle les secrets, et quelle est la limite ? How does a CI platform protect secrets, and what is the limit?
Secrets stockés chiffrés, scopés par environnement, injectés en variables à l'exécution et masqués dans les logs. Limite : le masquage ne reconnaît pas un secret transformé (base64, URL-encodé, concaténé) — un echo de debug peut le faire fuiter. Un secret leaké se révoque, il ne se supprime pas des logs archivés. Secrets stored encrypted, scoped per environment, injected as variables at runtime and masked in logs. Limit: masking doesn't recognize a transformed secret (base64, URL-encoded, concatenated) — a debugging echo can leak it. A leaked secret gets revoked, not deleted from archived logs.
QCM Quiz
Dans une équipe en continuous delivery (pas deployment), que se passe-t-il après un pipeline vert sur main ? In a team doing continuous delivery (not deployment), what happens after a green pipeline on main?
C'est toute la différence avec le continuous deployment : en delivery, chaque commit vert est déployable mais le déploiement prod reste une décision humaine. That's the whole difference with continuous deployment: in delivery, every green commit is deployable but the production deploy remains a human decision.
Quelle stratégie de déploiement limite le mieux le rayon d'impact d'un bug en prod ? Which deployment strategy best limits the blast radius of a production bug?
Le canary n'expose qu'une petite fraction des utilisateurs au bug, le temps de vérifier les métriques. Blue-green offre un rollback instantané mais expose 100 % du trafic dès la bascule. Canary exposes only a small fraction of users to the bug while metrics are checked. Blue-green offers instant rollback but exposes 100% of traffic at switch time.
Pourquoi le cache est-il crucial dans un pipeline CI ? Why is caching crucial in a CI pipeline?
Les runners sont éphémères : node_modules, les couches Docker ou ~/.cargo disparaissent après chaque job. Le cache les restaure et fait la différence entre 3 et 15 minutes de pipeline. Runners are ephemeral: node_modules, Docker layers or ~/.cargo vanish after each job. The cache restores them and makes the difference between a 3- and a 15-minute pipeline.
Un test échoue aléatoirement dans la CI (flaky). Quelle est la bonne réponse d'équipe ? A test fails randomly in CI (flaky). What is the right team response?
Le retry et la relance masquent le symptôme : l'équipe finit par ignorer les échecs et un vrai bug passe. Supprimer le test perd la couverture. On corrige la cause (course condition, dépendance au temps, ordre des tests) ou on quarantaine en attendant. Retries and re-runs mask the symptom: the team ends up ignoring failures and a real bug slips through. Deleting the test loses coverage. Fix the cause (race condition, time dependency, test ordering) or quarantine it meanwhile.
Pourquoi un rolling deployment exige-t-il des migrations DB rétro-compatibles ? Why does a rolling deployment require backward-compatible DB migrations?
Les instances sont remplacées une par une : si la migration supprime une colonne que l'ancienne version lit encore, les instances pas encore mises à jour crashent. D'où expand/contract. Instances are replaced one by one: if the migration drops a column the old version still reads, the not-yet-updated instances crash. Hence expand/contract.
Quel avantage principal apportent les feature flags par rapport à un rollback classique ? What main advantage do feature flags offer over a classic rollback?
Le flag découple release et déploiement : couper un flag est instantané, alors qu'un rollback implique de redéployer un artefact (et de gérer les migrations). Le code derrière un flag doit quand même être testé. Flags decouple release from deployment: killing a flag is instant, while a rollback means redeploying an artifact (and dealing with migrations). Code behind a flag still needs tests.
Jour 7 Day 7 Redis & le caching Redis & caching
Flashcards Flashcards
Pourquoi Redis est-il si rapide ? (réponse complète attendue en entretien) Why is Redis so fast? (full answer expected in an interview)
Quatre raisons : données servies depuis la RAM (aucune I/O disque sur le chemin des requêtes), event loop mono-thread (zéro lock, zéro context switch), structures de données optimisées en C, protocole minimal (RESP). Dire seulement « parce que c'est de la RAM » est insuffisant. Four reasons: data served from RAM (no disk I/O on the request path), single-threaded event loop (zero locks, zero context switches), data structures optimized in C, minimal protocol (RESP). Saying only 'because it's RAM' is not enough.
Quelle structure Redis pour un leaderboard, et avec quelles commandes ? Which Redis structure for a leaderboard, and with which commands?
Le sorted set : chaque membre a un score, maintenu trié en permanence. ZADD pour insérer/mettre à jour un score, ZINCRBY pour l'incrémenter, ZRANGE (ou ZREVRANGE) pour le top N, ZRANK pour la position d'un joueur. Tout est en O(log n). The sorted set: each member has a score, kept permanently ordered. ZADD to insert/update a score, ZINCRBY to increment it, ZRANGE (or ZREVRANGE) for the top N, ZRANK for a player's position. Everything is O(log n).
Décris le pattern cache-aside, avec son défaut principal. Describe the cache-aside pattern, including its main flaw.
Lecture : l'app interroge le cache ; sur un miss, elle lit la DB puis peuple le cache avec un TTL. Écriture : DB puis invalidation de la clé. Défauts : premier accès lent (cache froid) et fenêtre d'incohérence — entre l'écriture DB et l'invalidation, ou pendant le TTL, on sert l'ancienne valeur. Read: the app queries the cache; on a miss, it reads the DB then populates the cache with a TTL. Write: DB then key invalidation. Flaws: slow first access (cold cache) and an inconsistency window — between the DB write and the invalidation, or during the TTL, the old value is served.
Write-through vs write-behind : quel trade-off ? Write-through vs write-behind: what's the trade-off?
Write-through : chaque écriture passe par le cache qui écrit dans la DB de façon synchrone — cache toujours frais mais écritures plus lentes. Write-behind : on écrit dans le cache, flush asynchrone vers la DB — écritures ultra-rapides mais perte possible de données si crash avant le flush. Write-through: every write goes through the cache, which writes to the DB synchronously — cache always fresh but slower writes. Write-behind: you write to the cache, with an asynchronous flush to the DB — ultra-fast writes but possible data loss if a crash occurs before the flush.
Qu'est-ce qu'un cache stampede et quelles sont les parades ? What is a cache stampede and what are the countermeasures?
Une clé chaude expire et des centaines de requêtes font miss simultanément : toutes frappent la DB, qui s'écroule (dogpile). Parades : lock distribué (SET NX EX — un seul client recalcule, les autres attendent ou servent le stale), TTL jitter (TTL ± aléa pour désynchroniser les expirations), recalcul anticipé avant expiration. A hot key expires and hundreds of requests miss simultaneously: they all hit the DB, which collapses (dogpile). Countermeasures: a distributed lock (SET NX EX — a single client recomputes, the others wait or serve stale), TTL jitter (TTL ± random to desynchronize expirations), early recomputation before expiry.
RDB vs AOF : quelles différences ? RDB vs AOF: what are the differences?
RDB : snapshots binaires périodiques (fork + copy-on-write), compacts, restart rapide, mais perte de tout ce qui suit le dernier snapshot. AOF : journal de chaque écriture avec fsync configurable (everysec ≈ 1 s de perte max), fichier plus gros, restart plus lent. On les combine souvent ; un pur cache peut désactiver les deux. RDB: periodic binary snapshots (fork + copy-on-write), compact, fast restart, but everything after the last snapshot is lost. AOF: a journal of every write with configurable fsync (everysec ≈ at most 1 s of loss), bigger file, slower restart. They're often combined; a pure cache can disable both.
Que se passe-t-il quand Redis atteint maxmemory, selon la politique d'éviction ? What happens when Redis reaches maxmemory, depending on the eviction policy?
noeviction (le défaut) : les écritures échouent avec une erreur. allkeys-lru : éviction des clés les moins récemment utilisées, TTL ou pas. volatile-lru : éviction uniquement parmi les clés à TTL. allkeys-lfu : par fréquence d'accès, souvent le meilleur choix pour un vrai cache. noeviction (the default): writes fail with an error. allkeys-lru: evicts the least recently used keys, TTL or not. volatile-lru: evicts only among keys with a TTL. allkeys-lfu: by access frequency, often the best choice for a real cache.
Pourquoi le pub/sub de Redis n'est-il pas une vraie message queue ? Why is Redis pub/sub not a real message queue?
C'est du fire-and-forget : aucune persistance, un abonné déconnecté perd définitivement les messages émis pendant son absence, pas d'acquittement ni de redélivrance. Les streams comblent une partie du manque (consumer groups, acks, relecture) ; pour du routage riche, des DLQ et des garanties fortes, il faut une vraie MQ (RabbitMQ, Kafka). It's fire-and-forget: no persistence, a disconnected subscriber permanently loses messages published while away, no acknowledgment or redelivery. Streams fill part of the gap (consumer groups, acks, replay); for rich routing, DLQs and strong guarantees, you need a real MQ (RabbitMQ, Kafka).
QCM Quiz
Un développeur lance `KEYS *` sur un Redis de production contenant 50 millions de clés. Conséquence ? A developer runs `KEYS *` on a production Redis holding 50 million keys. Consequence?
L'exécution des commandes est mono-thread : une commande O(n) sur 50 M de clés monopolise l'event loop et fige tout le serveur. En prod, on itère avec SCAN, qui parcourt par petits lots sans bloquer. Command execution is single-threaded: an O(n) command over 50M keys monopolizes the event loop and freezes the whole server. In production, iterate with SCAN, which walks in small batches without blocking.
Quelle structure Redis pour un rate limiter en fenêtre glissante (100 requêtes / 60 s) ? Which Redis structure for a sliding-window rate limiter (100 requests / 60 s)?
Le sorted set scoré par timestamp permet de purger les entrées hors fenêtre (ZREMRANGEBYSCORE) puis de compter ce qui reste (ZCARD) — le tout idéalement dans un script Lua pour l'atomicité. INCR+EXPIRE ne donne qu'une fenêtre fixe. A sorted set scored by timestamp lets you purge out-of-window entries (ZREMRANGEBYSCORE) then count what remains (ZCARD) — ideally inside a Lua script for atomicity. INCR+EXPIRE only gives a fixed window.
Un cache Redis sans TTL atteint maxmemory avec la politique par défaut. Que se passe-t-il ? A Redis cache without TTLs reaches maxmemory with the default policy. What happens?
Contrairement à l'intuition, Redis n'évince rien par défaut : noeviction fait échouer les écritures une fois la mémoire pleine. Pour un cache, il faut configurer explicitement allkeys-lru ou allkeys-lfu — et mettre des TTL. Counter-intuitively, Redis evicts nothing by default: noeviction makes writes fail once memory is full. For a cache, you must explicitly configure allkeys-lru or allkeys-lfu — and set TTLs.
À quoi sert le « TTL jitter » (TTL ± aléa) sur les clés d'un cache ? What is "TTL jitter" (TTL ± random) on cache keys for?
Des clés remplies en masse (déploiement, warm-up) avec le même TTL expirent en même temps : vague de miss synchronisée sur la DB. Un aléa de ±10-20 % étale les expirations dans le temps. Keys populated in bulk (deploy, warm-up) with the same TTL expire at the same time: a synchronized wave of misses hits the DB. A ±10-20% random offset spreads expirations over time.
Comment supprimer un hash de plusieurs millions de champs sans figer Redis ? How do you delete a hash with several million fields without freezing Redis?
DEL sur une big key libère la mémoire de façon synchrone dans l'event loop : tout le serveur attend. UNLINK détache la clé immédiatement et libère la mémoire en arrière-plan. FLUSHDB viderait toute la base. DEL on a big key reclaims memory synchronously inside the event loop: the whole server waits. UNLINK detaches the key immediately and frees memory in the background. FLUSHDB would wipe the entire database.
Redis persiste en RDB avec un snapshot toutes les 5 minutes, sans AOF. Le serveur crashe. Que perd-on ? Redis persists with RDB snapshots every 5 minutes, no AOF. The server crashes. What is lost?
RDB est un instantané périodique : tout ce qui suit le dernier snapshot disparaît au crash. C'est l'AOF (fsync everysec) qui borne la perte à ~1 s. D'où le combo RDB + AOF quand les données comptent — ou aucun des deux pour un pur cache. RDB is a periodic snapshot: everything after the last one vanishes on a crash. AOF (fsync everysec) is what bounds the loss to ~1 s. Hence the RDB + AOF combo when data matters — or neither for a pure cache.
Jour 6 Day 6 SQL vs NoSQL SQL vs NoSQL
Flashcards Flashcards
Que signifie ACID ? Illustre avec un virement bancaire. What does ACID stand for? Illustrate with a bank transfer.
Atomicity : débit et crédit passent ensemble ou pas du tout. Consistency : les contraintes (solde, clés étrangères) restent vraies. Isolation : deux virements concurrents ne se voient pas à moitié faits. Durability : après commit, un crash ne perd rien (write-ahead log). Atomicity: debit and credit happen together or not at all. Consistency: constraints (balance, foreign keys) remain true. Isolation: two concurrent transfers don't see each other half-done. Durability: after commit, a crash loses nothing (write-ahead log).
Cite les quatre familles NoSQL avec un exemple chacune. Name the four NoSQL families with one example each.
Document (MongoDB) : JSON imbriqués, agrégats dénormalisés. Clé-valeur (Redis, DynamoDB) : GET/PUT par clé, latence minimale. Colonnes larges (Cassandra) : écritures massives distribuées, modélisation par requête. Graphe (Neo4j) : nœuds et relations de première classe, traversées efficaces. Document (MongoDB): nested JSON, denormalized aggregates. Key-value (Redis, DynamoDB): GET/PUT by key, minimal latency. Wide-column (Cassandra): massive distributed writes, query-driven modeling. Graph (Neo4j): first-class nodes and relationships, efficient traversals.
Énonce correctement le théorème CAP. State the CAP theorem correctly.
Dans un système distribué, PENDANT une partition réseau (P, subie, pas choisie), il faut trancher entre cohérence (refuser de répondre plutôt que répondre faux) et disponibilité (répondre au risque de diverger). Hors partition, le vrai trade-off est latence vs cohérence (PACELC). CAP ne s'applique pas à une base mono-nœud. In a distributed system, DURING a network partition (P, endured, not chosen), you must choose between consistency (refusing to answer rather than answering wrong) and availability (answering at the risk of diverging). Outside a partition, the real trade-off is latency vs consistency (PACELC). CAP doesn't apply to a single-node database.
Qu'est-ce que la cohérence éventuelle (eventual consistency) ? What is eventual consistency?
Les répliques convergent vers la même valeur « à terme » : entre-temps, une lecture peut renvoyer une donnée périmée. Des garanties intermédiaires existent (read-your-writes, cohérence de session), et certains systèmes règlent la cohérence par requête (Cassandra : ONE vs QUORUM). Replicas converge to the same value 'eventually': in the meantime, a read can return stale data. Intermediate guarantees exist (read-your-writes, session consistency), and some systems tune consistency per request (Cassandra: ONE vs QUORUM).
Quelle différence entre réplication et sharding ? What's the difference between replication and sharding?
Réplication : copier les mêmes données sur plusieurs nœuds (leader-follower) → scale les lectures, tolère les pannes ; attention au replica lag. Sharding : partitionner des données différentes sur plusieurs nœuds selon une shard key → scale aussi les écritures ; mauvaise clé = hot shard, et les requêtes cross-shard coûtent cher. Replication: copying the same data to several nodes (leader-follower) → scales reads, tolerates failures; beware of replica lag. Sharding: partitioning different data across nodes according to a shard key → also scales writes; a bad key = hot shard, and cross-shard queries are expensive.
Dans quels cas un index B-tree ne sert-il à rien ? In which cases is a B-tree index useless?
Colonne à faible sélectivité (booléen : le planner préfère un scan complet), fonction appliquée à la colonne (lower(email) sans index d'expression), LIKE avec wildcard en tête ('%foo'), colonnes hors du préfixe d'un index composite, table minuscule. Vérifier avec EXPLAIN ANALYZE. Low-selectivity column (a boolean: the planner prefers a full scan), a function applied to the column (lower(email) without an expression index), LIKE with a leading wildcard ('%foo'), columns outside a composite index's prefix, a tiny table. Check with EXPLAIN ANALYZE.
Qu'est-ce que le problème N+1 et comment le corriger ? What is the N+1 problem and how do you fix it?
L'ORM charge une liste (1 requête) puis, en lazy loading, exécute 1 requête par élément pour la relation accédée dans une boucle : 1+N requêtes, page lente, log rempli de requêtes identiques. Correction : eager loading (JOIN FETCH, include, select_related/prefetch_related). The ORM loads a list (1 query) then, via lazy loading, runs 1 query per item for the relation accessed in a loop: 1+N queries, slow page, log full of identical queries. Fix: eager loading (JOIN FETCH, include, select_related/prefetch_related).
Pourquoi Postgres + JSONB est-il souvent la réponse pragmatique au débat SQL vs NoSQL ? Why is Postgres + JSONB often the pragmatic answer to the SQL vs NoSQL debate?
JSONB stocke du JSON binaire indexable (GIN) et requêtable dans un moteur ACID : on garde les colonnes relationnelles et les contraintes pour le structuré, et la flexibilité documentaire pour la partie variable — sans ajouter une deuxième base à opérer. JSONB stores binary JSON that is indexable (GIN) and queryable inside an ACID engine: you keep relational columns and constraints for the structured part, and document-style flexibility for the variable part — without adding a second database to operate.
QCM Quiz
Un virement débite un compte et en crédite un autre : soit les deux opérations passent, soit aucune. Quelle propriété ACID est en jeu ? A transfer debits one account and credits another: either both operations happen, or neither. Which ACID property is at play?
Tout ou rien = atomicité. La cohérence porte sur les contraintes, l'isolation sur la concurrence, la durabilité sur la survie au crash après commit. All or nothing = atomicity. Consistency is about constraints, isolation about concurrency, durability about surviving a crash after commit.
Pendant une partition réseau, que fait un système qui privilégie la disponibilité (AP) ? During a network partition, what does a system favoring availability (AP) do?
AP = rester disponible pendant la partition, quitte à diverger, puis converger après (cohérence éventuelle). Refuser de répondre serait le choix CP. « AP » ne signifie pas perdre des données. AP = staying available during the partition, even if it diverges, then converging afterwards (eventual consistency). Refusing to answer would be the CP choice. AP does not mean losing data.
Quel type de base est le plus adapté pour « les amis des amis de mes amis qui aiment le même jeu » ? Which database type fits best for 'friends of friends of my friends who like the same game'?
Une traversée à 3 niveaux avec filtre est le cas d'école du graphe : les relations sont des citoyens de première classe. En SQL, ce serait une cascade de self-joins de plus en plus coûteuse. A 3-level traversal with a filter is the textbook graph case: relationships are first-class citizens. In SQL, it would be an increasingly expensive cascade of self-joins.
La requête `WHERE lower(email) = 'a@b.fr'` est lente malgré un index sur `email`. Pourquoi ? The query `WHERE lower(email) = 'a@b.fr'` is slow despite an index on `email`. Why?
L'index B-tree stocke les valeurs de `email`, pas de `lower(email)` : le moteur ne peut pas s'en servir. Solution : `CREATE INDEX ON users (lower(email))` — ou une colonne citext. The B-tree index stores values of `email`, not `lower(email)`: the engine can't use it. Solution: `CREATE INDEX ON users (lower(email))` — or a citext column.
Une page affiche 50 articles avec leur auteur ; le log montre 51 requêtes SQL. Quelle est la bonne correction ? A page displays 50 articles with their author; the log shows 51 SQL queries. What is the right fix?
C'est le problème N+1 : le lazy loading de l'ORM déclenche une requête par article. L'eager loading ramène tout en 1-2 requêtes. L'index n'aide pas (les requêtes sont déjà rapides individuellement) et le cache masquerait le problème. This is the N+1 problem: the ORM's lazy loading fires one query per article. Eager loading brings everything back in 1-2 queries. An index doesn't help (each query is already fast individually) and caching would only mask the problem.
Un utilisateur modifie son profil, recharge la page et voit l'ancienne version pendant quelques secondes. Cause la plus probable dans une architecture leader-follower ? A user edits their profile, reloads the page and sees the old version for a few seconds. Most likely cause in a leader-follower architecture?
L'écriture va au leader, la lecture part sur un follower pas encore synchronisé : c'est le replica lag. La garantie qui manque s'appelle read-your-writes (ex. lire depuis le leader juste après une écriture). CAP n'interdit rien de tel. The write goes to the leader, the read hits a follower not yet caught up: that's replica lag. The missing guarantee is called read-your-writes (e.g. read from the leader right after a write). CAP forbids no such thing.
Jour 5 Day 5 OAuth 2.0, OIDC & JWT OAuth 2.0, OIDC & JWT
Flashcards Flashcards
Quelle est la différence entre authentification et autorisation, et où se placent OAuth 2.0 et OIDC ? What is the difference between authentication and authorization, and where do OAuth 2.0 and OIDC fit?
L'authentification prouve l'identité (login, MFA) ; l'autorisation détermine les droits. OAuth 2.0 est un framework d'autorisation déléguée : il ne dit pas qui est l'utilisateur. C'est OIDC qui ajoute la couche d'identité (id_token, endpoint /userinfo) au-dessus d'OAuth. Authentication proves identity (login, MFA); authorization determines rights. OAuth 2.0 is a delegated authorization framework: it doesn't say who the user is. OIDC is what adds the identity layer (id_token, /userinfo endpoint) on top of OAuth.
De quoi est composé un JWT ? What is a JWT made of?
Trois parties encodées en base64url, séparées par des points : header (algorithme de signature), payload (claims : sub, iss, aud, exp, iat + claims métier), signature calculée sur les deux premières. Le token est signé mais PAS chiffré : lisible par tous, infalsifiable sans la clé. Three base64url-encoded parts separated by dots: header (signing algorithm), payload (claims: sub, iss, aud, exp, iat + business claims), and a signature computed over the first two. The token is signed but NOT encrypted: anyone can read it, nobody can forge it without the key.
HS256 vs RS256 : quelle différence et quand choisir l'un ou l'autre ? HS256 vs RS256: what's the difference and when do you pick one over the other?
HS256 = HMAC symétrique : le même secret signe et vérifie, donc tout service qui vérifie peut aussi forger. RS256 = RSA asymétrique : la clé privée signe, la clé publique (publiée via JWKS) vérifie. En microservices, RS256 : les services valident les tokens sans jamais détenir la clé de signature. HS256 = symmetric HMAC: the same secret signs and verifies, so any verifying service can also forge. RS256 = asymmetric RSA: the private key signs, the public key (published via JWKS) verifies. In microservices, RS256: services validate tokens without ever holding the signing key.
Pourquoi un JWT est-il difficile à révoquer, et quelle est la parade standard ? Why is a JWT hard to revoke, and what is the standard countermeasure?
Il est auto-porteur : valide jusqu'à son exp, sans consultation du serveur — un logout ne l'invalide pas. Parade : access token court (5-15 min) + refresh token long stocké côté serveur, donc révocable, avec rotation (chaque usage émet un nouveau refresh token, la réutilisation d'un ancien signale un vol). It's self-contained: valid until its exp without asking the server — a logout doesn't invalidate it. Countermeasure: short-lived access token (5-15 min) + long-lived refresh token stored server-side, hence revocable, with rotation (each use issues a new refresh token; reusing an old one signals theft).
Qu'est-ce que PKCE et contre quoi protège-t-il ? What is PKCE and what does it protect against?
Une extension du flow authorization code : le client génère un code_verifier aléatoire, envoie son hash SHA-256 (code_challenge) au début, et présente le verifier à l'échange du code. Un code intercepté est donc inexploitable. Conçu pour les clients publics (mobile, SPA) sans client_secret ; recommandé partout, obligatoire en OAuth 2.1. An extension of the authorization code flow: the client generates a random code_verifier, sends its SHA-256 hash (code_challenge) upfront, and presents the verifier when exchanging the code. An intercepted code is therefore unusable. Designed for public clients (mobile, SPA) without a client_secret; recommended everywhere, mandatory in OAuth 2.1.
Quelle différence entre l'access token et l'id_token d'OIDC ? What's the difference between the access token and OIDC's id_token?
L'access token sert à appeler l'API (resource server) : c'est de l'autorisation, son contenu est destiné à l'API. L'id_token est un JWT destiné au client, qui décrit QUI est connecté (claims sub, email, name…) : c'est de l'authentification. Ne jamais utiliser l'un à la place de l'autre. The access token is for calling the API (resource server): it's authorization, and its content is meant for the API. The id_token is a JWT meant for the client, describing WHO is logged in (sub, email, name claims…): that's authentication. Never use one in place of the other.
localStorage vs cookie httpOnly pour stocker un token : quels risques respectifs ? localStorage vs httpOnly cookie for storing a token: what are the respective risks?
localStorage est lisible par tout JS de la page : une XSS exfiltre le token. Un cookie httpOnly + Secure + SameSite est invisible pour JS (protégé XSS) mais envoyé automatiquement : surface CSRF, atténuée par SameSite=Lax/Strict et un token anti-CSRF. Pattern robuste : access token en mémoire + refresh token en cookie httpOnly. localStorage is readable by any JS on the page: an XSS exfiltrates the token. An httpOnly + Secure + SameSite cookie is invisible to JS (XSS-safe) but sent automatically: CSRF surface, mitigated by SameSite=Lax/Strict and an anti-CSRF token. Robust pattern: access token in memory + refresh token in an httpOnly cookie.
Que doit vérifier le serveur quand il reçoit un JWT ? What must the server check when it receives a JWT?
La signature avec l'algorithme ATTENDU (configuré côté serveur, jamais lu aveuglément dans le header), puis les claims : exp (avec une tolérance de clock skew), iss (bon émetteur), aud (token bien destiné à ce service), et les scopes/rôles pour l'autorisation. Le tout via une lib éprouvée, pas de crypto maison. The signature with the EXPECTED algorithm (configured server-side, never blindly read from the header), then the claims: exp (with clock-skew tolerance), iss (right issuer), aud (token really meant for this service), and scopes/roles for authorization. All through a battle-tested library, no home-made crypto.
QCM Quiz
Que garantit la signature d'un JWT ? What does a JWT's signature guarantee?
La signature prouve que le token n'a pas été modifié et qu'il vient bien du détenteur de la clé. Le payload reste lisible par tous : base64url n'est pas du chiffrement. The signature proves the token wasn't modified and really comes from the key holder. The payload stays readable by anyone: base64url is not encryption.
Quel flow OAuth 2.0 pour un batch nocturne qui appelle une API interne sans utilisateur ? Which OAuth 2.0 flow for a nightly batch calling an internal API with no user involved?
Sans resource owner, pas de redirection ni de consentement : le client s'authentifie directement avec ses credentials (client credentials). Authorization code implique un utilisateur ; implicit et ROPC sont dépréciés. With no resource owner, there's no redirect or consent: the client authenticates directly with its credentials (client credentials). Authorization code involves a user; implicit and ROPC are deprecated.
En quoi consiste l'attaque par « confusion d'algorithme » sur les JWT ? What is the JWT "algorithm confusion" attack?
Si la lib lit l'alg du header sans le vérifier, un attaquant forge un token HS256 signé avec la clé publique RSA (connue de tous) : le serveur, croyant faire du HMAC, valide. Parade : imposer l'algorithme attendu côté serveur. If the library reads the header's alg without enforcing it, an attacker forges an HS256 token signed with the (publicly known) RSA public key: the server, believing it's doing HMAC, validates it. Defense: enforce the expected algorithm server-side.
Pourquoi donne-t-on une durée de vie courte (5-15 min) aux access tokens JWT ? Why are JWT access tokens given a short lifetime (5-15 min)?
Le token étant valide jusqu'à exp sans consultation du serveur, on borne le risque par une durée courte ; le refresh token, révocable côté serveur, renouvelle la session sans re-login. Since the token is valid until exp without asking the server, the risk is bounded by a short lifetime; the refresh token, revocable server-side, renews the session without re-login.
Contre quoi un cookie httpOnly protège-t-il le token qu'il contient ? What does an httpOnly cookie protect its token against?
httpOnly rend le cookie invisible à document.cookie et à tout JS : une XSS ne peut plus l'exfiltrer. Mais le cookie part automatiquement avec les requêtes → il faut traiter le CSRF séparément (SameSite, token anti-CSRF). L'interception réseau, c'est le rôle de Secure/TLS. httpOnly makes the cookie invisible to document.cookie and any JS: an XSS can no longer exfiltrate it. But the cookie is sent automatically with requests → CSRF must be handled separately (SameSite, anti-CSRF token). Network interception is the job of Secure/TLS.
Dans une intégration « Login with Google » (OIDC), quel token le front doit-il envoyer à votre API backend pour agir au nom de l'utilisateur ? In a "Login with Google" (OIDC) integration, which token should the front end send to your backend API to act on the user's behalf?
L'access token est fait pour être présenté à l'API (resource server). L'id_token est destiné au client pour savoir qui est connecté ; le code ne sert qu'à l'échange initial ; le refresh token ne quitte jamais le stockage sécurisé du client. The access token is made to be presented to the API (resource server). The id_token is meant for the client to know who's logged in; the code is only for the initial exchange; the refresh token never leaves the client's secure storage.
Jour 4 Day 4 RabbitMQ & les files de messages RabbitMQ & message queues
Flashcards Flashcards
Quels sont les trois bénéfices principaux d'une message queue entre deux services ? What are the three main benefits of a message queue between two services?
Découplage (le producteur ignore qui consomme, le consommateur peut être down sans casser le producteur), lissage de charge (un pic s'empile dans la queue au lieu d'écrouler le consommateur), résilience (le message persiste jusqu'à son traitement, avec retry natif via la redélivrance). Decoupling (the producer doesn't know who consumes, the consumer can be down without breaking the producer), load smoothing (a spike piles up in the queue instead of crushing the consumer), resilience (the message persists until processed, with native retry through redelivery).
Dans le modèle AMQP, où un producteur publie-t-il ses messages ? In the AMQP model, where does a producer publish its messages?
Jamais directement dans une queue : dans un exchange, avec une routing key. L'exchange route ensuite le message vers zéro, une ou plusieurs queues selon ses bindings (les règles de liaison exchange → queue). Never directly to a queue: to an exchange, with a routing key. The exchange then routes the message to zero, one or several queues according to its bindings (the exchange → queue link rules).
Quels sont les trois types d'exchange principaux et leur logique de routage ? What are the three main exchange types and their routing logic?
Direct : correspondance exacte entre routing key et binding. Fanout : diffusion à toutes les queues liées, routing key ignorée (pub/sub pur). Topic : pattern matching sur la clé segmentée par des points, avec `*` = exactement un mot et `#` = zéro ou plusieurs mots. Direct: exact match between routing key and binding. Fanout: broadcast to all bound queues, routing key ignored (pure pub/sub). Topic: pattern matching on the dot-separated key, with `*` = exactly one word and `#` = zero or more words.
Que se passe-t-il si un consumer meurt avant d'avoir acquitté un message ? What happens if a consumer dies before acknowledging a message?
Le broker détecte la fermeture du canal et remet le message en queue avec le flag redelivered ; un autre consumer le reprend. Rien n'est perdu (at-least-once), mais le traitement a pu être partiellement appliqué — d'où l'exigence d'idempotence côté consumer. The broker detects the channel closing and requeues the message with the redelivered flag; another consumer picks it up. Nothing is lost (at-least-once), but processing may have been partially applied — hence the idempotence requirement on the consumer side.
At-most-once vs at-least-once : quelle différence et quel réglage les produit ? At-most-once vs at-least-once: what's the difference and which setting produces each?
Auto-ack = at-most-once : le message est considéré livré dès l'envoi, un crash du consumer le perd. Ack manuel après traitement = at-least-once : rien n'est perdu, mais un crash entre traitement et ack produit un doublon. L'exactly-once de bout en bout n'existe pas sans coopération applicative. Auto-ack = at-most-once: the message is considered delivered as soon as it's sent, a consumer crash loses it. Manual ack after processing = at-least-once: nothing is lost, but a crash between processing and ack produces a duplicate. End-to-end exactly-once doesn't exist without application-level cooperation.
Pourquoi et comment rendre un consumer idempotent ? Why and how do you make a consumer idempotent?
Parce que le at-least-once produit des doublons lors des redélivrances. Techniques : déduplication par message id (stocké en base avec contrainte unique, le doublon échoue proprement) ou opérations naturellement idempotentes (upsert, `SET status = 'paid'` plutôt que `balance += x`). Because at-least-once produces duplicates on redeliveries. Techniques: deduplication by message id (stored in the database with a unique constraint, the duplicate fails cleanly) or naturally idempotent operations (upsert, `SET status = 'paid'` rather than `balance += x`).
Qu'est-ce qu'une dead letter queue (DLQ) et pourquoi est-elle indispensable ? What is a dead letter queue (DLQ) and why is it essential?
Une queue vers laquelle un dead-letter exchange (DLX) route les messages rejetés sans requeue, expirés (TTL) ou en dépassement de longueur max. Sans elle, un message empoisonné qui fait crasher le consumer revient en boucle et bloque la queue ; avec elle, on l'isole, on l'inspecte et on le rejoue. A queue to which a dead-letter exchange (DLX) routes messages rejected without requeue, expired (TTL) or overflowing the max length. Without it, a poison message that crashes the consumer loops forever and blocks the queue; with it, you isolate, inspect and replay it.
RabbitMQ vs Kafka : quelle différence de modèle et quand choisir l'un ou l'autre ? RabbitMQ vs Kafka: what's the model difference and when do you choose which?
Rabbit est une queue : broker intelligent qui route finement, message supprimé après ack — idéal pour la distribution de tâches, le routage riche, la latence faible. Kafka est un log append-only : les messages restent, chaque consumer avance son offset — replay possible, lectures indépendantes du même flux, très haut débit via les partitions. Event streaming → Kafka ; task queues → Rabbit. Rabbit is a queue: a smart broker with fine-grained routing, messages deleted after ack — ideal for task distribution, rich routing, low latency. Kafka is an append-only log: messages stay, each consumer advances its offset — replay possible, independent reads of the same stream, very high throughput via partitions. Event streaming → Kafka; task queues → Rabbit.
QCM Quiz
Dans RabbitMQ, vers quoi un producteur publie-t-il un message ? In RabbitMQ, what does a producer publish a message to?
En AMQP, le producteur ne connaît que l'exchange et la routing key ; le routage vers les queues est déclaré par les bindings. Les partitions par hash de clé, c'est le modèle Kafka. In AMQP, the producer only knows the exchange and the routing key; routing to queues is declared through bindings. Partitions chosen by key hash are the Kafka model.
Avec un topic exchange, quelle routing key matche le binding `logs.*.error` ? With a topic exchange, which routing key matches the binding `logs.*.error`?
`*` matche exactement un mot entre deux points : `logs.api.error` colle. `logs.api.db.error` a deux mots au milieu (il faudrait `#`), `logs.error` n'en a aucun, et `api.logs.error` ne commence pas par `logs`. `*` matches exactly one word between dots: `logs.api.error` fits. `logs.api.db.error` has two words in the middle (you'd need `#`), `logs.error` has none, and `api.logs.error` doesn't start with `logs`.
Quelle garantie de livraison obtient-on avec l'auto-ack activé ? Which delivery guarantee do you get with auto-ack enabled?
En auto-ack, le message est considéré livré dès l'envoi au consumer : s'il crashe en plein traitement, le broker ne redélivre rien. L'at-least-once exige l'ack manuel après traitement. With auto-ack, the message is considered delivered as soon as it's sent to the consumer: if it crashes mid-processing, the broker redelivers nothing. At-least-once requires a manual ack after processing.
Quels messages sont routés vers un dead-letter exchange (DLX) ? Which messages are routed to a dead-letter exchange (DLX)?
Trois causes de dead-lettering : reject/nack avec requeue=false, expiration TTL, dépassement de max-length. Le broker n'inspecte jamais le contenu du message — un JSON invalide ne l'intéresse pas. Three causes of dead-lettering: reject/nack with requeue=false, TTL expiry, max-length overflow. The broker never inspects message content — invalid JSON means nothing to it.
À quoi sert le prefetch (QoS) côté consumer ? What is prefetch (QoS) for on the consumer side?
Sans prefetch, le broker déverse tous les messages disponibles sur le premier consumer connecté, même s'il est lent. `prefetch=N` borne les messages en vol non acquittés : les consumers rapides en reçoivent plus. L'ordre entre consumers, lui, n'est jamais garanti. Without prefetch, the broker dumps every available message on the first connected consumer, even a slow one. `prefetch=N` caps unacked in-flight messages: fast consumers receive more. Order across consumers is never guaranteed.
Quelle différence fondamentale entre le modèle de Kafka et celui de RabbitMQ ? What is the fundamental difference between Kafka's model and RabbitMQ's?
Dans Kafka, les messages restent dans le log (rétention configurable) et chaque consumer group lit à son propre offset — d'où le replay et les lectures indépendantes. Dans Rabbit, un message acquitté est supprimé de la queue. Les deux sont asynchrones et offrent des garanties de livraison. In Kafka, messages stay in the log (configurable retention) and each consumer group reads at its own offset — hence replay and independent reads. In Rabbit, an acknowledged message is deleted from the queue. Both are asynchronous and offer delivery guarantees.
Jour 3 Day 3 REST vs GraphQL vs gRPC REST vs GraphQL vs gRPC
Flashcards Flashcards
Quelles sont les principales contraintes de REST ? What are REST's main constraints?
Ressources identifiées par des URLs, interface uniforme HTTP (verbes GET/POST/PUT/PATCH/DELETE + codes de statut), statelessness (chaque requête porte tout son contexte), réponses cacheables. HATEOAS (liens vers les actions possibles dans les réponses) complète le modèle « pur », rarement implémenté. Resources identified by URLs, the uniform HTTP interface (GET/POST/PUT/PATCH/DELETE verbs + status codes), statelessness (each request carries its full context), cacheable responses. HATEOAS (links to possible actions inside responses) completes the "pure" model, rarely implemented.
Quelle différence entre un 401 et un 403 ? What's the difference between a 401 and a 403?
401 Unauthorized = non authentifié : le serveur ne sait pas qui vous êtes (token absent, invalide ou expiré). 403 Forbidden = authentifié mais non autorisé : identité connue, droits insuffisants. Réessayer avec les mêmes credentials ne changera rien à un 403. 401 Unauthorized = not authenticated: the server doesn't know who you are (missing, invalid or expired token). 403 Forbidden = authenticated but not authorized: known identity, insufficient rights. Retrying with the same credentials won't change a 403.
Qu'appelle-t-on over-fetching et under-fetching, et comment GraphQL les résout-il ? What are over-fetching and under-fetching, and how does GraphQL solve them?
Over-fetching : l'API renvoie plus de champs que nécessaire (40 champs pour en afficher 3). Under-fetching : un écran nécessite plusieurs appels enchaînés. GraphQL laisse le client décrire exactement les champs voulus, relations comprises, en un seul aller-retour sur un endpoint unique. Over-fetching: the API returns more fields than needed (40 fields to display 3). Under-fetching: one screen requires several chained calls. GraphQL lets the client describe exactly the fields it wants, relations included, in a single round trip on a single endpoint.
Qu'est-ce que le problème N+1 en GraphQL et comment le résout-on ? What is the N+1 problem in GraphQL and how is it solved?
Avec des resolvers naïfs, une liste de N éléments dont chacun résout une relation (ex. l'auteur d'un post) déclenche 1 requête pour la liste + N requêtes pour les relations. Solution : le batching avec le pattern DataLoader, qui regroupe les chargements d'un même tick en une seule requête (WHERE id IN (...)) et déduplique. With naive resolvers, a list of N items each resolving a relation (e.g. a post's author) triggers 1 query for the list + N queries for the relations. Solution: batching with the DataLoader pattern, which groups same-tick loads into a single query (WHERE id IN (...)) and deduplicates.
Pourquoi gRPC est-il plus performant que REST/JSON ? Why is gRPC faster than REST/JSON?
Sérialisation protobuf binaire (champs numérotés, payloads compacts, parsing rapide), transport HTTP/2 (multiplexage sur une connexion persistante, compression d'en-têtes), code client/serveur généré depuis le contrat .proto, et streaming natif (server, client, bidirectionnel). Binary protobuf serialization (numbered fields, compact payloads, fast parsing), HTTP/2 transport (multiplexing over a persistent connection, header compression), client/server code generated from the .proto contract, and native streaming (server, client, bidirectional).
Qu'est-ce que l'idempotence et quels verbes HTTP le sont ? What is idempotence and which HTTP verbs are idempotent?
Une opération est idempotente si la rejouer produit le même état final qu'une seule exécution. GET, PUT et DELETE sont idempotents ; POST ne l'est pas. C'est crucial pour les retries : rejouer un POST de paiement sans idempotency key peut débiter deux fois. An operation is idempotent if replaying it produces the same final state as a single execution. GET, PUT and DELETE are idempotent; POST is not. This is crucial for retries: replaying a payment POST without an idempotency key can charge twice.
Pagination offset vs cursor : quelle différence et laquelle préférer ? Offset vs cursor pagination: what's the difference and which should you prefer?
Offset (`?page=3&limit=20`) : simple, mais les éléments se décalent si la liste change entre deux pages, et OFFSET profond force la base à parcourir puis jeter des milliers de lignes. Cursor : un pointeur opaque après le dernier élément vu — stable et performant. À préférer par défaut pour les listes qui bougent. Offset (`?page=3&limit=20`): simple, but items shift if the list changes between pages, and a deep OFFSET forces the database to scan then discard thousands of rows. Cursor: an opaque pointer after the last seen item — stable and fast. Prefer it by default for lists that change.
REST, GraphQL ou gRPC : quelle grille de choix rapide ? REST, GraphQL or gRPC: what's the quick decision grid?
API publique → REST (universel, cacheable, testable au curl). BFF ou client mobile agrégeant plusieurs sources → GraphQL (composition des données en un aller-retour). Microservices internes à fort trafic → gRPC (contrats stricts, perfs, streaming ; mais navigateur seulement via grpc-web + proxy). Public API → REST (universal, cacheable, curl-testable). BFF or mobile client aggregating several sources → GraphQL (data composition in one round trip). High-traffic internal microservices → gRPC (strict contracts, performance, streaming; but browsers only via grpc-web + proxy).
QCM Quiz
Quel verbe HTTP n'est PAS idempotent ? Which HTTP verb is NOT idempotent?
Deux POST identiques créent deux ressources. Rejouer un PUT (remplacement complet), un DELETE ou un GET produit le même état final — c'est ce qui rend leurs retries sûrs. Two identical POSTs create two resources. Replaying a PUT (full replacement), a DELETE or a GET produces the same final state — which is what makes their retries safe.
Une app mobile n'affiche que 3 champs mais l'API REST en renvoie 40. Comment s'appelle ce problème ? A mobile app displays only 3 fields but the REST API returns 40. What is this problem called?
Over-fetching = recevoir plus de données que nécessaire. Under-fetching = devoir enchaîner plusieurs appels pour un écran. GraphQL résout les deux en laissant le client sélectionner ses champs. Over-fetching = receiving more data than needed. Under-fetching = having to chain several calls for one screen. GraphQL solves both by letting the client select its fields.
Sur quoi repose gRPC pour la sérialisation et le transport ? What does gRPC rely on for serialization and transport?
gRPC sérialise en protobuf (binaire, compact, typé) et transporte sur HTTP/2, ce qui apporte multiplexage, compression d'en-têtes et streaming bidirectionnel. gRPC serializes with protobuf (binary, compact, typed) and transports over HTTP/2, which brings multiplexing, header compression and bidirectional streaming.
En protobuf, quelle règle garantit la compatibilité ascendante d'un message ? In protobuf, which rule guarantees a message's backward compatibility?
Le wire format protobuf identifie les champs par leur numéro, pas par leur nom. Réutiliser un numéro pour un autre champ corrompt silencieusement le décodage des anciens messages ; on ajoute des numéros, on ne recycle jamais (mot-clé reserved). The protobuf wire format identifies fields by number, not name. Reusing a number for another field silently corrupts decoding of old messages; you add numbers, never recycle them (the reserved keyword).
Une requête arrive avec un token expiré. Quel code de statut renvoyer ? A request arrives with an expired token. Which status code should you return?
Token expiré = le serveur ne peut plus authentifier le client → 401 (avec en général un header WWW-Authenticate). 403 signifierait « identité connue mais droits insuffisants ». 419 n'est pas un code standard. Expired token = the server can no longer authenticate the client → 401 (usually with a WWW-Authenticate header). 403 would mean "known identity but insufficient rights". 419 is not a standard code.
Pourquoi le cache HTTP classique fonctionne-t-il mal avec GraphQL ? Why does standard HTTP caching work poorly with GraphQL?
Les caches HTTP (navigateur, CDN) travaillent sur des GET avec des URLs distinctes. En GraphQL, chaque requête est un POST vers /graphql avec un body différent : il faut du caching applicatif (client normalisé type Apollo, persisted queries). HTTP caches (browser, CDN) work on GETs with distinct URLs. In GraphQL, every request is a POST to /graphql with a different body: you need application-level caching (a normalized client like Apollo, persisted queries).
Jour 2 Day 2 Git avancé : rebase, cherry-pick & bisect Advanced Git: rebase, cherry-pick & bisect
Flashcards Flashcards
Qu'est-ce qu'une branche pour Git, concrètement ? What is a branch to Git, concretely?
Un simple pointeur mutable vers un commit : un fichier de 41 octets dans `.git/refs/heads/` contenant un hash. L'historique est le graphe (DAG) des commits ; la branche n'est qu'une étiquette qui avance à chaque commit. D'où des branches instantanées et gratuites. Just a mutable pointer to a commit: a 41-byte file in `.git/refs/heads/` containing a hash. History is the graph (DAG) of commits; the branch is only a label that advances with each commit. Hence instant, free branching.
Quelle est la différence fondamentale entre merge et rebase ? What is the fundamental difference between merge and rebase?
Merge crée un commit de fusion à deux parents et préserve l'historique tel qu'il s'est passé. Rebase rejoue chaque commit de la branche par-dessus la cible : nouveaux commits, nouveaux hashes, historique linéaire mais réécrit. Le résultat du code est le même, l'historique non. Merge creates a two-parent merge commit and preserves history as it happened. Rebase replays each commit of the branch on top of the target: new commits, new hashes, a linear but rewritten history. The resulting code is the same, the history is not.
Que permet le rebase interactif (`git rebase -i`) ? What does interactive rebase (`git rebase -i`) let you do?
Réécrire une série de commits avant de la partager : réordonner, fusionner (`squash`/`fixup`), reformuler (`reword`), modifier (`edit`) ou supprimer (`drop`) des commits. C'est l'outil standard pour nettoyer une branche avant d'ouvrir la PR. Rewrite a series of commits before sharing it: reorder, combine (`squash`/`fixup`), reword (`reword`), amend (`edit`) or delete (`drop`) commits. It's the standard tool for cleaning up a branch before opening the PR.
À quoi sert `git cherry-pick` et quel est son cas d'usage typique ? What is `git cherry-pick` for, and what is its typical use case?
Il rejoue un commit précis sur la branche courante, en créant un nouveau commit (nouveau hash). Cas typique : reporter un hotfix de `main` vers une branche de release. Attention : le même changement existe alors deux fois dans l'historique si les branches sont mergées ensuite. It replays one specific commit onto the current branch, creating a new commit (new hash). Typical case: backporting a hotfix from `main` to a release branch. Beware: the same change then exists twice in history if the branches are later merged.
Comment fonctionne `git bisect` ? How does `git bisect` work?
Recherche dichotomique du commit fautif : on marque un commit `bad` et un commit `good`, Git checkout le commit du milieu, on teste et on répond good/bad, jusqu'à isoler le coupable en log₂(n) étapes (1000 commits ≈ 10 tests). `git bisect run ./script.sh` automatise tout. Binary search for the offending commit: you mark one `bad` and one `good` commit, Git checks out the middle commit, you test and answer good/bad, until the culprit is isolated in log₂(n) steps (1000 commits ≈ 10 tests). `git bisect run ./script.sh` automates the whole thing.
Qu'est-ce que le reflog et pourquoi est-ce un filet de sécurité ? What is the reflog and why is it a safety net?
`git reflog` journalise localement tous les déplacements de HEAD et des branches (~90 jours). Après un rebase raté ou un `reset --hard` malheureux, on retrouve le hash d'avant l'erreur et on restaure avec `git reset --hard HEAD@{n}`. Un commit non référencé n'est perdu qu'après passage du garbage collector. `git reflog` locally journals every move of HEAD and branches (~90 days). After a botched rebase or an unfortunate `reset --hard`, you find the hash from before the mistake and restore with `git reset --hard HEAD@{n}`. An unreferenced commit is only lost once the garbage collector runs.
Quelle est la règle d'or du rebase ? What is the golden rule of rebase?
Ne jamais rebaser des commits déjà poussés et partagés. Le rebase crée de nouveaux hashes : les collègues qui ont basé leur travail sur les anciens commits se retrouvent avec des historiques divergents pénibles à réconcilier. Rebase = uniquement sur ses commits locaux. Never rebase commits that have already been pushed and shared. Rebase creates new hashes: colleagues who based their work on the old commits end up with painfully diverged histories. Rebase = only on your local commits.
`git push --force` vs `--force-with-lease` : quelle différence ? `git push --force` vs `--force-with-lease`: what's the difference?
`--force` écrase la branche distante aveuglément, même si un collègue a poussé entre-temps (travail perdu). `--force-with-lease` échoue si la branche distante a bougé depuis le dernier fetch : même usage (pousser après un rebase), sans le risque. C'est le seul force push acceptable en équipe. `--force` blindly overwrites the remote branch, even if a colleague pushed in the meantime (lost work). `--force-with-lease` fails if the remote branch moved since your last fetch: same use (pushing after a rebase), without the risk. It's the only acceptable force push on a team.
QCM Quiz
Que fait `git rebase main` aux commits de la branche courante ? What does `git rebase main` do to the commits of the current branch?
Le hash d'un commit couvre son contenu, son parent et ses métadonnées : rejouer un commit sur un autre parent crée forcément un nouveau commit. Les anciens restent dans .git/objects, non référencés. A commit's hash covers its content, parent and metadata: replaying a commit on a different parent necessarily creates a new commit. The old ones remain in .git/objects, unreferenced.
Après un `git reset --hard` sur le mauvais commit, comment récupérer son travail commité ? After a `git reset --hard` on the wrong commit, how do you recover your committed work?
Le reflog journalise tous les déplacements de HEAD : `git reset --hard HEAD@{n}` restaure la position d'avant. Seul le travail jamais commité est réellement perdu. Revert, lui, crée un commit inverse — autre usage. The reflog journals every move of HEAD: `git reset --hard HEAD@{n}` restores the previous position. Only work that was never committed is truly lost. Revert creates an inverse commit — a different use case.
Avec `git bisect`, combien de tests faut-il environ pour isoler un bug dans 1000 commits ? With `git bisect`, about how many tests does it take to isolate a bug in 1000 commits?
Bisect fait une recherche dichotomique : log₂(1000) ≈ 10 étapes. C'est tout l'intérêt par rapport à un parcours linéaire de l'historique. Bisect performs a binary search: log₂(1000) ≈ 10 steps. That's the whole point compared to walking the history linearly.
Quelle commande rejoue un commit précis d'une autre branche sur la branche courante ? Which command replays one specific commit from another branch onto the current branch?
cherry-pick applique le diff d'un commit unique et crée un nouveau commit. Merge intègre toute la branche jusqu'à ce commit, rebase rejoue la branche courante ailleurs, checkout ne fait que se déplacer. cherry-pick applies the diff of a single commit and creates a new commit. Merge integrates the whole branch up to that commit, rebase replays the current branch elsewhere, checkout only moves you around.
Pourquoi ne faut-il pas rebaser une branche déjà poussée et utilisée par des collègues ? Why shouldn't you rebase a branch that's already pushed and used by colleagues?
Les collègues ont basé leur travail sur les anciens commits ; après votre rebase (et force push), leurs branches pointent sur un historique qui n'existe plus en amont — réconciliation pénible. Les anciens commits, eux, ne sont pas supprimés immédiatement. Colleagues based their work on the old commits; after your rebase (and force push), their branches point to a history that no longer exists upstream — painful reconciliation. The old commits themselves are not immediately deleted.
À quoi `git pull` est-il équivalent par défaut ? What is `git pull` equivalent to by default?
Par défaut, pull = fetch + merge, d'où les commits de merge parasites quand l'historique local a divergé. `git pull --rebase` (ou `pull.rebase=true`) rejoue vos commits locaux par-dessus le remote à la place. By default, pull = fetch + merge, hence the noisy merge commits when local history has diverged. `git pull --rebase` (or `pull.rebase=true`) replays your local commits on top of the remote instead.
Jour 1 Day 1 Docker & la conteneurisation Docker & containerization
Flashcards Flashcards
Quelle est la différence fondamentale entre un conteneur et une machine virtuelle ? What is the fundamental difference between a container and a virtual machine?
La VM virtualise du matériel et embarque un OS complet avec son propre noyau via un hyperviseur. Le conteneur est un simple processus isolé (namespaces + cgroups) qui partage le noyau de l'hôte : démarrage en millisecondes et overhead de quelques Mo, contre minutes et Go pour la VM. A VM virtualizes hardware and ships a full OS with its own kernel via a hypervisor. A container is just an isolated process (namespaces + cgroups) sharing the host kernel: millisecond startup and a few MB of overhead, versus minutes and GBs for a VM.
Quels mécanismes du noyau Linux rendent les conteneurs possibles ? Which Linux kernel mechanisms make containers possible?
Les namespaces (isolent ce que le processus voit : PID, réseau, montages, hostname…), les cgroups (limitent CPU/RAM/I/O) et un union filesystem comme OverlayFS (couches d'image en lecture seule + couche d'écriture éphémère). Namespaces (isolate what the process sees: PID, network, mounts, hostname…), cgroups (limit CPU/RAM/I/O) and a union filesystem like OverlayFS (read-only image layers + an ephemeral writable layer).
Quelle différence entre une image et un conteneur ? What's the difference between an image and a container?
L'image est le modèle immuable construit depuis un Dockerfile (comme une classe) ; le conteneur est une instance en cours d'exécution de cette image (comme un objet), avec sa couche d'écriture propre et éphémère. The image is the immutable template built from a Dockerfile (like a class); the container is a running instance of that image (like an object), with its own ephemeral writable layer.
Pourquoi et comment persister les données d'une base de données conteneurisée ? Why and how do you persist a containerized database's data?
La couche d'écriture du conteneur disparaît avec lui. On monte donc un volume nommé (ou un bind mount) sur le répertoire de données, ex. `-v pgdata:/var/lib/postgresql/data` : le volume survit aux recréations du conteneur et se sauvegarde indépendamment. The container's writable layer disappears with it. You mount a named volume (or bind mount) on the data directory, e.g. `-v pgdata:/var/lib/postgresql/data`: the volume outlives container recreations and can be backed up independently.
Qu'est-ce qu'un multi-stage build et pourquoi l'utiliser ? What is a multi-stage build and why use it?
Un Dockerfile avec plusieurs `FROM` : on compile dans une image lourde (SDK, outils de build) puis on copie uniquement l'artefact final dans une image runtime minimale. Résultat : image plus petite, plus rapide à distribuer, sans outils de build donc surface d'attaque réduite. A Dockerfile with several `FROM` stages: you compile in a heavy image (SDK, build tools) then copy only the final artifact into a minimal runtime image. Result: smaller image, faster to ship, no build tools inside so a reduced attack surface.
CMD vs ENTRYPOINT : quelle différence ? CMD vs ENTRYPOINT: what's the difference?
`ENTRYPOINT` définit l'exécutable fixe du conteneur ; `CMD` fournit ses arguments par défaut, remplaçables à l'exécution (`docker run image autre-arg`). Combinés : `ENTRYPOINT ["node"]` + `CMD ["server.js"]` lance `node server.js` par défaut. `ENTRYPOINT` sets the container's fixed executable; `CMD` provides its default arguments, overridable at run time (`docker run image other-arg`). Combined: `ENTRYPOINT ["node"]` + `CMD ["server.js"]` runs `node server.js` by default.
Comment deux conteneurs d'une même stack Compose communiquent-ils ? How do two containers in the same Compose stack communicate?
Ils sont placés sur un même réseau bridge dédié et se joignent par leur nom de service via le DNS interne de Docker (ex. `postgres:5432` depuis le conteneur applicatif). Pas besoin de publier les ports sur l'hôte pour la communication interne. They're placed on a dedicated bridge network and reach each other by service name through Docker's internal DNS (e.g. `postgres:5432` from the app container). No need to publish ports on the host for internal communication.
Pourquoi l'ordre des instructions dans un Dockerfile est-il important ? Why does the order of instructions in a Dockerfile matter?
Chaque instruction crée une couche mise en cache ; modifier une instruction invalide toutes les couches suivantes. On place donc les étapes stables en premier (installation des dépendances) et le code source en dernier, pour que `docker build` ne réinstalle pas tout à chaque changement de code. Each instruction creates a cached layer; changing one invalidates all subsequent layers. Put stable steps first (dependency installation) and source code last, so `docker build` doesn't reinstall everything on every code change.
QCM Quiz
Que partagent tous les conteneurs Docker tournant sur un même hôte Linux ? What do all Docker containers running on the same Linux host share?
Les conteneurs partagent le noyau de l'hôte — c'est ce qui les rend légers. Filesystem et espace PID sont isolés par conteneur, et il n'y a pas d'hyperviseur. Containers share the host kernel — that's what makes them lightweight. Filesystem and PID space are isolated per container, and there is no hypervisor.
Où finissent les données écrites dans un conteneur sans volume monté ? Where does data written in a container without a mounted volume end up?
Sans volume, tout va dans la couche d'écriture éphémère du conteneur : elle disparaît avec lui. L'image, elle, reste immuable. Without a volume, everything goes to the container's ephemeral writable layer, which disappears with it. The image itself stays immutable.
Que fait exactement `docker run -p 8080:80 nginx` ? What exactly does `docker run -p 8080:80 nginx` do?
La syntaxe est `-p <port-hôte>:<port-conteneur>`. Attention : par défaut c'est bindé sur 0.0.0.0, donc joignable depuis l'extérieur, en contournant UFW. The syntax is `-p <host-port>:<container-port>`. Careful: it binds to 0.0.0.0 by default, reachable from outside and bypassing UFW.
Quel est le risque principal du tag `latest` en production ? What is the main risk of the `latest` tag in production?
`latest` n'est qu'un tag par défaut que l'éditeur peut réécrire à tout moment : déploiements non reproductibles. En prod, on épingle une version, idéalement un digest. `latest` is just a default tag the publisher can rewrite at any time: non-reproducible deployments. In production, pin a version, ideally a digest.
Dans quel ordre le CLI Docker délègue-t-il l'exécution d'un conteneur ? In what order does the Docker CLI delegate container execution?
Le CLI parle au démon dockerd (API REST), qui délègue à containerd, qui invoque runc (runtime OCI) pour créer le processus isolé. D'où Kubernetes utilisant containerd sans Docker. The CLI talks to the dockerd daemon (REST API), which delegates to containerd, which invokes runc (OCI runtime) to create the isolated process. Hence Kubernetes using containerd without Docker.
Pourquoi copie-t-on package.json et lance-t-on `npm install` AVANT de copier le reste du code dans un Dockerfile Node ? Why copy package.json and run `npm install` BEFORE copying the rest of the code in a Node Dockerfile?
Le cache est invalidé couche par couche : si seul le code change, la couche `npm install` reste en cache et le build est quasi instantané. La taille finale, elle, ne change pas. The cache is invalidated layer by layer: if only the code changes, the `npm install` layer stays cached and the build is nearly instant. Final size is unchanged.