Back home

Swift Concurrency Series 02|Problemas resolvidos por async/await

É fazer com que o sistema assíncrono recupere as condições de manutenção a longo prazo

Se você olhar apenas para a superfície, o async/await parece resolver principalmente três problemas:

  • muitos retornos de chamada
  • Aninhamento muito profundo
  • O código é muito feio

Mas depois de realmente usá-lo no projeto por um período de tempo, você descobrirá que são apenas aparências. O que isso realmente resolve é: **Os negócios assíncronos podem finalmente ser organizados, fundamentados e reutilizados como negócios normais. **

Esta é uma mudança de manutenção de engenharia.

1. A primeira coisa que resolve é: os processos de negócios não são mais sequestrados por métodos de escrita

Muitos negócios assíncronos em si não são complicados. O que é complicado é que o antigo método de escrita torna tudo complicado.

Por exemplo, um processo real, mas comum:

  1. Extraia informações do usuário
  2. Verifique o status da associação
  3. Extraia conteúdo recomendado na página inicial
  4. Se uma das etapas falhar, volte para a exibição completa
  5. Status da última página atualizada

Este teria sido um processo sequencial muito claro.

Mas na era da conclusão, muitas vezes temos que lidar primeiro com estas “questões de escrita”:

  • Onde está escrito o ramo de sucesso?
  • Onde está escrito o branch com falha?
  • Onde está escrita a troca de thread principal?
  • Qual camada é responsável pelo retorno antecipado? -Qual camada é responsável por unificar os erros das bombas?

Aí a complexidade não vem mais do negócio, mas da própria expressão. async/await O benefício mais direto é remover essa camada extra de ruído e devolver a complexidade do negócio ao próprio negócio.

2. Deixa a “dependência” clara novamente

Muitos processos assíncronos são fortemente dependentes.

Por exemplo:

  • Somente depois de obter o status de login você poderá obter as informações do usuário
  • Somente após obter as informações do usuário você poderá decidir quais módulos carregar na página inicial.
  • Somente após obter a configuração experimental você poderá decidir o caminho de exibição da página

É claro que a conclusão também pode expressar esses relacionamentos, mas o problema é: muitas vezes ela esconde dependências em camadas de aninhamento. O código pode ser executado, mas a cadeia de dependências não está mais clara.

Um dos valores fundamentais do async/await é trazer esse relacionamento “quem depende de quem” de volta a um fluxo de controle linear:

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

O valor deste código não é apenas ter uma boa aparência, mas também poder ser visto imediatamente:

  • Relacionamento sequencial
  • ponto de ruptura
  • Qual passo pode estar errado?

Isso afetará diretamente sua confiança ao modificar os requisitos posteriormente, porque você pode finalmente determinar onde está a seção que está movendo em todo o link.

3. Melhora significativamente a propagação de erros

No antigo modelo assíncrono, o tratamento de erros era o mais frágil.

Como todos os níveis de conclusão podem falhar, isso geralmente termina nesta situação:

  • Um conjunto de tratamento para falha de solicitação de primeiro nível
  • Outro conjunto de tratamentos para falha da segunda camada
  • Se o terceiro nível falhar, tente outro.
  • Alguns lugares engoliram errado
  • Faça brindes em alguns lugares
  • Alguns lugares apenas registram

Você descobrirá que o verdadeiro problema é que o caminho do erro está dividido como o processo principal.

async/await fornece pelo menos um modelo unificado de propagação de erros:

  • Descarte esta camada
  • Continue jogando para cima
  • Responsabilidade unificada de níveis superiores

Em outras palavras, não decide para a equipe “como lidar com os erros”, mas pelo menos deixa claro “como os erros fluem” novamente. Isto é especialmente importante para limites de negócios.

4. Expõe explicitamente o ponto de pausa

Uma situação comum é ignorar o significado mais importante de await: É um lembrete.

Está dizendo:

  • Possível pausa aqui
  • O contexto aqui pode variar
  • O código depois disso não deve estar exatamente no mesmo ambiente por padrão

Esta é a chave para o pensamento simultâneo.

Porque o perigo real do código assíncrono é que, depois de chamá-lo, você muitas vezes pensa subconscientemente:

  • A página atual ainda está lá
  • O status atual não mudou
  • O objeto atual permanece intacto

E await pelo menos marca claramente “este é o limite” gramaticalmente. Isso forçará você a começar a pensar seriamente sobre a validade do estado, em vez de tratar o assíncrono como uma chamada de função comum.

5. Torna mais fácil inserir o design principal em vez da lógica do plug-in.

No passado, muitos códigos também podiam cancelar, mas o cancelamento geralmente era como uma função de atualização:

  • Salve um token separadamente
  • Lembre-se de cancelar quando a página for destruída
  • Interrompa manualmente solicitações antigas em alguns cenários

Isso pode ser feito? Claro que você pode. Mas o problema é que o cancelamento no modelo antigo muitas vezes não faz parte do processo principal, mas sim como um patch externo.

No Swift Concurrency, tarefas e cancelamento são finalmente vistos de forma mais natural como um conjunto de coisas. Isso força várias perguntas importantes a serem feitas anteriormente:

  • Quem é o dono desta tarefa?
  • Deve parar quando a página for abandonada?
  • Novas tarefas estão chegando. As tarefas antigas deveriam se tornar inválidas?

Isso não ajuda automaticamente a acertar o cancelamento, mas traz à tona o fato de que o cancelamento deve ser incluído nele.

6. Melhora não apenas a experiência pessoal, mas também a consistência da colaboração em equipe.

Esta é uma situação comum que é subestimada.

Quando uma pessoa escreve código, a diferença entre conclusão e async/await só pode ser refletida na suavidade. Mas em projetos de colaboração entre várias pessoas, o que é realmente importante no async/await é que ele torna a expressão da equipe mais unificada.

Agora, pelo menos, é possível padronizar:

  • Os recursos assíncronos aparecerão na função async
  • Falha com throw
  • Use await para ponto de pausa

Esta unificação é muito importante. Porque o maior medo em projetos complexos é que cada um utilize seu próprio método de organização assíncrona. Mais cedo ou mais tarde, o projeto se tornará executável, mas ninguém será capaz de assumi-lo rapidamente.

7. Não resolve nada

Neste ponto, também devemos deixar claro que async/await não resolve estes problemas:

  • Não elimina automaticamente as condições de corrida
  • Não impede automaticamente que solicitações antigas substituam novos resultados
  • Não decidirá pela equipe como os limites de status devem ser traçados
  • Não garante automaticamente que as atualizações da UI ocorram no contexto correto

Portanto, se o design assíncrono original de um projeto for muito confuso, pode ser “melhor parecer confuso” depois de ser substituído por async/await.

Isto deve ser visto claramente. async/await não é uma panacéia arquitetônica, apenas ilumina muitos problemas que foram originalmente encobertos pela escrita.

8. Conclusão: O que isso resolve é “O código assíncrono ainda pode ser mantido por muito tempo?”

Para resumir, eu diria:

async/await A solução real é que o código assíncrono se torna cada vez mais difícil de organizar, raciocinar e manter em projetos complexos.

Portanto, uma afirmação mais precisa não é:

“Isso torna o código mais curto.”

Em vez disso:

“Ele traz o código assíncrono de volta à condição estrutural para manutenção a longo prazo.”

FAQ

What to read next

Related

Continue reading