/* Page prose (fr) */
"ClassicModernInPractice" = "# Classique et moderne en pratique\n\n## La carte des concepts\n\nPresque chaque outil classique a une contrepartie moderne directe. Quand tu lis de l'ancien code, ou que tu le migres, voici la table de traduction:\n\n* Un completion handler, `(Result<T,E>) -> Void`, ➡️ une fonction `async throws -> T`. Le résultat revient *comme* une valeur de retour; les erreurs font `throw`.\n* `DispatchQueue.global().async { }` ➡️ `Task { }` / le pool coopératif. Tu décris le *travail*, pas *quelle file*.\n* `DispatchGroup` / `semaphore.wait()` pour un lot ➡️ `async let` (ensemble fixe) ou `TaskGroup` (ensemble dynamique). La jonction est structurelle; aucun compteur à équilibrer.\n* Une file en série utilisée pour protéger un état partagé ➡️ un **`actor`**. L'isolation est imposée par le type, pas par la discipline.\n* `DispatchQueue.main.async { }` ➡️ **`@MainActor`**. L'appartenance au thread principal fait partie de la signature.\n* `Operation` avec des vérifications manuelles de `isCancelled` ➡️ **annulation coopérative de `Task`** (`Task.isCancelled` / `try Task.checkCancellation()`). L'annulation se propage vers le bas de l'arbre de tâches automatiquement.\n* Un delegate ou un callback qui se déclenche plusieurs fois ➡️ **`AsyncStream`** (ou une **continuation** pour un seul déclenchement). Les événements deviennent une boucle `for await` dont tu peux faire `break`.\n\nDeux choses qui valent la peine d'être soulignées:\n\nPremièrement, **`async let` et `TaskGroup` remplacent tous les deux `DispatchGroup`**: choisis `async let` quand tu connais les récupérations d'avance (comme nos deux ici), et `TaskGroup` quand le nombre est décidé à l'exécution.\n\nDeuxièmement, **l'actor est le héros silencieux**: la chose la plus propice aux bugs du modèle classique (une file en série ou un sémaphore de compte 1 protégeant un état partagé, par lequel tu devais penser à router chaque accès) devient un type que le compilateur surveille pour toi.\n\n---\n\n## Quand utiliser encore le modèle classique\n\nLe modèle moderne est celui par défaut pour le code neuf. Mais \"le classique est mort\" serait faux et te pousserait vers des réécritures inutiles. Tourne-toi vers (ou conserve) GCD et `Operation` quand:\n\n* **Tu appelles des APIs plus anciennes.**  \nBeaucoup de frameworks (et ton propre code plus ancien) te tendent encore des completion handlers ou des delegates. Tu *interopères* avec eux; tu n'as pas à convertir le monde entier d'abord. (Le geste propre est de les envelopper; vois la page suivante.)\n* **Tu as besoin d'un contrôle de dispatch très fin.**  \nUne file en série personnalisée précise avec une QoS précise, un `DispatchSource` pour un fichier ou un timer, un bloc de barrière sur une file concurrente. Ceux-ci restent légitimes, et parfois l'outil le plus direct. Le pool coopératif cache volontairement les détails des threads; quand tu as vraiment besoin de ces détails, GCD est juste là.\n* **Tu cibles des versions d'OS antérieures à `async`/`await`.**  \nLa concurrence Swift tourne sur iOS 13 et versions ultérieures (et les équivalents macOS 10.15, tvOS 13, watchOS 6). Comme iOS 13 est sorti en 2019, cette raison est maintenant rare, mais si une cible de déploiement descend encore en dessous de cette ligne, GCD est ton option portable.\n* **Le code fonctionne déjà et tu ne l'as pas encore migré.**  \nDu GCD qui fonctionne n'est pas un bug. Réécrire du code stable purement pour le moderniser ajoute du risque sans gain visible pour l'utilisateur. Migre là où tu changes déjà des choses, pas partout à la fois.\n\nÊtre honnête là-dessus a de l'importance: le but est un code *correct et maintenable*, pas une base de code 100 % moderne pour elle-même.\n\n[Précédent](@previous)  |  page 5 sur 8  |  [Suivant: Une stratégie de migration pragmatique](@next)";
