Confusão no início: post-mortem na velocidade de lançamento de um aplicativo iOS

Um aplicativo moderno possui muitos requisitos não funcionais: tamanho do aplicativo, tráfego consumido, acessibilidade para pessoas com deficiência, estabilidade, inicialização e velocidade de operação. Nosso aplicativo foi iniciado por muito tempo, dezenas de segundos. Hoje foi lançada uma atualização na qual o aplicativo iOS começou a rodar muitas vezes mais rápido. Eu digo a você como aconteceu e por que apenas agora.



Começa por um longo tempo


O aplicativo tem muito código, muitas classes e elas estão de alguma forma conectadas. Para gerenciar esses relacionamentos, usamos Dip (leia-se: Swinject ou qualquer outra estrutura de DI sem geração de código).

Funciona assim: no início do aplicativo, todas as dependências são amontoadas no "contêiner" e, em seguida, a classe desejada é extraída dele com todas as dependências descartadas. Leva tempo para começar, leva tempo para abrir qualquer tela.

Mas as fotos são lindas


Durante muito tempo, nem nos assustou: acabamos de desenhar belos protetores de tela com novas pizzas e não cozinhamos a vapor. Os protetores de tela para pizza tiveram que ser removidos quando começamos em vários países, porque a variedade é diferente em todos os lugares. A imagem não se tornou tão interessante, esperar o lançamento se tornou mais chato, mas perdemos esse ponto.

Aqui estão nossos salpicos. Bonito, mas escondendo um problema que nem tentamos resolver.



Após o próximo lançamento, começamos a desacelerar a troca de cartões no controlador de página. O perfilador de tempo mostrou que as dependências são removidas por um longo tempo quando uma nova tela aparece. Porque É impossível entender. É muito difícil depurar o Dip devido às mesmas chamadas abstratas. Tentamos dividir um contêiner comum em muitos pequenos, mas só piorou. Como resultado, desligamos os cartões invertidos e continuamos as atualizações de Ano Novo.

É assim que o Dip se parece no criador de perfil. No final da lista, é atingido o limite da pilha de chamadas. É impossível fazer algo razoável com isso.



Voa para 4S? Corrigir mais tarde


No momento, o bug "não iniciou a compilação do lançamento no 4S" estava no backlog, embora os de depuração tivessem sido lançados. Ninguém notou a conexão dos problemas, elevou a versão mínima do iOS para 10 e também adiou as alterações. Existem poucos usuários no 4S, certo?

Vimos Dip: não no começo, mas na compilação


No entanto, ficou claro que Dip precisava ser cortado. E o que mudar? Em tempo hábil, vimos o artigo Injeção de Dependência em Swift .

Funciona simplesmente: escrevemos várias funções resolve() com um tipo diferente (o compilador descobrirá isso). Portanto, as comunicações deixarão de ser calculadas no início e o compilador poderá otimizar o código. Isso também é útil para o desenvolvimento: se você descreveu as dependências incorretamente, descobrirá sobre isso na inicialização, e não quando abrir a tela. Obviamente, existem problemas: se a função resolve() não entender o tipo, produzirá um erro tão inútil com cem candidatos:



Fizemos isso em novembro. Houve MUITAS mudanças, e naquele momento lançamos o novo produto Combo e nos preparamos para as alterações mais recentes antes do Ano Novo. O novo código apareceu no projeto antes do Ano Novo, mas não o liberamos até janeiro devido ao congelamento de código antes do feriado. Por isso, por três semanas, usamos o programa no modo de teste, encontramos problemas e os corrigimos.

É assim que o código de dependência parece agora. Sujo, mas trabalhando. 450 lugares com registro e 1400 lugares com extração.



Funcionalmente, o código é o mesmo, apenas a maneira de trabalhar com ele é diferente. A diferença de velocidade é visível em todos os modelos. No XS - duas vezes mais rápido, e no SE, veja você mesmo:


Por isso, aceleramos não apenas o início, mas também a abertura das telas. Antes das alterações, cada tela levava de 0,3 a 1 segundos apenas na dependência.

Ano novo sem pizza


Em dezembro, eles começaram a escrever para nós que o aplicativo falha na inicialização, não inicia e, após reiniciar, a reinstalação não ajuda. Anteriormente, havia apenas uma razão para isso - migrações de banco de dados, mas nos livramos disso e não vimos novas partidas no Crashlytics. O que deu errado?


Hipótese: esse iOS descarta os aplicativos se eles forem executados por um longo período de tempo. A versão foi confirmada pelo fato de que todas as análises eram de dispositivos antigos: 5, 5S, 6. O número dessas análises aumentou significativamente, porque a pizza é um feriado, as pessoas costumam pedir no Ano Novo. A equipe está preocupada, o produto está preocupado, mas estamos lançando a nova versão somente em janeiro.

Tivemos a sorte de que a solução foi escrita e só pôde ser testada. Em outro cenário, meses podem ser gastos procurando causas e corrigindo-as.



Às vezes, é difícil transmitir a importância de uma tarefa técnica para uma empresa: não há métricas, a importância não é clara, o perigo não é previsto. As empresas podem resolver o problema de diferentes maneiras: é assim que pintamos belas imagens, em vez de acelerar o aplicativo. Mas o desempenho é importante para todos os usuários. Isso afeta muito:

  • Esperando. Se o aplicativo iniciar por um longo tempo, quanto tempo eles levarão pizza?
  • O prazer de usar. Por que estúpido em todas as telas?
  • E mesmo para estabilidade. “O aplicativo não está sendo executado !!! Desenvolvedores, vocês testam aí? ”(C).

E ignore o Dip, o Swinject e outras estruturas que funcionam com contêineres em tempo real se você tiver um projeto grande e muitas dependências.
Para não perder o próximo artigo, assine o canal Dodo Pizza Mobile.

Source: https://habr.com/ru/post/pt485200/


All Articles