Module 0 · Pour commencer

La méthode pour lire un fichier inconnu

C'est la compétence la plus rentable de tout ce guide, et de loin. Avant d'apprendre React, TypeScript ou quoi que ce soit d'autre, apprends à aborder un fichier que tu n'as jamais vu sans paniquer. Ce module ne t'apprend pas un langage : il t'apprend une façon de regarder le code. Une fois que tu l'as, tout le reste du guide devient plus facile.

💡 Le concept

On ne lit pas du code comme un roman, de la première à la dernière ligne. Un développeur expérimenté survole d'abord, puis plonge sur un seul chemin. Il cherche la forme du fichier avant les détails. Le secret n'est pas de tout comprendre d'un coup : c'est de savoir dans quel ordre poser tes questions. La compréhension vient par couches, pas en un seul bloc.

Lire n'est pas écrire

On a tendance à croire que si on sait écrire du code, on sait forcément le lire. C'est faux, et c'est l'un des malentendus les plus coûteux quand on débute. Écrire et lire sont deux compétences distinctes, qui s'entraînent séparément. Quand tu écris, tu pars de ton intention : tu sais déjà ce que tu veux que le programme fasse, et tu traduis cette intention en code. Le sens existe d'abord dans ta tête, le code n'est que sa trace. Quand tu lis, tout est inversé : tu n'as que la trace, et tu dois reconstruire l'intention qui l'a produite. Tu fais le chemin à l'envers, à partir d'indices laissés par quelqu'un d'autre (parfois par toi-même, six mois plus tôt, ce qui revient au même).

Cette inversion de perspective est tout l'enjeu. Lire du code, ce n'est pas décoder une syntaxe, c'est deviner ce que l'auteur essayait d'accomplir. Les bons lecteurs ne se demandent pas seulement « que fait cette ligne ? » mais « pourquoi l'auteur a-t-il écrit ça plutôt qu'autre chose ? Quel problème cherchait-il à régler ? De quoi avait-il peur ? ». Un test sur la longueur d'un mot de passe, par exemple, n'est pas juste une comparaison de nombres : c'est la trace d'une peur (« et si quelqu'un envoie un mot de passe de 5 000 caractères ? ») et d'une contrainte technique (la limite de l'outil de chiffrement). Le code te montre la solution ; ton travail de lecteur, c'est de remonter jusqu'à la question.

Autre vérité libératrice : même les auteurs relisent leur propre code et ne le comprennent pas instantanément. Personne ne garde un fichier entier en tête. Un développeur qui retravaille du code écrit trois mois plus tôt le redécouvre presque comme un étranger — il applique exactement la même méthode de lecture que toi sur un fichier inconnu. Si tu pensais que les « vrais » programmeurs lisent un fichier d'un coup d'œil et comprennent tout, détrompe-toi : ils sont juste rapides à survoler et disciplinés pour ne pas tout lire en même temps. La fluidité que tu admires n'est pas de la mémoire, c'est de la méthode.

🧭 Bon à savoir

Dans la plupart des projets, le code passe bien plus de temps à être lu qu'à être écrit : on l'écrit une fois, on le relit des dizaines de fois (pour le corriger, l'étendre, le réviser). C'est pour ça que lire vite et juste est un super-pouvoir : tu passes la majorité de ta vie de développeur à faire exactement ça. Mieux tu lis, plus vite tu progresses sur tout le reste.

Pourquoi cette compétence est sous-estimée

On ne t'enseigne presque jamais à lire du code. Les cours, les tutoriels, les écoles : tout est tourné vers l'écriture (« écris une fonction qui fait X »). Du coup, beaucoup de gens arrivent en entreprise en sachant produire du code neuf, mais paniquent dès qu'on les met devant une base de code existante. Or, dans la vraie vie, tu commences presque toujours par de l'existant : on te demande de corriger un bug dans un fichier que tu n'as pas écrit, d'ajouter une option à un écran qui existe déjà, de comprendre pourquoi telle valeur arrive cassée. Tu lis avant d'écrire, toujours.

La bonne nouvelle, c'est que tu pars avec un avantage : tu connais déjà JavaScript. Tu n'as donc pas à apprendre la syntaxe en même temps que la méthode. Ton obstacle n'est pas « qu'est-ce que const ? » — tu le sais. Ton obstacle, c'est l'abondance : un fichier de l'app contient trop d'informations pour ta mémoire de travail, et sans stratégie tu te noies. La méthode qui suit est précisément une stratégie pour ne jamais regarder plus d'informations que ce que ton cerveau peut tenir à un instant donné. Tu découpes l'éléphant en bouchées.

La démarche en 6 temps

Voici le cœur du module. Pour n'importe quel fichier, pose-toi ces 6 questions, toujours dans cet ordre. L'ordre n'est pas décoratif : chaque temps prépare le suivant en réduisant ce que tu dois tenir en tête. Tu vas de la vue la plus large (« à quoi sert ce fichier ? ») à la plus étroite (« que fait cette ligne précise ? »), et seulement quand tu y es prêt.

Temps 1 — Les imports : de quoi ça dépend ?

Tout en haut du fichier. Les imports te disent ce dont le fichier a besoin pour fonctionner, et c'est une mine d'informations gratuites. Voit-on react ou react-native ? Alors le fichier touche à l'affichage. Voit-on un client de base de données, un supabase, un fetch ? Alors il parle au réseau ou au stockage. Ne voit-on presque rien, juste une ou deux dépendances internes ? Alors c'est sans doute du code « pur » : de la logique sans effets de bord, le genre le plus facile et le plus agréable à lire. En dix secondes, sans avoir lu une seule fonction, tu connais déjà la catégorie du fichier. C'est comme regarder les ingrédients d'une recette avant de la cuisiner.

Temps 2 — Les exports : qu'est-ce que ça offre ?

Souvent en bas, ou répartis dans le fichier devant le mot-clé export. Si les imports disent ce dont le fichier dépend, les exports disent ce qu'il offre au reste de l'application — sa raison d'être, son contrat public. Un fichier qui exporte trois fonctions nommées getEmailError, getPasswordError, validateEmail t'annonce sa mission avant même que tu lises son contenu : il valide des formulaires. Tout ce qui n'est pas exporté est privé, un rouage interne ; tu pourras le survoler plus vite, parce que personne d'autre ne s'en sert. Imports et exports forment ensemble la « façade » du fichier : ce qui entre, ce qui sort. Avec ces deux temps seulement, tu as déjà une phrase qui résume le fichier.

Temps 3 — Les types et signatures : quelle est la forme des données ?

Une signature de fonction, c'est (email: string): string | null : ce qui entre, ce qui sort. C'est l'information la plus dense du code. Une bonne signature te raconte une histoire complète sans une seule ligne de logique : « je prends un email sous forme de texte, et je te rends soit un texte, soit rien ». Les types sont une carte des données. On les approfondira dans le module sur les types (TypeScript), mais retiens dès maintenant ce réflexe : lis la signature avant le corps. Très souvent, la signature suffit à comprendre l'intention de la fonction, et tu peux décider de ne même pas lire son intérieur tout de suite.

Temps 4 — Le survol descendant : lis les noms, pas le contenu

Maintenant, parcours le fichier du haut vers le bas, mais en ne lisant que les noms — noms de fonctions, noms de variables, noms de constantes — sans jamais ouvrir l'intérieur des accolades. Tu construis une carte mentale. C'est comme survoler une ville en avion avant d'y marcher : tu repères les grands quartiers, les axes principaux, sans connaître encore chaque ruelle. Un code bien écrit se lit presque comme du français à ce niveau-là, parce que les bons noms sont déjà des phrases. Si en survolant tu peux te raconter l'histoire du fichier (« d'abord on définit des limites, ensuite on a des validateurs qui retournent l'erreur, puis des validateurs qui la lèvent »), tu as gagné : tu sais où tout se trouve, sans avoir lu une seule ligne de logique.

Temps 5 — Tracer UN chemin concret

C'est ici qu'on plonge enfin dans les détails — mais d'une manière très précise. Tu choisis un seul scénario concret (« l'utilisateur tape un email sans @ ») et tu le suis, ligne par ligne, une seule fois, comme si tu étais la donnée qui traverse la fonction. Tu ne lis pas toutes les branches : tu ne lis que celles que ton scénario emprunte. C'est radicalement plus facile que d'essayer de comprendre toutes les possibilités à la fois, parce que ta mémoire ne suit qu'une histoire au lieu de cinq. Le vrai code est plein de if, de boucles, de cas particuliers — mais pour un scénario donné, la plupart de ces branches ne se déclenchent pas. Choisis un cas, deviens la donnée, avance.

Temps 6 — Nommer le pattern

La dernière étape, et la plus satisfaisante : recule, et donne un nom à ce que tu viens de lire. « Ah, c'est juste une suite de validations qui s'arrêtent à la première erreur. » « Ah, c'est une fabrique qui assemble un objet selon un paramètre. » Quand tu nommes un pattern, tu le relies à quelque chose que tu connais déjà, et il cesse d'être effrayant : tu n'as plus à le re-comprendre la prochaine fois, tu le reconnais. C'est exactement comme ça que les développeurs expérimentés vont vite — pas parce qu'ils lisent plus vite caractère par caractère, mais parce qu'ils reconnaissent les formes au premier coup d'œil. La section « Reconnaître les patterns courants », plus bas, est ta première trousse de ces noms.

🧭 Le réflexe clé

Si tu te sens perdu, c'est presque toujours que tu es trop tôt à l'étape 5 (lire les détails) alors que tu n'as pas fait les étapes 1 à 4. C'est le piège numéro un. Le réflexe à entraîner : dès que ça noie, remonte. Reviens aux imports, aux exports, aux signatures, refais ta carte, et seulement ensuite replonge sur un chemin. Se sentir perdu n'est pas un signe que tu es nul ; c'est un signal que tu as sauté une étape.

On applique la méthode

Assez de théorie, passons à un vrai fichier de ton app : les validateurs du formulaire d'inscription. C'est un excellent premier patient, parce qu'il est court, pur (sans React ni base de données) et représentatif d'un motif qu'on croise partout. Surtout : ne le lis pas encore en entier. On va appliquer la méthode, temps par temps, et tu vas voir à quel point la compréhension arrive sans effort quand l'ordre est respecté.

Temps 1 & 2 — Imports et exports

apps/mobile/src/utils/validators/auth.ts
// ── TEMPS 1 : les imports. Ce fichier ne dépend que d'UNE chose :
//    une classe d'erreur maison. Donc : pas d'écran, pas de base de
//    données. C'est du code "pur" (juste de la logique). Bon signe :
//    un fichier pur est facile à lire et à tester.
import { ValidationError } from '@/utils/errors';

export const MIN_PASSWORD_LENGTH = 8;
export const MAX_PASSWORD_LENGTH = 72; // limite de bcrypt
export const MAX_EMAIL_LENGTH = 254;   // limite RFC 5321

// Regex email simple — Supabase fait la vraie validation côté serveur.
const EMAIL_REGEX = /.+@.+\..+/;

Les export devant les constantes te disent qu'elles sont réutilisées ailleurs (les écrans affichent « min 8 caractères » en se basant dessus). Le const EMAIL_REGEX sans export est privé à ce fichier.

Note déjà tout ce que ces quelques lignes te donnent gratuitement. La seule dépendance est ValidationError : aucun écran, aucun réseau, aucune base de données. Tu peux donc te détendre — ce fichier ne va pas te promener à travers dix autres modules ; il se suffit presque à lui-même. Les trois constantes exportées (longueurs min/max) sont un signal fort : si elles sont exportées, c'est que d'autres fichiers s'en servent, sûrement les écrans qui affichent « 8 caractères minimum ». Et les petits commentaires (« limite de bcrypt », « RFC 5321 ») sont de l'or pur : ils répondent au « pourquoi » avant même que tu poses la question. C'est ça, lire l'intention derrière le code.

Temps 3 & 4 — Signatures et survol

On lit juste les en-têtes des fonctions, pas leur contenu. Que nous apprennent-ils ?

// TEMPS 3 : la signature dit tout.
//   "prend un email (string), retourne soit un message d'erreur (string),
//    soit null". La convention est claire : null = tout va bien.
export function getEmailError(email: string): string | null { /* ... */ }

export function getPasswordError(password: string): string | null { /* ... */ }

export function getPasswordConfirmError(
  password: string,
  confirm: string,
): string | null { /* ... */ }

// Deux autres fonctions qui, elles, LÈVENT une erreur au lieu de la retourner.
export function validateEmail(email: string): void { /* ... */ }
export function validatePassword(password: string): void { /* ... */ }

Survol terminé. Sans avoir lu une seule ligne de logique, tu sais déjà que ce fichier propose deux familles de validateurs : ceux qui retournent l'erreur (pour afficher un message sous un champ) et ceux qui la lèvent (throw, pour la couche métier). C'est ça, « nommer le pattern ».

Regarde la puissance du temps 3 : la signature (email: string): string | null te raconte toute l'histoire sans une ligne de corps. Et le temps 4 — le simple survol des noms — fait émerger une structure : il y a les fonctions en get…Error qui rendent un string | null, et les fonctions en validate… qui rendent void (rien). Cette différence de type de retour n'est pas anodine ; elle annonce deux comportements opposés. Les premières te donnent l'erreur pour que tu en fasses ce que tu veux ; les secondes la lancent et interrompent le programme. Tu viens de comprendre l'architecture du fichier sans avoir lu un seul if. C'est exactement l'effet recherché.

Temps 5 — Tracer UN chemin concret

Scénario : l'utilisateur tape "bob" (sans @) comme email. Suivons uniquement ce chemin dans getEmailError. Deviens la chaîne "bob" et traverse la fonction :

export function getEmailError(email: string): string | null {
  const trimmed = email.trim();          // "bob" → "bob" (rien à couper)

  if (trimmed.length === 0) {            // 3 ≠ 0 → on saute ce bloc
    return 'Email is required';
  }
  if (trimmed.length > MAX_EMAIL_LENGTH) { // 3 > 254 ? non → on saute
    return `Email cannot exceed ${MAX_EMAIL_LENGTH} characters`;
  }
  if (!EMAIL_REGEX.test(trimmed)) {      // "bob" ne matche pas .+@.+\..+
    return 'Enter a valid email address'; // ◀── ON SORT ICI
  }
  return null;                            // (jamais atteint dans ce scénario)
}

En traçant un seul scénario, la fonction devient évidente : une série de gardes, chacune renvoyant un message dès qu'un problème est trouvé. Tu n'as pas eu besoin de comprendre les 5 fonctions à la fois — juste un chemin.

Remarque ce que tu n'as pas eu à faire : tu n'as pas tenu en tête les quatre messages d'erreur en même temps, tu n'as pas réfléchi aux mots de passe, tu n'as pas ouvert les autres fonctions. Tu as suivi une donnée à travers un chemin, et la dernière ligne (return null) n'a même pas été atteinte dans ce scénario. Pour bien ancrer la méthode, refais l'exercice mentalement avec un autre scénario : un email vide "". Tu verras qu'il sort dès le premier if, sur 'Email is required'. Deux scénarios, deux chemins, et tu connais la fonction par cœur — sans jamais avoir essayé de tout embrasser d'un coup.

🏋️ Ce que ça révèle de ton app

Ce petit fichier illustre une décision d'architecture de Halterofit : la validation est centralisée et « pure ». Les écrans n'inventent pas leurs propres règles, ils appellent getEmailError. Résultat : changer la longueur minimale du mot de passe se fait à un seul endroit. Quand tu liras l'écran d'inscription (le module sur useState & useEffect), tu reconnaîtras ces fonctions ; et la séparation entre validateurs qui retournent et validateurs qui lèvent est exactement la frontière entre la couche d'affichage et la couche métier (le module sur les services y revient).

Reconnaître les patterns courants

Lire vite, c'est surtout reconnaître des formes déjà vues. Le code neuf est rare ; la plupart du temps, ce que tu lis est une variation de quelques motifs qui reviennent sans cesse. Une fois que tu sais les nommer, tu n'as plus à les décrypter ligne par ligne : tu vois la forme, tu connais l'intention. Voici les motifs que tu vas croiser le plus souvent, avec, pour chacun, à quoi il ressemble et comment le repérer.

Les gardes (early return / clauses de garde)

Le motif que tu viens de voir dans getEmailError. Une suite de if placés en début de fonction, chacun traitant un cas problématique et sortant immédiatement (return ou throw) si la condition est remplie. À la fin, quand toutes les gardes ont été franchies sans déclencher, on arrive au cas « tout va bien ». Comment le reconnaître : beaucoup de return précoces, peu ou pas de else, et le « vrai » travail tout en bas. L'intention : éliminer d'abord les cas tordus pour que le cas normal reste simple et non indenté.

function exemple(x) {
  if (!x) return null;        // garde : on sort tôt si x est absent
  if (x.length === 0) return null; // garde : encore un cas à écarter
  return faireLeVraiTravail(x); // ◀ le cas normal, en bas, au calme
}

La transformation (map / filter)

On prend une liste et on en produit une autre. map transforme chaque élément (même nombre d'éléments en sortie) ; filter garde seulement certains éléments (sortie plus courte). Comment le reconnaître : une chaîne d'appels sur un tableau, souvent avec une petite fonction fléchée à l'intérieur. L'intention : décrire ce qu'on veut obtenir sans écrire de boucle manuelle. Quand tu lis liste.map(...), ne lis pas ça comme une boucle compliquée : lis « pour chaque élément, je le transforme ainsi ».

const noms = users.map(u => u.name);        // transforme chaque user en son nom
const actifs = users.filter(u => u.isActive); // garde seulement les actifs

La validation

Tout le fichier auth.ts en est un exemple. On reçoit une donnée venue de l'extérieur (un formulaire, une réponse réseau) et on vérifie qu'elle respecte des règles avant de s'en servir. Comment le reconnaître : des fonctions dont le nom commence par validate, check, is…, get…Error ; un retour qui est soit un booléen, soit un message d'erreur, soit null quand tout va bien. L'intention : protéger le reste du code des données invalides. C'est presque toujours bâti avec des gardes.

La fabrique (factory)

Une fonction dont le seul but est de construire et retourner un objet, souvent en choisissant sa forme selon un paramètre. Comment le reconnaître : un nom du genre create…, make…, build… ; en entrée quelques options, en sortie un objet tout assemblé. L'intention : centraliser la fabrication d'un objet pour que personne d'autre n'ait à connaître les détails de son montage.

function createUser(name, role = 'member') {
  return { name, role, createdAt: Date.now() }; // assemble et rend l'objet
}

L'adaptateur

Du code qui sert d'intermédiaire entre deux mondes qui ne parlent pas la même langue : par exemple, transformer la forme des données renvoyées par un serveur en la forme qu'attend ton interface. Comment le reconnaître : une fonction qui prend un objet d'une forme et en renvoie un autre de forme différente, sans logique métier — juste du « renommage » et de la réorganisation de champs. L'intention : isoler ton code des formats externes, pour que si le serveur change, tu n'aies à corriger qu'un seul endroit.

// transforme la forme "serveur" en forme "app"
function toUser(row) {
  return { id: row.user_id, name: row.full_name }; // adapte les noms de champs
}

Le hook personnalisé

Spécifique à React, mais omniprésent dans ton app. Une fonction dont le nom commence par use (useAuth, useWorkout…) et qui regroupe un morceau de logique réutilisable lié à l'état ou au cycle de vie d'un composant. Comment le reconnaître : le préfixe use, et à l'intérieur d'autres hooks (useState, useEffect). L'intention : extraire une logique d'écran pour la partager entre plusieurs composants. On y consacre tout un module plus loin ; pour l'instant, retiens juste : « use au début = hook = logique d'interface réutilisable ».

💡 Le concept

Ces noms ne sont pas du jargon pour faire savant : ce sont des raccourcis de pensée. Le jour où tu vois « garde » au lieu de « une suite de if avec des return », tu lis deux fois plus vite, parce que ton cerveau traite un seul concept au lieu de cinq lignes. Construire ton vocabulaire de patterns, c'est littéralement augmenter ta vitesse de lecture.

Quand tu es vraiment bloqué

Ça arrivera, même avec la méthode. Un fichier dense, une fonction qui t'échappe, un comportement que tu n'arrives pas à expliquer. Voici une trousse de techniques concrètes à essayer, dans un ordre raisonnable, du plus simple au plus laborieux. Le but n'est pas de tout appliquer : c'est d'avoir des options quand le premier réflexe ne suffit pas.

  • La recherche dichotomique (couper le problème en deux). Tu ne comprends pas une fonction de 40 lignes ? Ne la prends pas en entier. Demande-toi : « la confusion est-elle dans la première moitié ou la seconde ? ». Mets un repère mental au milieu, vérifie ce que tu crois savoir à ce point-là, et continue à couper la zone douteuse en deux jusqu'à tomber sur LA ligne qui te bloque. C'est la même idée que chercher un mot dans un dictionnaire : tu n'ouvres pas page par page.
  • Lire les types et signatures. Quand le corps est obscur, remonte à la signature : que prend la fonction, que rend-elle ? Souvent, le type de retour à lui seul te dit l'intention et tu peux traiter le corps comme une boîte noire. « Ça rend un string | null : c'est donc un validateur, peu importe comment il s'y prend. »
  • Suivre les noms. Une variable t'intrigue ? Cherche où elle est créée et où elle est utilisée. Le voyage d'une donnée à travers le fichier raconte presque toujours l'histoire mieux que la lecture linéaire. Tu suis le fil, pas les lignes.
  • Isoler un seul scénario. C'est le temps 5, en version « secours ». Quand tout se mélange, fige des valeurs concrètes (« et si l'email était exactement "a@b.c" ? ») et avance pas à pas avec ces valeurs en main. Le concret dissout l'abstrait.
  • Utiliser « aller à la définition » dans l'éditeur. Un nom que tu ne connais pas (ValidationError, une fonction importée) ? Clic droit, « aller à la définition » (ou F12 dans la plupart des éditeurs). Tu sautes directement à l'endroit où la chose est définie, au lieu de deviner. C'est l'outil le plus sous-utilisé des débutants, et le plus puissant.
  • Lire les commentaires d'en-tête. Beaucoup de fichiers commencent par un bloc de commentaire qui explique leur rôle et donne des exemples d'usage. C'est l'auteur qui te parle directement. Ne le saute jamais : c'est souvent le résumé que tu cherchais.
  • Lire les tests, s'ils existent. Un fichier de test est une documentation vivante : chaque test décrit une entrée et le résultat attendu. Si tu ne comprends pas ce que fait getPasswordError, le test te montrera noir sur blanc « avec ceci, on attend cela ». C'est parfois la façon la plus rapide de comprendre une fonction : par ses exemples.
🏋️ Dans Halterofit

Le fichier auth.ts que tu viens de lire commence justement par un bloc d'en-tête qui explique son usage en deux exemples : « dans les écrans, vérifie le résultat » et « dans la couche service, ça lève une erreur ». C'est la technique « lire les commentaires d'en-tête » en action : l'auteur t'a résumé le fichier avant même que tu l'ouvres. Prends le réflexe de lire ces blocs en premier dans toute l'app.

Les questions à se poser

Pour finir, voici une checklist mentale réutilisable. Ce n'est pas une liste à cocher religieusement : c'est un jeu de questions à te poser quand tu ouvres n'importe quel fichier, dans n'importe quel projet. Avec le temps, elles deviendront automatiques et tu ne les « poseras » plus consciemment — mais au début, les avoir en tête te sort du « je lis sans savoir où je vais ».

  1. De quoi ce fichier dépend-il ? (les imports) — touche-t-il à l'écran, au réseau, à la base, ou est-il pur ?
  2. Qu'offre-t-il au reste de l'app ? (les exports) — quelle est sa mission en une phrase ?
  3. Quelle est la forme des données ? (les signatures) — ce qui entre, ce qui sort.
  4. Quelle est sa structure d'ensemble ? (le survol des noms) — quels sont les grands blocs ?
  5. Que se passe-t-il pour UN cas concret ? (tracer un chemin) — choisis un scénario et deviens la donnée.
  6. À quoi cela ressemble-t-il que je connais déjà ? (nommer le pattern) — garde, transformation, validation, fabrique… ?
  7. Et la question qui chapeaute tout : quelle intention l'auteur essayait-il de réaliser ?
✍️ Exercice de lecture

Voici une fonction du même fichier que tu n'as pas encore vue en détail. Applique la méthode : lis d'abord sa signature, puis trace un chemin, puis nomme son pattern.

export function getPasswordConfirmError(
  password: string,
  confirm: string,
): string | null {
  if (confirm.length === 0) {
    return 'Please confirm your password';
  }
  if (password !== confirm) {
    return 'Passwords do not match';
  }
  return null;
}

Questions : (1) Dans quel cas cette fonction retourne-t-elle null ? (2) Si l'utilisateur laisse le champ de confirmation vide, quel message obtient-il, et pourquoi ce test est-il en premier ? (3) À quel pattern de la section précédente cette fonction appartient-elle ?

Voir le corrigé

(1) Elle retourne null (= « pas d'erreur ») uniquement quand les deux conditions de problème sont fausses : le champ n'est pas vide ET password === confirm. null est le cas « tout va bien », atteint en tombant tout en bas, une fois toutes les gardes franchies.

(2) Il obtient « Please confirm your password ». Le test du champ vide est placé en premier parce que c'est l'erreur la plus précise et la plus utile : dire « les mots de passe ne correspondent pas » alors que le champ est simplement vide serait déroutant. C'est le pattern « garde la plus spécifique d'abord », qu'on retrouve partout dans le code.

(3) C'est le pattern des gardes (early return), doublé du pattern de validation : une suite de if qui sortent dès qu'un problème est détecté, et le cas normal (null) tout en bas. Tu viens de nommer le pattern — temps 6 réussi.

🧠 Quiz éclair

1. Quelle est la toute première chose à regarder dans un fichier inconnu ?

Les imports (temps 1) : ils révèlent immédiatement les dépendances du fichier, donc sa nature (logique pure, écran, accès aux données…). En dix secondes, tu connais la catégorie du fichier.

2. Que signifie une signature (email: string): string | null ?

La fonction prend une chaîne et retourne soit une chaîne (un message d'erreur) soit null. Par convention ici, null veut dire « valide, aucune erreur ».

3. Tu te sens noyé dans un fichier. Que faire selon la méthode ?

Remonter d'une étape. Tu es sûrement passé trop vite aux détails (temps 5) sans avoir survolé (temps 1 à 4). Reviens aux imports/exports/signatures, refais ta carte, puis ne trace qu'un seul chemin.

4. Pourquoi dit-on que « lire n'est pas écrire » ?

Parce que ce sont deux compétences distinctes. En écrivant, tu pars de ton intention et tu la traduis en code. En lisant, tu fais le chemin inverse : tu n'as que le code et tu dois reconstruire l'intention de l'auteur. Lire, c'est deviner le « pourquoi » derrière chaque ligne, pas seulement décoder la syntaxe.

5. Tu vois une fonction nommée createWorkout(options) qui assemble et retourne un objet. Quel pattern reconnais-tu ?

Une fabrique (factory). Le préfixe create… et le fait qu'elle construise puis retourne un objet à partir de paramètres sont les signes typiques. Son intention : centraliser le montage de l'objet pour que le reste du code n'ait pas à en connaître les détails.

À retenir

Lire du code = survoler d'abord, plonger ensuite. Ordre fixe : imports → exports → signatures → noms → un seul chemin → nommer le pattern. Tu n'as jamais besoin de tout comprendre en même temps. Lire, c'est reconstruire l'intention de l'auteur, pas décoder une syntaxe. Et quand tu reconnais un pattern (garde, transformation, validation, fabrique, adaptateur, hook), tu lis deux fois plus vite.

⚠️ Piège fréquent

Vouloir comprendre chaque ligne du premier coup, de haut en bas. C'est épuisant et inefficace. Personne ne lit le code comme ça — même pas ceux qui l'ont écrit. Si tu te noies, ce n'est pas que tu es nul : c'est le signal que tu as sauté le survol et plongé trop tôt dans les détails. Remonte, et tout redevient gérable.

🔄 Transférable

Cette méthode marche pour n'importe quel langage et n'importe quel projet. Imports/exports/signatures existent partout (Python, Java, Go…), et les patterns (gardes, transformations, fabriques, adaptateurs) sont universels. Les techniques de déblocage — recherche dichotomique, « aller à la définition », lire les tests — te serviront toute ta carrière, pas juste pour Halterofit.