Back home

Swift Concurrency Series 02|Problèmes résolus par async/await

Il s'agit de faire retrouver au système asynchrone les conditions d'une maintenance à long terme

Si l’on regarde seulement la surface, async/await semble résoudre principalement trois problèmes :

  • trop de rappels
  • Nidification trop profonde
  • Le code est trop moche

Mais après l’avoir utilisé dans le projet pendant un certain temps, vous constaterez que ce ne sont que des apparences. Ce que cela résout réellement, c’est : **Les activités asynchrones peuvent enfin être organisées, raisonnées et réutilisées comme des activités normales. **

Il s’agit d’un changement de maintenabilité technique.

1. La première chose que cela résout est la suivante : les processus métier ne sont plus détournés par les méthodes d’écriture

De nombreuses entreprises asynchrones elles-mêmes ne sont pas compliquées. Ce qui est compliqué, c’est que l’ancienne méthode d’écriture rend les choses compliquées.

Par exemple, un processus réel mais courant :

  1. Extraire les informations utilisateur
  2. Vérifiez le statut de membre
  3. Extrayez le contenu recommandé sur la page d’accueil
  4. Si l’une des étapes échoue, revenez à l’affichage complet
  5. Dernier état de la page mise à jour

Cela aurait été un processus séquentiel très clair.

Mais à l’ère de l’achèvement, nous devons souvent d’abord régler ces « problèmes d’écriture » :

  • Où est écrite la branche réussie ?
  • Où est écrite la branche défaillante ?
  • Où est écrit le changement de thread principal ?
  • Quelle couche est responsable du retour anticipé ? -Quelle couche est responsable des erreurs de bombe unificatrice ?

La complexité ne vient alors plus du métier, mais de l’expression elle-même. async/await L’avantage le plus direct est de supprimer cette couche de bruit supplémentaire et de restituer la complexité métier à l’entreprise elle-même.

2. Cela rend la « dépendance » à nouveau claire

De nombreux processus asynchrones sont fortement dépendants.

Par exemple :

  • Ce n’est qu’après avoir obtenu le statut de connexion que vous pourrez obtenir les informations utilisateur
  • Ce n’est qu’après avoir obtenu les informations utilisateur que vous pourrez décider quels modules charger sur la page d’accueil.
  • Ce n’est qu’après avoir obtenu la configuration expérimentale que vous pourrez décider du chemin d’affichage de la page

Bien sûr, la complétion peut également exprimer ces relations, mais le problème est le suivant : elle cache souvent les dépendances dans des couches d’imbrication. Le code peut s’exécuter, mais la chaîne de dépendances n’est plus claire.

L’une des valeurs fondamentales du async/await est de ramener cette relation « qui dépend de qui » à un flux de contrôle linéaire :

let session = try await authService.loadSession()
let user = try await userService.loadUser(session: session)
let modules = try await homeService.loadModules(for: user)

La valeur de ce code n’est pas seulement qu’il est beau, mais qu’il peut être vu immédiatement :

  • Relation séquentielle
  • point de rupture
  • Quelle étape pourrait être erronée ?

Cela affectera directement votre confiance lors de la modification ultérieure des exigences, car vous pourrez enfin déterminer où se trouve la section que vous déplacez dans l’ensemble du lien.

3. Cela améliore considérablement la propagation des erreurs

Dans l’ancien modèle asynchrone, la gestion des erreurs était la plus fragile.

Étant donné que chaque niveau d’achèvement peut échouer, cela aboutit souvent à cette situation :

  • Un ensemble de gestion en cas d’échec des requêtes de premier niveau
  • Un autre ensemble de traitements pour la défaillance de la deuxième couche
  • Si le troisième niveau échoue, essayez-en un autre.
  • Certains endroits l’ont mal avalé
  • Faire griller des toasts à certains endroits
  • Certains endroits enregistrent uniquement

Vous constaterez que le vrai problème est que le chemin d’erreur est divisé comme le processus principal.

async/await donne au moins un modèle unifié de propagation des erreurs :

  • Jetez cette couche
  • Continuez simplement à lancer vers le haut
  • Responsabilité unifiée des niveaux supérieurs

En d’autres termes, il ne décide pas pour l’équipe « comment gérer les erreurs », mais il rend au moins clair « comment les erreurs circulent ». Ceci est particulièrement important pour les frontières commerciales.

4. Il expose explicitement le point de pause

Une situation courante consiste à ignorer la signification la plus importante de await : C’est un rappel.

C’est révélateur :

  • Pause possible ici
  • Le contexte ici peut varier
  • Le code suivant ne doit pas être exactement dans le même environnement par défaut

C’est la clé de la pensée concurrente.

Car le vrai danger du code asynchrone est qu’après l’avoir appelé, on pense souvent inconsciemment :

  • La page actuelle est toujours là
  • Le statut actuel n’a pas changé
  • L’objet actuel reste intact

Et await marque au moins clairement « c’est la limite » grammaticalement. Cela vous obligera à commencer à réfléchir sérieusement à la validité de l’état, plutôt que de traiter l’asynchrone comme un appel de fonction ordinaire.

5. Cela facilite la saisie de la conception principale au lieu de la logique du plug-in.

Dans le passé, de nombreux codes pouvaient également effectuer une annulation, mais l’annulation était généralement comme une fonction de rattrapage :

  • Enregistrez un jeton séparément
  • Pensez à annuler lorsque la page est détruite
  • Arrêtez manuellement les anciennes requêtes dans certains scénarios

Est-ce possible ? Bien sûr que vous le pouvez. Mais le problème est que l’annulation dans l’ancien modèle ne fait souvent pas partie du processus principal, mais comme un correctif externe.

Dans Swift Concurrency, les tâches et l’annulation sont enfin plus naturellement considérées comme un ensemble de choses. Cela oblige à poser plusieurs questions clés plus tôt :

  • À qui appartient cette tâche ?
  • Doit-il s’arrêter lorsque la page est quittée ?
  • De nouvelles tâches arrivent, les anciennes tâches devraient-elles devenir invalides ?

Cela ne contribue pas automatiquement à une annulation correcte, mais cela met en évidence le fait que l’annulation doit être intégrée dans le processus.

6. Cela améliore non seulement l’expérience personnelle, mais également la cohérence de la collaboration en équipe.

Il s’agit d’une situation courante qui est sous-estimée.

Lorsqu’une personne écrit du code, la différence entre l’achèvement et async/await ne peut se refléter que dans la fluidité. Mais dans les projets de collaboration à plusieurs personnes, ce qui est vraiment important avec le async/await, c’est qu’il rend l’expression de l’équipe plus unifiée.

Maintenant, au moins, il est possible d’utiliser par défaut :

  • Les capacités asynchrones apparaîtront dans la fonction async
  • Échec avec throw
  • Utilisez await pour le point de pause

Cette unification est très importante. Car la plus grande crainte dans les projets complexes, c’est que chacun utilise son propre mode d’organisation asynchrone. Tôt ou tard, le projet deviendra réalisable, mais personne ne pourra le reprendre rapidement.

7. Ça ne résout rien

À ce stade, nous devons également préciser que async/await ne résout pas ces problèmes :

  • Cela n’élimine pas automatiquement les conditions de concurrence
  • N’empêche pas automatiquement les anciennes requêtes d’écraser les nouveaux résultats
  • Ne décidera pas pour l’équipe comment les limites de statut doivent être tracées
  • Ne garantit pas automatiquement que les mises à jour de l’interface utilisateur se produisent dans le contexte correct

Ainsi, si la conception asynchrone originale d’un projet est très désordonnée, il serait peut-être simplement « préférable d’avoir l’air désordonné » après son remplacement par async/await.

Cela doit être vu clairement. async/await n’est pas une panacée architecturale, il met simplement en lumière de nombreux problèmes initialement dissimulés par l’écriture.

8. Conclusion : ce que cela résout, c’est “Le code asynchrone peut-il encore être conservé pendant une longue période ?”

Pour le dire sous une forme plus courte, je dirais :

async/await La vraie solution est que le code asynchrone devient de plus en plus difficile à organiser, à raisonner et à maintenir dans des projets complexes.

Une déclaration plus précise n’est donc pas :

“Cela rend le code plus court.”

Au lieu de cela :

“Cela ramène le code asynchrone à l’état structurel pour une maintenabilité à long terme.”

FAQ

What to read next

Related

Continue reading