Toutes les formules

Le fichier de révision. Chaque module des guides isole un patron de code canonique — les voici sortis de leurs chapitres, réunis. Cette page n'apprend rien de neuf : elle sert à recroiser, encore et encore, jusqu'à ce que reconnaître devienne un réflexe.

💡 Comment s'en servir

Ne la lis pas d'un bout à l'autre comme un module. Ouvre-la quand tu as dix minutes, descends au hasard, et devant chaque formule pose-toi une seule question : « est-ce que je saurais dire à quoi elle sert et où elle s'emploie ? » Si oui, tu passes. Sinon, le lien à droite te ramène au module qui l'explique.

La reconnaissance vient de la fréquence des rencontres, pas de la durée de chacune. Cinq passages de dix minutes valent mieux qu'une relecture d'une heure.

🧵 Le fil qui les relie : un code honnête

Lis les noms à la suite et une famille apparaît. Le fetch honnête vérifie res.ok au lieu de faire confiance. Le handler POST honnête revalide côté serveur ce que le client a déjà validé. Le repli qui ne ment pas admet qu'aucune configuration ne correspond. Le validateur pur rend un verdict sans effet de bord caché. Le test d'intégration qui parle échoue vraiment quand la fonctionnalité casse, au lieu de passer au vert sur du néant.

Cinq formules, une seule idée : un bon code admet ce qu'il ne sait pas. Il ne suppose pas que la requête a réussi, que la donnée est valide, que la clé existe, que le test a vérifié quelque chose. C'est la ligne de partage la plus fiable entre du code de tutoriel et du code de production — et c'est aussi, en entrevue, ce qui distingue une réponse récitée d'une réponse vécue.

Le Web moderne & Next.js

9 formules

Du squelette d'une page jusqu'à la présentation d'un test technique à l'oral.

0. La page web minimale 1. Le nom d'événement et son callback 2. Le champ étiqueté 3. La rangée flexible 4. La grille qui respire 5. Le fetch honnête 6. Le clou que Next.js enfonce à ta place 7. Un état pour tout le formulaire 8. Le validateur pur
La page web minimale Module 0 · Du mobile au web : lire ce guide
<!DOCTYPE html>                <!-- "ceci est du HTML moderne" -->
<html lang="fr">               <!-- racine du document -->
  <head>                       <!-- métadonnées : RIEN d'affiché ici -->
    <meta charset="UTF-8">     <!-- encodage des caractères (accents !) -->
    <title>RendezVous</title>  <!-- le titre de l'onglet -->
  </head>
  <body>                       <!-- tout ce qui est VISIBLE vit ici -->
    <h1>Prendre rendez-vous</h1>
    <script src="app.js" defer></script> <!-- le JS, chargé sans bloquer -->
  </body>
</html>

Deux zones, une règle : le <head> décrit la page (invisible), le <body> la contient (visible). Tu la reconnaîtras partout — y compris dans ce que Next.js envoie au navigateur, et jusque dans les pages de ce guide, qui sont elles-mêmes bâties sur ce squelette.

Le nom d'événement et son callback Module 1 · Le navigateur : DOM, événements, rendu
element.addEventListener('click', (event) => {
  event.preventDefault(); // si l'élément a un comportement par défaut
  // ... réagir : lire des valeurs, modifier le DOM, appeler le réseau
});

C'est le patron le plus répété de tout le frontend : tu le verras tel quel en vanilla JS, dans les DevTools, dans les vieux tutoriels — et déguisé en onClick={...} ou onSubmit={...} en React, où c'est la bibliothèque qui pose l'écouteur pour toi (on le re-démontera dans le module « React web ↔ React Native : les ponts »). Chaque fois que tu vois un nom d'événement et un callback, c'est cette formule.

Le champ étiqueté Module 2 · HTML sémantique & accessibilité
<label htmlFor="email">Courriel</label>
<input
  id="email"                      // le même identifiant des deux côtés : c'est LE lien
  type="email"                    // bon clavier mobile + validation native
  aria-describedby="email-err"    // « ma description est là-bas » (l'erreur)
  aria-invalid={hasError}         // état invalide annoncé au lecteur d'écran
/>
<p id="email-err" role="alert">Adresse email invalide.</p>

On l'emploie pour chaque champ de formulaire, sans exception ; on la reconnaît au trio htmlFor/id identiques (en HTML pur : for="email" — React impose htmlFor). Le role="alert" de la dernière ligne, lui, veut dire « lis-moi à voix haute dès que j'apparais » — on le détaille à la section sur ARIA. Tu reverras cette formule telle quelle au module « Formulaires 2 — validation & erreurs », où l'on branchera hasError sur une vraie validation.

La rangée flexible Module 3 · CSS 1 — modèle de boîte & flexbox
.row {
  display: flex;                  /* passe les enfants en flexbox        */
  align-items: center;            /* alignés verticalement au centre     */
  justify-content: space-between; /* premiers/derniers aux bords,        */
  gap: 12px;                      /* espace régulier entre les enfants   */
}

C'est le patron le plus tapé du frontend web — barres d'en-tête, lignes de liste, pieds de carte : un coup d'œil et tu le reconnais partout. En React Native il s'écrit exactement pareil, à un détail près : il faut ajouter flexDirection: 'row', puisque le défaut y est column.

La grille qui respire Module 4 · CSS 2 — grid, responsive, variables
.services {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}

La grille responsive sans une seule media query : « autant de colonnes d'au moins 240 px que la place le permet, qui se partagent le reste ». Apprends à la reconnaître d'un coup d'œil — elle est partout, des portfolios aux dashboards, et c'est souvent la première chose qu'on écrit dans un test technique de mise en page.

Le fetch honnête Module 5 · HTTP & fetch : parler au réseau
const res = await fetch('/api/services');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const services = await res.json();

Les trois lignes que tout frontend tape chaque semaine : demander, vérifier le verdict, lire le corps. La deuxième ligne est celle que les juniors oublient — sans elle, un 500 passe pour un succès et le crash arrive plus loin, méconnaissable.

Le clou que Next.js enfonce à ta place Module 6 · React web ↔ React Native : les ponts
import { createRoot } from 'react-dom/client';
import App from './App';

// 1. On trouve la boîte vide définie dans index.html
// 2. createRoot en fait un « territoire » géré par React
// 3. render y peint l'arbre décrit par <App />
createRoot(document.getElementById('root')).render(<App />);

C'est tout ce que « monter React » veut dire : désigner un nœud du DOM et dire à React « à partir d'ici, c'est toi qui commandes ». Retiens-la quand même, même si Next.js te la cachera entièrement dès le module « La carte de Next.js » — c'est exactement ce qui te permettra de comprendre ce que Next.js fait à ta place.

Un état pour tout le formulaire Module 7 · Formulaires 1 — contrôlé ou non
const [values, setValues] = useState({});

const handleChange = (e) =>
  setValues({ ...values, [e.target.name]: e.target.value });

Un seul handleChange dessert N champs : on le branche tel quel sur chaque onChange, et c'est l'attribut name du champ qui dit quelle clé modifier. On la reverra enrichie dans le module Formulaires 2 — validation & erreurs, où le même handler effacera aussi l'erreur du champ touché.

Le validateur pur Module 8 · Formulaires 2 — validation & erreurs
function validate(values) {
  const errors = {};
  if (!values.fullName?.trim()) errors.fullName = 'Le nom est requis.';
  if (!/.+@.+\..+/.test(values.email ?? '')) errors.email = 'Courriel invalide.';
  return errors; // {} = valide
}

Une fonction pure, testable, totalement indépendante de React : on lui donne les valeurs, elle rend un dictionnaire { field: message }, et un objet vide signifie « tout va bien ». C'est le patron qu'attendent les évaluateurs quand ils te demandent « ajoute la validation » : ils regardent si les règles vivent dans un seul endroit isolé, ou si elles sont éparpillées dans le JSX.

Next.js en profondeur

6 formules

App Router · RSC · rendu · mutations

0. Le duo layout + page 1. La frontière client 2. Le lien qui reste un lien 3. La page qui n'existe qu'une fois servie 4. Le handler POST honnête 5. Le test d'intégration qui parle
Le duo layout + page Module 0 · La carte de Next.js
// app/layout.tsx — OBLIGATOIRE, une seule fois, à la racine.
// C'est lui qui écrit <html> et <body> : il n'y a pas d'index.html.
export default function RootLayout({
  children,                                  // ← le segment enfant : la page, ou un layout plus profond
}: { children: React.ReactNode }) {
  return (
    <html lang="fr">
      <body>{children}</body>
    </html>
  );
}

// app/page.tsx — la page de l'URL « / ». Export DEFAULT obligatoire.
export default function Page() {
  return <h1>Bienvenue chez RendezVous</h1>;
}

Le layout enveloppe, la page occupe. Chaque segment de l'App Router est une variation de ce duo : un layout optionnel qui persiste, une page qui change. Tu la reconnaîtras à ses deux marques : l'export default et le paramètre children du layout.

La frontière client Module 1 · Server et Client Components
'use client';
import { useState } from 'react';

export default function AppointmentForm({ services }) {
  const [service, setService] = useState('');
  // … interactivité ici
}

La directive marque le début du monde navigateur : à partir de cette ligne, on a le droit d'utiliser l'état, les événements et les API du navigateur. Et tout ce que ce fichier importe le rejoint automatiquement dans le bundle client — d'où la règle : place-la le plus bas possible dans l'arbre.

Le lien qui reste un lien Module 2 · Routing : segments, layouts, navigation
import Link from 'next/link';

// L'utilisateur clique → toujours un Link (préchargé, accessible, vrai <a>)
<Link href={`/rendez-vous/${service.slug}`}>{service.nom}</Link>

// Et côté client, quand la navigation suit une action :
'use client';
import { useRouter } from 'next/navigation';

const router = useRouter();
router.push('/confirmation');   // push = on empile ; replace = pas de retour

Link pour tout ce que l'utilisateur clique : il précharge la destination, garde le comportement natif d'un lien (nouvel onglet, clavier, lecteur d'écran) et évite le rechargement complet. useRouter() pour les navigations déclenchées par du code — après un formulaire, un paiement, un changement de filtre — et jamais l'inverse : un lien déguisé en bouton, c'est un lien qu'on ne peut ni ouvrir dans un onglet, ni atteindre au clavier.

La page qui n'existe qu'une fois servie Module 3 · Rendu & data fetching
export default async function Page() {
  const res = await fetch('https://api.exemple.ca/services');
  if (!res.ok) throw new Error('Chargement impossible');
  const services = await res.json();
  return <ListeServices services={services} />;
}

Pas de useEffect, pas de useState, pas de spinner : la page n'existe qu'une fois les données là. Ce qui montre l'attente à l'utilisateur, c'est loading.js ou un <Suspense> (section « Le streaming : envoyer la page en morceaux ») — pas un état à toi.

Le handler POST honnête Module 4 · Route Handlers & Server Actions
export async function POST(request: Request) {
  const body = await request.json();
  const errors = validate(body);
  if (Object.keys(errors).length) return Response.json({ errors }, { status: 400 });
  const created = await creerRendezVous(body);
  return Response.json(created, { status: 201 });
}

Lire, valider, agir, répondre avec le bon statut — les quatre gestes, toujours dans cet ordre. Le jour où tu vois un handler qui agit avant de valider, ou qui répond 200 à une création, tu tiens le bug avant même d'avoir lu le reste du fichier.

Le test d'intégration qui parle Module 5 · Tester le web : Vitest & Testing Library
it('envoie les values saisies quand le formulaire est soumis', async () => {
  render(<PageRendezVous />);
  await userEvent.selectOptions(screen.getByLabelText('Service'), 'Échographie');
  await userEvent.type(screen.getByLabelText('Courriel'), 'a@b.ca');
  await userEvent.click(screen.getByRole('button', { name: /réserver/i }));
  expect(await screen.findByText(/rendez-vous confirmé/i)).toBeInTheDocument();
});

Relis ces six lignes et cherche un détail d'implémentation : il n'y en a aucun. Pas un nom d'état, pas une classe CSS, pas un nom de fonction interne — seulement des étiquettes, un libellé de bouton, et un message visible. Ce test survivrait à une réécriture complète du composant : passage de useState à useReducer, découpage en cinq sous-composants, migration vers React Hook Form ou vers une Server Action. Tant que la clinique se réserve de la même façon, il reste vert.

Le test technique

5 formules

Lire, critiquer, présenter — et l'entrevue

0. La critique en trois temps 1. Le repli qui ne ment pas 2. Le traducteur unique 3. Le plan de présentation en 5 temps 4. La question du niveau en dessous
La critique en trois temps Module 0 · Lire et critiquer du code frontend
Observation  : « Ici, la validation n'existe que côté client. »
Impact       : « Une requête envoyée directement à l'API créerait un
                 rendez-vous invalide. »
Proposition  : « Est-ce qu'on pourrait rejouer le validateur dans le
                 Route Handler ? »

Le même patron sert en revue de code, en entrevue et pour se relire soi-même : un fait vérifiable, sa conséquence concrète, puis une piste posée en question plutôt qu'en verdict. Il décrit un code, jamais une personne — c'est précisément ce qui le rend recevable.

Le repli qui ne ment pas Module 1 · Étude de cas : l'énoncé et les données
function findFormConfig(configs, service) {
  return configs.find((c) => c.services.includes(service))
      ?? configs.find((c) => c.services.includes('*'));
}

La correspondance exacte d'abord, le joker ensuite : la priorité est écrite dans la structure du code, pas dans l'ordre des données. Et le type de retour admet l'absence (les deux recherches peuvent échouer), ce qui oblige l'appelant à traiter ce cas — c'est précisément ce qui empêche un plantage à l'exécution le jour où un service n'a ni configuration dédiée ni repli.

Le traducteur unique Module 2 · Étude de cas : la solution disséquée
// UN SEUL endroit du projet traduit le vocabulaire des données
// vers celui du HTML. Partout ailleurs, on parle « config ».
{field.type === 'dropdown' ? (
  <select {...common}>…</select>
) : field.type === 'phone' ? (
  <input {...common} type="tel" />   // "phone" ici, "tel" en HTML
) : (
  <input {...common} type="text" />  // le repli, jamais absent
)}

Deux vocabulaires se rencontrent dans tout projet piloté par des données : celui de la configuration et celui de la plateforme. La formule consiste à les faire se rencontrer en un seul point, et à écrire partout ailleurs le vocabulaire des données. Quand un nouveau type de champ apparaît, tu sais exactement quel fichier ouvrir ; et l'objet common, étalé dans chaque branche, garantit que le trio d'accessibilité s'applique à tous les contrôles sans qu'on ait à y penser.

Le plan de présentation en 5 temps Module 3 · L'entrevue frontend
1. Le problème    — « On devait construire X, avec les contraintes Y. »
2. L'architecture — « J'ai découpé en A, B, C ; l'état vit dans A parce que… »
3. Une trace      — « Voici ce qui se passe quand l'utilisateur clique ici,
                     jusqu'au serveur. »
4. Un choix       — « J'ai pris X plutôt que Y parce que… »
5. La suite       — « Avec une journée de plus : validation serveur, tests,
                     accessibilité. »

Le même plan tient en cinq minutes comme en trente : chaque temps se dilate ou se comprime sans que la structure change. Et il évite le récit ligne par ligne, qui perd tout le monde — y compris toi.

La question du niveau en dessous Module 4 · Pour aller plus loin
Devant un outil, une bibliothèque, un framework :

  « Qu'est-ce que cet outil m'apporte
    que le niveau en dessous ne m'apportait pas ? »

  → Réponse en une phrase concrète  : l'outil est justifié.
  → « rien, mais c'est plus moderne » : le niveau en dessous suffisait.

La question qui gouverne toute cette carte, et tu la verras revenir à chaque territoire : on ne quitte le CSS pour Motion, Motion pour GSAP, le HTML pour la 3D, les props pour un magasin global que lorsqu'on peut nommer ce que l'étage supérieur apporte de plus. Elle sert autant en entrevue qu'en revue de code, et t'évite le piège numéro un du développeur enthousiaste : adopter un outil avant d'avoir le problème.

IFT-2007 · Analyse OO

7 formules

Processus unifié · UML · patrons de conception

0. Frontière, éléments, relations 1. Souligner, trier, relier, compter 2. Le descriptif en six lignes 3. Visibilité, nom, type 4. Boîte, trait, barre, message 5. Responsabilité, classe, patron, raison 6. événement [garde] / action
Frontière, éléments, relations Module 0 · Le processus unifié & UML
1. LA FRONTIÈRE  — qu'est-ce qui est DANS le système, et qu'est-ce qui est dehors ?
2. LES ÉLÉMENTS  — que représentent les boîtes ? des concepts ? des objets ? des acteurs ?
3. LES RELATIONS — que veulent dire les traits, et surtout DANS QUEL SENS se lisent-ils ?

La manière de lire n'importe quel diagramme UML, dans cet ordre. On l'emploie devant un diagramme inconnu ; on la reconnaît au fait que la troisième question est toujours la plus payante — c'est le sens des traits qui porte le sens du modèle, et c'est aussi ce qu'on rate le plus souvent.

Souligner, trier, relier, compter Module 1 · Le modèle du domaine
1. SOULIGNER  tous les noms communs de l'énoncé, sans juger.

2. TRIER      chacun en trois tas :
                · CONCEPT  — il a une identité propre, on peut en avoir plusieurs
                             et les distinguer          → une boîte
                · ATTRIBUT — c'est une valeur simple qui appartient à autre chose
                                                        → une ligne dans une boîte
                · BRUIT    — synonyme, mot du système, ou concept hors sujet
                                                        → on le raye

3. RELIER     une association par FAIT du métier, nommée par un VERBE
              (« emprunte », « contient », « réfère »), avec son sens de lecture.

4. COMPTER    la multiplicité à chaque bout, en posant à chaque fois
              la même question : « combien de X pour UN SEUL Y ? »

La méthode de construction d'un modèle du domaine. On l'emploie sur toute description textuelle ; on la reconnaît au fait que l'étape 2 est la seule qui demande de réfléchir — les trois autres sont mécaniques.

Le descriptif en six lignes Module 2 · Cas d'utilisation & DSS
Nom                : un VERBE à l'infinitif + son complément
Acteur principal   : qui déclenche, et pour quel objectif
Préconditions      : ce qui est VRAI avant qu'on commence
Garanties (succès) : ce qui sera VRAI à la fin, si tout va bien
Scénario principal : les étapes numérotées, quand TOUT va bien
Extensions         : 3a, 5a… — les variantes, rattachées à leur étape

Le format de Larman, celui que le cours emploie. On l'écrit pour chaque cas d'utilisation retenu ; on le reconnaît au fait que les deux dernières lignes pèsent plus que les quatre premières réunies.

Visibilité, nom, type Module 3 · Le diagramme de classes & l'architecture logique
VISIBILITÉ   +  public       accessible de partout
             -  privé        accessible dans la classe seule
             #  protégé      la classe et ses sous-classes
             ~  paquetage    les classes du même paquetage

ATTRIBUT     visibilité nom : Type [multiplicité] = valeurParDefaut
                -  solde : double = 0.0
                -  lignes : LigneCommande [1..*]

OPÉRATION    visibilité nom(param : Type, ...) : TypeRetour
                +  calculerTotal() : double
                +  ajouterLigne(plat : Plat, quantite : int) : void

             souligné = membre de CLASSE       italique = ABSTRAIT

La notation d'un membre de classe en UML. On l'écrit pour chaque ligne des deux compartiments du bas ; on la reconnaît au fait que tout y est facultatif sauf le nom et la visibilité — et que c'est la visibilité qu'on oublie.

Boîte, trait, barre, message Module 4 · Les diagrammes d'interaction
LIGNE DE VIE
   :Livre          un objet de Livre
   emprunte:Livre  un objet nommé
   Livre           la CLASSE, pas un objet
   Usager          un acteur, sans boîte

   sous la boîte, un trait POINTILLÉ :
   c'est le TEMPS. Rien n'est à l'échelle,
   seul l'ORDRE compte.

BARRE D'ACTIVATION
   posée sur le trait = l'objet EXÉCUTE
   début : la réception ; fin : la réponse

MESSAGE
   [garde] valeur := nom(arg : Type)
      estDisponible()
      [en regle] no := emprunter(livre)

RETOUR
   flèche pointillée, portant la VALEUR

La grammaire d'un diagramme de séquence, en entier. On la reconnaît à ce que tout y est facultatif sauf le nom du message : la garde, la valeur de retour et même les arguments s'omettent dès qu'ils vont de soi.

Responsabilité, classe, patron, raison Module 5 · Les principes GRASP
<responsabilité> → <classe>
   par <PATRON>, parce que <raison>

   calculerSousTotal() → LigneCommande
      par EXPERT, parce qu'elle detient la
      quantite et atteint le prix du plat

   creerEmprunt() → Lecteur
      par CREATEUR, parce qu'il enregistre
      ses emprunts

La raison nomme un FAIT du diagramme : une
donnee possedee, une agregation, un
evenement recu. Jamais « c'est plus propre ».

Le gabarit de toute justification GRASP, et la forme exacte attendue sur une copie. On le reconnaît à ce qu'il tient en une ligne et demie : si la raison prend trois phrases, c'est que le patron invoqué n'est pas le bon.

événement [garde] / action Module 6 · Les diagrammes d'états
événement [garde] / action

  ÉVÉNEMENT   ce qui ARRIVE à l'objet
      rendre()              un appel
      après(30 jours)       le temps
      quand(solde < 0)      une condition
                            devenue vraie

  [GARDE]     une condition BOOLÉENNE, testée
              quand l'événement arrive.
              Fausse : rien ne se passe.
      [prolongations < 1]

  / ACTION    ce qui S'EXÉCUTE pendant le
              passage. Instantané.
      / facturerAmende()

ÉTIQUETTES COMPLÈTES
      rendre()
      rendre() / facturerAmende()
      prolonger(j) [prolongations < 1]
      payer(m) [solde >= m] / debiter(m)

Seul l'événement est normalement présent ; la garde et l'action s'omettent dès qu'il n'y en a pas. C'est la réponse à la question la plus fréquente sur cette notation, et la source des étiquettes qu'on croit incomplètes alors qu'elles sont justes. Une flèche nue, sans aucun événement, existe aussi — c'est la transition automatique, traitée plus bas —, mais c'est un cas particulier qu'on n'écrit que lorsqu'on le veut vraiment.

IFT-2008 · Algorithmes

5 formules

Analyse · structures de données · C++

0. Les quatre gestes de l'analyse 1. Le conteneur qui possède sa mémoire 2. Le parcours du fil 3. Le parcours marqué 4. Le parcours marqué — rappel
Les quatre gestes de l'analyse Module 0 · L'analyse asymptotique
// GESTE 1 — le baromètre : l'instruction la plus interne.
// GESTE 2 — le compte : pour i fixé, l'interne tourne i fois.
//           Donc le total s'écrit  somme de i, pour i de 1 à n.
// GESTE 3 — le formulaire : cette somme vaut n(n+1)/2.
// GESTE 4 — la conclusion : n(n+1)/2 est dominé par n², donc Theta(n^2).

for (int i = 1; i <= n; i++) {
  for (int j = 1; j <= i; j++) {
    somme += j;                    // ← le baromètre
  }
}

On l'emploie sur toute boucle imbriquée ; on la reconnaît au fait que la borne de la boucle interne dépend de l'indice externe, ce qui donne toujours une somme et non un produit.

Le conteneur qui possède sa mémoire Module 1 · Les éléments de C++
template<typename T>             // 1. générique : un moule, tous les types
class Conteneur {
private:
    T*  donnees;                  // 2. ce qu'on POSSÈDE, et qu'il faudra rendre
    int taille;

public:
    Conteneur(int n)              // 3. liste d'initialisation, PUIS allocation
        : taille(n) { donnees = new T[n]; }

    ~Conteneur() { delete[] donnees; }   // 4. le delete vit ICI, toujours

    void ajouter(const T& v);            // 5. on reçoit en const T&
    int  getTaille() const;              // 6. qui ne modifie pas est const
};

Le squelette de toutes les structures du cours : liste, pile, file, arbre, monceau. On la reconnaît à la paire new dans le constructeur / delete dans le destructeur — et dès qu'on la voit, on sait qu'il faut chercher les trois méthodes de la règle des trois.

Le parcours du fil Module 2 · Les structures linéaires
// Visiter tous les nœuds, du premier au dernier.
for (Noeud* courant = tete; courant != nullptr; courant = courant->suivant) {
    // ... traiter courant->valeur
}

// La VARIANTE de suppression : on s'arrête sur le nœud d'AVANT,
// parce qu'une liste simple ne sait pas revenir en arrière.
Noeud* courant = tete;
while (courant->suivant != nullptr && courant->suivant->valeur != v)
    courant = courant->suivant;
// ici, courant->suivant est le nœud à retirer (ou nullptr : absent)

Le patron le plus réutilisé du reste du cours. On le reconnaît à sa condition d'arrêt — != nullptr, jamais un indice — et à sa mise à jour, qui suit un pointeur au lieu d'incrémenter un compteur. Chaque fois qu'une opération demande de trouver quelque chose dans une liste, c'est cette boucle qui coûte le Θ(n).

Le parcours marqué Module 3 · Les graphes : représenter et parcourir
marquer(depart);
attente.ajouter(depart);

while (!attente.vide()) {
    u = attente.retirer();       // <-- LA SEULE LIGNE QUI DIFFÈRE
    traiter(u);

    for (int v : voisins[u]) {
        if (!marque(v)) {
            marquer(v);
            attente.ajouter(v);
        }
    }
}
// attente = file  -> parcours en LARGEUR
// attente = pile  -> parcours en PROFONDEUR

Le patron le plus rentable du chapitre, parce qu'il n'y en a qu'un. BFS et DFS ne sont pas deux algorithmes : c'est un algorithme, paramétré par la nature de la structure d'attente. Retiens-le sous cette forme et tu n'auras plus jamais deux codes à mémoriser — seulement la question « qui sort en premier ? ». Le module suivant le rappellera trois fois : la détection de cycle, le tri topologique et les composantes fortement connexes sont ce même squelette, avec un geste de plus au moment de traiter.

Le parcours marqué — rappel Module 4 · Les graphes : ce que les parcours calculent
marquer(depart);
attente.ajouter(depart);

while (!attente.vide()) {
    u = attente.retirer();       // file -> largeur ; pile -> profondeur
    traiter(u);                  // <-- TOUT CE MODULE TIENT ICI

    for (int v : voisins[u]) {
        if (!marque(v)) { marquer(v); attente.ajouter(v); }
    }
}

La ligne traiter(u) était un affichage dans le module précédent. Remplace-la par « noter que u est en cours d'exploration » et tu détectes un cycle ; par « empiler u en sortant » et tu obtiens un tri topologique ; par « ajouter u au groupe courant » et tu comptes des composantes. Un seul squelette, quatre algorithmes.

Lire Halterofit

13 formules

Les patrons qu'on recroise partout dans un projet React Native / Expo / TypeScript.

0. La cascade de gardes 1. Charger, réussir, échouer — et toujours éteindre la lumière 2. Le type fabriqué à partir d'un autre 3. Les données descendent, l'événement remonte 4. Brancher, puis débrancher 5. Ne pas recalculer ce qui n'a pas bougé 6. Le champ contrôlé 10. Le videur à l'entrée du sous-arbre 11. Le composant propose, l'appelant dispose 12. Une seule vérité, le reste s'en déduit 13. La même requête, en photo ou en direct 14. La ligne t'appartient-elle ? 15. Le hook livre l'écran clé en main
La cascade de gardes Module 0 · Méthode pour lire le code
export function getEmailError(email: string): string | null {
  const trimmed = email.trim();

  if (trimmed.length === 0) return 'Email is required';
  if (trimmed.length > MAX_EMAIL_LENGTH) return 'Email cannot exceed…';
  if (!EMAIL_REGEX.test(trimmed)) return 'Enter a valid email address';

  return null; // aucune garde n'a mordu → tout va bien
}

Quand on valide une donnée venue de l'extérieur avant de s'en servir. On la reconnaît à sa pile de if qui sortent tôt, sans else, et au cas normal seul tout en bas (null = pas d'erreur).

Charger, réussir, échouer — et toujours éteindre la lumière Module 1 · JavaScript moderne & l'asynchrone
const handleSignUp = async () => {
  setError('');
  setIsLoading(true);
  try {
    await signUp(email, password, displayName); // pause NON bloquante
    router.replace({ pathname: '/(auth)/confirm-account' });
  } catch (err) {
    setError(isOperationalError(err) ? err.userMessage : 'Something went wrong.');
  } finally {
    setIsLoading(false); // succès OU échec : on éteint le sablier
  }
};

Quand un geste de l'utilisateur déclenche une opération longue (réseau, base). On la reconnaît au trio setIsLoading(true)try/catchfinally qui remet le drapeau à false quoi qu'il arrive.

Le type fabriqué à partir d'un autre Module 2 · Lire les types TypeScript
// Pour CRÉER : la base génère l'id → on le retire du type d'entrée.
export type CreateWorkout = Omit<Workout, 'id'>;

// Pour METTRE À JOUR : on n'envoie que ce qui change → tout devient facultatif.
export type UpdateWorkout = Partial<Omit<Workout, 'id'>>;

Quand une entité a plusieurs formes selon le moment (créer, modifier, afficher). On la reconnaît aux chevrons imbriqués, qui se lisent de l'intérieur vers l'extérieur : le noyau, puis les couches.

Les données descendent, l'événement remonte Module 3 · Le modèle mental de React
// Le parent possède la donnée et la fait DESCENDRE en prop ;
// il passe un callback pour que l'enfant fasse REMONTER l'événement.
{series.map((s) => (
  <SetRow
    key={s.id}                       // identité stable, pour le diff de React
    reps={s.reps}                    // donnée qui descend (prop, lecture seule)
    onComplete={() => marquerFait()} // événement qui remonte (callback)
  />
))}

Dès qu'un composant en rend un autre. On la reconnaît au couple « une prop de données + une prop on… », et à la key dès qu'il y a un .map().

Brancher, puis débrancher Module 4 · useState & useEffect
useEffect(() => {
  if (startEpochMs == null) return; // rien à synchroniser

  const tick = () =>
    setElapsed(Math.max(0, Math.floor((Date.now() - startEpochMs) / 1000)));
  const timeout = setTimeout(tick, 0);
  const interval = setInterval(tick, 1000);

  return () => {          // le nettoyage débranche ce que l'effet a branché
    clearTimeout(timeout);
    clearInterval(interval);
  };
}, [startEpochMs]);       // quand faut-il rejouer ?

Quand le composant doit se synchroniser avec un système extérieur (minuteur, abonnement, écouteur). On la reconnaît à ses trois parties : l'effet, la fonction de nettoyage retournée, et le tableau de dépendances.

Ne pas recalculer ce qui n'a pas bougé Module 5 · useContext, useMemo, memo
const exercises = useMemo(() => {
  const dbExercises = workout?.exercises ?? [];
  if (dbExercises.length === 0) return dbExercises;
  const visibleIds = new Set(exerciseIdsKey ? exerciseIdsKey.split(',') : []);
  return dbExercises.filter((e) => visibleIds.has(e.id));
}, [workout, exerciseIdsKey]); // le chrono re-render chaque seconde : on ne refiltre pas

Quand un calcul réel (filtrer, trier, construire un Set) se retrouve dans un composant qui re-render souvent. On la reconnaît à la forme useMemo(() => …, [ingrédients]) : mêmes dépendances, donc même référence rendue.

Le champ contrôlé Module 6 · React Native : les briques
const [email, setEmail] = useState('');
// …
<Input
  placeholder="Email"
  value={email}           // l'état React est la SOURCE DE VÉRITÉ du champ
  onChangeText={setEmail} // chaque frappe met l'état à jour (la chaîne, pas un event)
  editable={!isLoading}   // champ gelé pendant une requête
/>

Pour toute saisie utilisateur. On la reconnaît au couple value={x} / onChangeText={setX} : le champ n'a pas de mémoire propre, il n'affiche que l'état. Son jumeau web est la formule « Un état pour tout le formulaire ».

Le videur à l'entrée du sous-arbre Module 10 · Navigation (Expo Router)
export default function AppLayout() {
  const isAuthenticated = useAuthStore((s) => s.isAuthenticated);

  // LA GARDE : pas connecté → on redirige, aucun écran privé n'est rendu.
  if (!isAuthenticated) return <Redirect href="/sign-in" />;

  return (
    <Stack screenOptions={{ headerShown: false }}>
      <Stack.Screen name="(tabs)" />
    </Stack>
  );
}

Quand un groupe entier d'écrans doit être protégé par une même condition. On la reconnaît à un _layout.tsx qui retourne un <Redirect> au lieu de son conteneur : trois lignes protègent tout le sous-arbre.

Le composant propose, l'appelant dispose Module 11 · Composants & style
function Button({ className, variant, size, ...props }: ButtonProps) {
  return (
    <Pressable
      className={cn(
        props.disabled && 'opacity-50',    // a) conditionnel
        buttonVariants({ variant, size }), // b) le style CVA
        className                          // c) l'appelant EN DERNIER → il surcharge
      )}
      {...props}                           // onPress, disabled, children… transmis
    />
  );
}

Pour toute brique d'un système de composants. On la reconnaît à la signature qui collecte (...props) puis réétale ({...props}), et à l'ordre du cn()className finit toujours dernier — la dernière classe gagne.

Une seule vérité, le reste s'en déduit Module 12 · État global (Zustand)
export const useAuthStore = create<AuthState>()((set) => ({
  user: null,
  isAuthenticated: false,
  setUser: (user) =>
    set({
      user,                           // LA source de vérité
      isAuthenticated: user !== null, // dérivé : les deux ne peuvent se contredire
    }),
}));

// À la lecture : un sélecteur = on ne s'abonne QU'À cette tranche.
const isAuthenticated = useAuthStore((s) => s.isAuthenticated);

Quand une donnée est partagée par des écrans éloignés. On la reconnaît à un objet « valeurs + fonctions », où les champs calculables sont recalculés dans l'action, et à la lecture par sélecteur (s) => s.champ.

La même requête, en photo ou en direct Module 13 · WatermelonDB & offline-first
// PHOTO : lecture unique → une Promesse. Marqueurs : await + .fetch()
export async function getActiveWorkout(userId: string) {
  const rows = await database.get('workouts')
    .query(Q.where('user_id', userId), Q.where('completed_at', null)).fetch();
  return rows[0] ? workoutToPlain(rows[0]) : null;
}

// DIRECT : MÊME requête, seul le verbe final change → un Observable.
export function observeActiveWorkout(userId: string) {
  return database.get('workouts')
    .query(Q.where('user_id', userId), Q.where('completed_at', null)).observe();
}

Chaque fois qu'on lit la base locale. On la reconnaît au verbe final : .fetch() = une photo figée, pour un traitement ponctuel ; .observe() = un flux qui ré-émet, pour un écran qui doit rester à jour.

La ligne t'appartient-elle ? Module 14 · Supabase : le backend
-- Sans cette ligne, aucune politique ne s'applique.
ALTER TABLE public.workouts ENABLE ROW LEVEL SECURITY;

-- FOR ALL = lire, insérer, modifier, supprimer.
CREATE POLICY "Users see own workouts" ON public.workouts FOR ALL
  -- Postgres ajoute ce filtre à CHAQUE requête : incontournable depuis l'app.
  USING ((select auth.uid()) = user_id);

Dès qu'une table contient les données de plusieurs utilisateurs. On la reconnaît au motif auth.uid() = user_id : la sécurité vit dans la base, jamais dans un if côté client.

Le hook livre l'écran clé en main Module 15 · Traçage de bout en bout
// Dans le hook : des DONNÉES prêtes à afficher + des ACTIONS à brancher.
return {
  currentExercise,
  isLastExercise: exerciseCount > 0 && safeIndex === exerciseCount - 1,
  elapsedSeconds,
  goToNextExercise: nextExercise, // action du store, simplement ré-exposée
};

// Dans l'écran : une ligne. Il ignore qu'il existe un store et une base.
const { currentExercise, elapsedSeconds, goToNextExercise } = useActiveWorkout();

Quand un écran a besoin de plusieurs données et de plusieurs gestes. On la reconnaît au return { … } mêlant valeurs et fonctions, et à l'écran qui déstructure tout en une seule ligne.