Evolução do CI na equipe de desenvolvimento mobile

Hoje, a maioria dos produtos de software são desenvolvidos em equipes. As condições para o desenvolvimento bem-sucedido da equipe podem ser representadas na forma de um diagrama simples.

Evolução do CI na equipe de desenvolvimento mobile

Depois de escrever seu código, você precisa ter certeza de que:

  1. Funciona.
  2. Não quebra nada, inclusive o código que seus colegas escreveram.

Se ambas as condições forem atendidas, você estará no caminho do sucesso. Para verificar facilmente essas condições e não nos desviarmos do caminho lucrativo, criamos a Integração Contínua.

CI é um fluxo de trabalho onde você integra seu código ao código geral do produto com a maior freqüência possível. E você não apenas integra, mas também verifica constantemente se tudo está funcionando. Como você precisa verificar muito e com frequência, vale a pena pensar em automação. Você pode verificar tudo manualmente, mas não deveria, e aqui está o porquê.

  • queridas pessoas. Uma hora de trabalho de qualquer programador custa mais do que uma hora de trabalho de qualquer servidor.
  • Pessoas cometem erros. Portanto, podem surgir situações quando os testes foram executados no branch errado ou o commit errado foi compilado para os testadores.
  • As pessoas são preguiçosas. De vez em quando, quando termino uma tarefa, surge o pensamento: “O que há para verificar? Escrevi duas linhas - tudo funciona! Acho que alguns de vocês às vezes também têm esses pensamentos. Mas você deve sempre verificar.

Como a Integração Contínua foi implementada e desenvolvida na equipe de desenvolvimento móvel da Avito, como eles passaram de 0 a 450 builds por dia, e que máquinas de construção montam 200 horas por dia, diz Nikolai Nesterov (nesterov) é participante de todas as mudanças evolutivas do aplicativo Android CI/CD.

A história é baseada no exemplo de um comando Android, mas a maioria das abordagens também se aplica ao iOS.


Era uma vez uma pessoa que trabalhava na equipe Avito Android. Por definição, ele não precisava de nada da Integração Contínua: não havia ninguém com quem se integrar.

Mas a aplicação cresceu, surgiram cada vez mais novas tarefas e a equipa cresceu em conformidade. Em algum momento, é hora de estabelecer mais formalmente um processo de integração de código. Decidiu-se usar o fluxo Git.

Evolução do CI na equipe de desenvolvimento mobile

O conceito de fluxo Git é bem conhecido: um projeto tem uma ramificação de desenvolvimento comum e, para cada novo recurso, os desenvolvedores cortam uma ramificação separada, comprometem-se com ela, enviam push e, quando desejam mesclar seu código na ramificação de desenvolvimento, abrem um solicitação de pull. Para compartilhar conhecimento e discutir abordagens, introduzimos a revisão de código, ou seja, os colegas devem verificar e confirmar o código uns dos outros.

Cheques

Ver o código com os olhos é legal, mas não o suficiente. Portanto, estão sendo introduzidas verificações automáticas.

  • Em primeiro lugar, verificamos Montagem ARCA.
  • Muito Testes Junit.
  • Consideramos cobertura de código, já que estamos executando testes.

Para entender como essas verificações devem ser executadas, vejamos o processo de desenvolvimento no Avito.

Pode ser representado esquematicamente assim:

  • Um desenvolvedor escreve código em seu laptop. Você pode executar verificações de integração aqui mesmo - com um gancho de commit ou simplesmente executar verificações em segundo plano.
  • Depois que o desenvolvedor envia o código, ele abre uma solicitação pull. Para que seu código seja incluído no branch de desenvolvimento, é necessário passar por uma revisão de código e coletar o número necessário de confirmações. Você pode habilitar verificações e compilações aqui: até que todas as compilações sejam bem-sucedidas, a solicitação pull não poderá ser mesclada.
  • Depois que a solicitação pull for mesclada e o código incluído no desenvolvimento, você pode escolher um horário conveniente: por exemplo, à noite, quando todos os servidores estão livres, e executar quantas verificações desejar.

Ninguém gostava de fazer varreduras em seus laptops. Quando um desenvolvedor termina um recurso, ele deseja enviá-lo rapidamente e abrir uma solicitação pull. Se neste momento são iniciadas algumas verificações longas, isso não só não é muito agradável, mas também retarda o desenvolvimento: enquanto o laptop está verificando alguma coisa, é impossível trabalhar nele normalmente.

Gostamos muito de fazer verificações à noite, porque há muito tempo e servidores, você pode passear. Mas, infelizmente, quando o código do recurso entra em desenvolvimento, o desenvolvedor tem muito menos motivação para corrigir os erros encontrados pelo CI. Periodicamente, ao olhar todos os erros encontrados no relatório matinal, eu me pegava pensando que iria corrigi-los algum dia depois, porque agora há uma nova tarefa interessante no Jira que só quero começar a fazer.

Se as verificações bloquearem uma solicitação pull, então há motivação suficiente, porque até que as compilações fiquem verdes, o código não entrará em desenvolvimento, o que significa que a tarefa não será concluída.

Como resultado, escolhemos a seguinte estratégia: executamos o máximo conjunto possível de verificações à noite e lançamos as mais críticas e, o mais importante, as mais rápidas em uma solicitação pull. Mas não paramos por aí: paralelamente, otimizamos a velocidade das verificações para transferi-las do modo noturno para verificações de pull request.

Naquela época, todas as nossas compilações foram concluídas rapidamente, então simplesmente incluímos a compilação ARK, testes Junit e cálculos de cobertura de código como um bloqueador para a solicitação pull. Ligamos, pensamos a respeito e abandonamos a cobertura de código porque pensamos que não precisávamos dela.

Levamos dois dias para configurar completamente o IC básico (doravante a estimativa de tempo é aproximada, necessária para escala).

Depois disso, começamos a pensar mais - estamos verificando corretamente? Estamos executando compilações em solicitações pull corretamente?

Iniciamos a construção no último commit do branch a partir do qual o pull request foi aberto. Mas os testes deste commit só podem mostrar que o código que o desenvolvedor escreveu funciona. Mas não provam que ele não quebrou nada. Na verdade, você precisa verificar o estado do branch de desenvolvimento depois que um recurso é mesclado nele.

Evolução do CI na equipe de desenvolvimento mobile

Para fazer isso, escrevemos um script bash simples pré-merge.sh:

#!/usr/bin/env bash

set -e

git fetch origin develop

git merge origin/develop

Aqui, todas as alterações mais recentes do desenvolvimento são simplesmente extraídas e mescladas no branch atual. Adicionamos o script premerge.sh como a primeira etapa em todas as compilações e começamos a verificar exatamente o que queríamos, ou seja integração.

Demorou três dias para localizar o problema, encontrar uma solução e escrever este script.

O aplicativo se desenvolveu, mais e mais tarefas apareceram, a equipe cresceu e o premerge.sh às vezes começou a nos decepcionar. O Develop teve alterações conflitantes que interromperam a compilação.

Um exemplo de como isso acontece:

Evolução do CI na equipe de desenvolvimento mobile

Dois desenvolvedores começam a trabalhar simultaneamente nos recursos A e B. O desenvolvedor do recurso A descobre um recurso não utilizado no projeto answer() e, como um bom escoteiro, remove-o. Ao mesmo tempo, o desenvolvedor do recurso B adiciona uma nova chamada para esta função em seu branch.

Os desenvolvedores terminam seu trabalho e abrem uma solicitação pull ao mesmo tempo. As compilações são iniciadas, premerge.sh verifica ambas as solicitações pull em relação ao estado de desenvolvimento mais recente - todas as verificações estão verdes. Depois disso, a solicitação pull do recurso A é mesclada, a solicitação pull do recurso B é mesclada... Boom! O desenvolvimento é interrompido porque o código de desenvolvimento contém uma chamada para uma função inexistente.

Evolução do CI na equipe de desenvolvimento mobile

Quando não vai se desenvolver, é desastre local. A equipe inteira não pode coletar nada e enviar para teste.

Acontece que trabalhei com mais frequência em tarefas de infraestrutura: análises, rede, bancos de dados. Ou seja, fui eu quem escreveu as funções e classes que outros desenvolvedores usam. Por causa disso, muitas vezes me encontrei em situações semelhantes. Eu até deixei essa foto pendurada por um tempo.

Evolução do CI na equipe de desenvolvimento mobile

Como isso não nos convinha, começamos a explorar opções sobre como evitá-lo.

Como não quebrar o desenvolvimento

A primeira opção: reconstrua todas as solicitações pull ao atualizar o desenvolvimento. Se, em nosso exemplo, a solicitação pull com o recurso A for a primeira a ser incluída no desenvolvimento, a solicitação pull do recurso B será reconstruída e, consequentemente, as verificações falharão devido a um erro de compilação.

Para entender quanto tempo isso levará, considere um exemplo com dois PRs. Abrimos dois PRs: duas compilações, duas execuções de verificações. Após a fusão do primeiro PR com o desenvolvimento, o segundo precisa ser reconstruído. No total, dois PRs requerem três execuções de verificações: 2 + 1 = 3.

Em princípio, está tudo bem. Mas olhamos as estatísticas, e a situação típica em nossa equipe era de 10 PRs abertos, e então o número de verificações é a soma da progressão: 10 + 9 +... + 1 = 55. Ou seja, aceitar 10 PRs, você precisa reconstruir 55 vezes. E esta é uma situação ideal, quando todas as verificações passam pela primeira vez, quando ninguém abre uma solicitação pull adicional enquanto essas dezenas estão sendo processadas.

Imagine-se como um desenvolvedor que precisa ser o primeiro a clicar no botão “mesclar”, pois se um vizinho fizer isso, você terá que esperar até que todas as construções sejam realizadas novamente... Não, isso não vai funcionar , irá desacelerar seriamente o desenvolvimento.

Segunda maneira possível: coletar solicitações pull após a revisão do código. Ou seja, você abre uma pull request, coleta o número necessário de aprovações dos colegas, corrige o que for necessário e então lança os builds. Se forem bem-sucedidos, a solicitação pull será mesclada no desenvolvimento. Nesse caso, não há reinicializações adicionais, mas o feedback fica bastante lento. Como desenvolvedor, quando abro uma solicitação pull, quero imediatamente ver se ela funcionará. Por exemplo, se um teste falhar, você precisará corrigi-lo rapidamente. No caso de uma construção atrasada, o feedback fica mais lento e, portanto, todo o desenvolvimento. Isso também não nos convinha.

Como resultado, apenas a terceira opção permaneceu - bicicleta. Todo o nosso código, todas as nossas fontes estão armazenadas em um repositório no servidor Bitbucket. Assim, tivemos que desenvolver um plugin para o Bitbucket.

Evolução do CI na equipe de desenvolvimento mobile

Este plugin substitui o mecanismo de mesclagem de pull request. O início é padrão: o PR é aberto, todos os assemblies são iniciados, a revisão do código é concluída. Mas depois que a revisão do código é concluída e o desenvolvedor decide clicar em “mesclar”, o plugin verifica em qual estado de desenvolvimento as verificações foram executadas. Se o desenvolvimento tiver sido atualizado após as compilações, o plug-in não permitirá que tal solicitação pull seja mesclada no branch principal. Ele simplesmente reiniciará as compilações de um desenvolvimento relativamente recente.

Evolução do CI na equipe de desenvolvimento mobile

Em nosso exemplo com alterações conflitantes, tais compilações falharão devido a um erro de compilação. Assim, o desenvolvedor do recurso B terá que corrigir o código, reiniciar as verificações e o plugin aplicará automaticamente a solicitação pull.

Antes de implementar este plugin, calculamos em média 2,7 execuções de revisão por solicitação pull. Com o plugin foram 3,6 lançamentos. Isso nos convinha.

É importante notar que este plugin tem uma desvantagem: ele reinicia a compilação apenas uma vez. Ou seja, ainda existe uma pequena janela através da qual mudanças conflitantes podem se desenvolver. Mas a probabilidade de isso acontecer é baixa e fizemos essa compensação entre o número de partidas e a probabilidade de falha. Em dois anos disparou apenas uma vez, por isso provavelmente não foi em vão.

Levamos duas semanas para escrever a primeira versão do plugin Bitbucket.

Novos cheques

Enquanto isso, nossa equipe continuou a crescer. Novas verificações foram adicionadas.

Pensamos: por que cometer erros se eles podem ser evitados? E é por isso que eles implementaram análise de código estático. Começamos com o lint, que está incluído no Android SDK. Mas naquela época ele não sabia trabalhar com código Kotlin e já tínhamos 75% do aplicativo escrito em Kotlin. Portanto, os integrados foram adicionados ao lint Verificações do Android Studio.

Para fazer isso, tivemos que fazer muitas perversões: pegar o Android Studio, empacotá-lo no Docker e executá-lo no CI com um monitor virtual, para que ele pense que está rodando em um laptop real. Mas funcionou.

Foi também nessa época que começamos a escrever muito testes de instrumentação e implementado teste de captura de tela. É quando uma captura de tela de referência é gerada para uma visualização pequena separada, e o teste consiste em tirar uma captura de tela da visualização e compará-la diretamente com o padrão pixel por pixel. Se houver uma discrepância, significa que o layout deu errado em algum lugar ou algo está errado nos estilos.

Mas os testes de instrumentação e de captura de tela precisam ser executados em dispositivos: em emuladores ou em dispositivos reais. Considerando que são muitos testes e que são realizados com frequência, é necessário um farm inteiro. Começar seu próprio farm exige muito trabalho, então encontramos uma opção pronta - Firebase Test Lab.

Laboratório de testes do Firebase

Foi escolhido porque o Firebase é um produto do Google, o que significa que deve ser confiável e com pouca probabilidade de morrer. Os preços são razoáveis: US$ 5 por hora de operação de um dispositivo real, 1$ por hora de operação de um emulador.

Demorou aproximadamente três semanas para implementar o Firebase Test Lab em nosso CI.

Mas a equipe continuou a crescer e o Firebase, infelizmente, começou a nos decepcionar. Naquela época, ele não tinha nenhum SLA. Às vezes, o Firebase nos fazia esperar até que o número necessário de dispositivos estivesse livre para testes e não começasse a executá-los imediatamente, como queríamos. A espera na fila demorava até meia hora, o que é muito tempo. Testes de instrumentação foram executados em cada PR, atrasos realmente retardaram o desenvolvimento e então a conta mensal chegou com uma quantia redonda. No geral, optou-se por abandonar o Firebase e trabalhar internamente, pois a equipe já havia crescido bastante.

Docker + Python + bash

Pegamos o Docker, colocamos emuladores nele, escrevemos um programa simples em Python, que no momento certo traz o número necessário de emuladores na versão necessária e os interrompe quando necessário. E, claro, alguns scripts bash - onde estaríamos sem eles?

Demorou cinco semanas para criar nosso próprio ambiente de teste.

Como resultado, para cada solicitação pull havia uma extensa lista de verificações de bloqueio de mesclagem:

  • Montagem ARCA;
  • Testes Junit;
  • Fiapo;
  • Verificações do Android Studio;
  • Testes de instrumentação;
  • Testes de captura de tela.

Isso evitou muitas avarias possíveis. Tecnicamente tudo funcionou, mas os desenvolvedores reclamaram que a espera pelos resultados era muito longa.

Quanto tempo é muito longo? Carregamos dados do Bitbucket e TeamCity no sistema de análise e percebemos que tempo médio de espera 45 minutos. Ou seja, um desenvolvedor, ao abrir um pull request, espera em média 45 minutos pelos resultados do build. Na minha opinião, isso é muito e você não pode trabalhar assim.

Claro, decidimos acelerar todas as nossas construções.

Vamos acelerar

Vendo que as compilações geralmente ficam em fila, a primeira coisa que fazemos é comprei mais hardware — o desenvolvimento extensivo é o mais simples. As compilações pararam de ficar na fila, mas o tempo de espera diminuiu apenas ligeiramente, porque algumas verificações demoravam muito tempo.

Removendo verificações que demoram muito

Nossa Integração Contínua pode detectar esses tipos de erros e problemas.

  • Não vou. O CI pode detectar um erro de compilação quando algo não é compilado devido a alterações conflitantes. Como eu já disse, aí ninguém consegue montar nada, o desenvolvimento para e todo mundo fica nervoso.
  • Bug no comportamento. Por exemplo, quando o aplicativo é compilado, mas trava quando você pressiona um botão ou o botão não é pressionado. Isso é ruim porque tal bug pode atingir o usuário.
  • Bug no layout. Por exemplo, um botão foi clicado, mas foi movido 10 pixels para a esquerda.
  • Aumento da dívida técnica.

Depois de analisar esta lista, percebemos que apenas os dois primeiros pontos são críticos. Queremos detectar esses problemas primeiro. Bugs no layout são descobertos na fase de revisão do projeto e podem ser facilmente corrigidos. Lidar com dívida técnica requer processo e planejamento separados, por isso decidimos não testá-lo em uma solicitação pull.

Com base nessa classificação, alteramos toda a lista de verificações. Lint riscado e adiou seu lançamento da noite para o dia: só para produzir um relatório sobre quantos problemas havia no projeto. Concordamos em trabalhar separadamente com a dívida técnica, e As verificações do Android Studio foram completamente abandonadas. O Android Studio no Docker para executar inspeções parece interessante, mas causa muitos problemas de suporte. Qualquer atualização das versões do Android Studio significa uma luta contra bugs incompreensíveis. Também foi difícil suportar testes de captura de tela porque a biblioteca não era muito estável e havia falsos positivos. Os testes de captura de tela foram removidos da lista de verificação.

Como resultado, ficamos com:

  • Montagem ARCA;
  • Testes Junit;
  • Testes de instrumentação.

Cache remoto Gradle

Sem verificações pesadas, tudo ficou melhor. Mas não há limite para a perfeição!

Nosso aplicativo já estava dividido em cerca de 150 módulos Gradle. O cache remoto do Gradle geralmente funciona bem nesse caso, então decidimos tentar.

O cache remoto Gradle é um serviço que pode armazenar artefatos de construção em cache para tarefas individuais em módulos individuais. Gradle, em vez de realmente compilar o código, usa HTTP para acessar o cache remoto e perguntar se alguém já executou esta tarefa. Se sim, ele simplesmente baixa o resultado.

Executar o cache remoto do Gradle é fácil porque o Gradle fornece uma imagem Docker. Conseguimos fazer isso em três horas.

Tudo o que você precisava fazer era iniciar o Docker e escrever uma linha no projeto. Mas embora possa ser iniciado rapidamente, levará muito tempo para que tudo funcione bem.

Abaixo está o gráfico de falhas de cache.

Evolução do CI na equipe de desenvolvimento mobile

No início, a percentagem de perdas de cache era de cerca de 65. Após três semanas, conseguimos aumentar este valor para 20%. Descobriu-se que as tarefas coletadas pelo aplicativo Android têm dependências transitivas estranhas, devido às quais Gradle perdeu o cache.

Ao conectar o cache, aceleramos bastante a construção. Mas além da montagem, também existem testes de instrumentação, que demoram muito. Talvez nem todos os testes precisem ser executados para cada solicitação pull. Para descobrir, usamos a análise de impacto.

Análise de impacto

Em uma solicitação pull, coletamos git diff e encontramos os módulos Gradle modificados.

Evolução do CI na equipe de desenvolvimento mobile

Faz sentido executar apenas testes de instrumentação que verifiquem os módulos alterados e todos os módulos que dependem deles. Não faz sentido executar testes para módulos vizinhos: o código não mudou e nada pode quebrar.

Os testes de instrumentação não são tão simples, pois devem estar localizados no módulo Aplicativo de nível superior. Utilizamos heurística com análise de bytecode para entender a qual módulo cada teste pertence.

A atualização do funcionamento dos testes de instrumentação para que testem apenas os módulos envolvidos levou cerca de oito semanas.

As medidas destinadas a acelerar as inspeções funcionaram com êxito. De 45 minutos subimos para cerca de 15. Já é normal esperar um quarto de hora para uma construção.

Mas agora os desenvolvedores começaram a reclamar que não entendem quais compilações estão sendo iniciadas, onde ver o log, por que a compilação está vermelha, qual teste falhou, etc.

Evolução do CI na equipe de desenvolvimento mobile

Problemas com feedback retardam o desenvolvimento, por isso tentamos fornecer informações o mais claras e detalhadas possível sobre cada PR e construção. Começamos com comentários no Bitbucket para o PR, indicando qual compilação falhou e por quê, e escrevemos mensagens direcionadas no Slack. No final, criamos um painel de PR para a página com uma lista de todos os builds que estão em execução no momento e seus status: enfileirado, em execução, travado ou concluído. Você pode clicar na compilação e acessar seu log.

Evolução do CI na equipe de desenvolvimento mobile

Seis semanas foram gastas em feedback detalhado.

Planos

Passemos à história recente. Tendo resolvido o problema de feedback, atingimos um novo nível - decidimos construir nosso próprio farm de emuladores. Quando existem muitos testes e emuladores, eles são difíceis de gerenciar. Como resultado, todos os nossos emuladores migraram para o cluster k8s com gerenciamento flexível de recursos.

Além disso, existem outros planos.

  • Devolver fiapos (e outras análises estáticas). Já estamos trabalhando nessa direção.
  • Execute tudo em um bloqueador de relações públicas testes de ponta a ponta em todas as versões do SDK.

Assim, traçamos a história do desenvolvimento da Integração Contínua no Avito. Agora quero dar alguns conselhos de um ponto de vista experiente.

Dicas

Se eu pudesse dar apenas um conselho seria este:

Por favor, tenha cuidado com scripts de shell!

Bash é uma ferramenta muito flexível e poderosa, muito conveniente e rápida para escrever scripts. Mas você pode cair em uma armadilha e, infelizmente, nós caímos nela.

Tudo começou com scripts simples executados em nossas máquinas de construção:

#!/usr/bin/env bash
./gradlew assembleDebug

Mas, como você sabe, tudo se desenvolve e fica mais complicado com o tempo - vamos executar um script do outro, vamos passar alguns parâmetros lá - no final tivemos que escrever uma função que determina em que nível de aninhamento do bash estamos agora em ordem para inserir as cotações necessárias, para começar tudo.

Evolução do CI na equipe de desenvolvimento mobile

Você pode imaginar os custos de mão de obra para o desenvolvimento de tais scripts. Aconselho você a não cair nessa armadilha.

O que pode ser substituído?

  • Qualquer linguagem de script. Escrever para Script Python ou Kotlin mais conveniente porque é programação, não scripts.
  • Ou descreva toda a lógica de construção no formulário Tarefas Gradle personalizadas para o seu projeto.

Decidimos escolher a segunda opção e agora estamos excluindo sistematicamente todos os scripts bash e escrevendo muitas tarefas gradle personalizadas.

Dica nº 2: armazene a infraestrutura em código.

É conveniente quando a configuração de Integração Contínua não é armazenada na interface UI do Jenkins ou TeamCity, etc., mas na forma de arquivos de texto diretamente no repositório do projeto. Isso dá capacidade de versão. Não será difícil reverter ou construir o código em outra ramificação.

Os scripts podem ser armazenados em um projeto. O que fazer com o meio ambiente?

Dica nº 3: o Docker pode ajudar com o meio ambiente.

Definitivamente ajudará os desenvolvedores Android; o iOS ainda não tem um, infelizmente.

Este é um exemplo de arquivo docker simples que contém jdk e android-sdk:

FROM openjdk:8

ENV SDK_URL="https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip" 
    ANDROID_HOME="/usr/local/android-sdk" 
    ANDROID_VERSION=26 
    ANDROID_BUILD_TOOLS_VERSION=26.0.2

# Download Android SDK
RUN mkdir "$ANDROID_HOME" .android 
    && cd "$ANDROID_HOME" 
    && curl -o sdk.zip $SDK_URL 
    && unzip sdk.zip 
    && rm sdk.zip 
    && yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses

# Install Android Build Tool and Libraries
RUN $ANDROID_HOME/tools/bin/sdkmanager --update
RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" 
    "platforms;android-${ANDROID_VERSION}" 
    "platform-tools"

RUN mkdir /application
WORKDIR /application

Depois de escrever este arquivo Docker (vou lhe contar um segredo, você não precisa escrevê-lo, basta retirá-lo do GitHub) e montar a imagem, você obtém uma máquina virtual na qual pode construir o aplicativo e execute testes Junit.

As duas principais razões pelas quais isso faz sentido são escalabilidade e repetibilidade. Usando o docker, você pode criar rapidamente uma dúzia de agentes de construção que terão exatamente o mesmo ambiente do anterior. Isso facilita muito a vida dos engenheiros de CI. É muito fácil inserir o Android-sdk no docker, mas com emuladores é um pouco mais difícil: você terá que trabalhar um pouco mais (ou baixar o finalizado do GitHub novamente).

Dica nº 4: não se esqueça que a fiscalização não é feita pela fiscalização, mas sim pelas pessoas.

Feedback rápido e, o mais importante, claro é muito importante para os desenvolvedores: o que quebrou, qual teste falhou, onde posso ver o buildlog.

Dica nº 5: seja pragmático ao desenvolver integração contínua.

Entenda claramente quais tipos de erros você deseja evitar, quantos recursos, tempo e tempo de computador você está disposto a gastar. Verificações que demoram muito podem, por exemplo, ser adiadas durante a noite. E aqueles que detectam erros não muito importantes devem ser completamente abandonados.

Dica nº 6: use ferramentas prontas.

Existem muitas empresas que fornecem CI em nuvem.

Evolução do CI na equipe de desenvolvimento mobile

Esta é uma boa solução para equipes pequenas. Você não precisa oferecer suporte a nada, apenas pague um pouco, construa sua aplicação e até execute testes de instrumentação.

Dica nº 7: Em uma equipe grande, soluções internas são mais lucrativas.

Mas, mais cedo ou mais tarde, à medida que a equipa cresce, as soluções internas tornar-se-ão mais lucrativas. Há um problema com essas decisões. Existe uma lei dos rendimentos decrescentes na economia: em qualquer projeto, cada melhoria subsequente é cada vez mais difícil e requer cada vez mais investimento.

A economia descreve toda a nossa vida, incluindo a Integração Contínua. Construí um cronograma de custos trabalhistas para cada etapa de desenvolvimento da nossa Integração Contínua.

Evolução do CI na equipe de desenvolvimento mobile

É evidente que qualquer melhoria se torna cada vez mais difícil. Olhando esse gráfico você pode entender que a Integração Contínua precisa ser desenvolvida de acordo com o crescimento do tamanho da equipe. Para uma equipe de duas pessoas, gastar 50 dias desenvolvendo um farm de emuladores interno é uma ideia medíocre. Mas, ao mesmo tempo, para uma equipe grande, não fazer Integração Contínua também é uma má ideia, porque problemas de integração, correção de comunicação, etc. levará ainda mais tempo.

Começamos com a ideia de que a automação é necessária porque as pessoas são caras, cometem erros e são preguiçosas. Mas as pessoas também automatizam. Portanto, todos os mesmos problemas se aplicam à automação.

  • A automação é cara. Lembre-se do horário de trabalho.
  • Quando se trata de automação, as pessoas cometem erros.
  • Às vezes dá muita preguiça de automatizar, porque tudo funciona assim. Por que melhorar mais alguma coisa, por que toda essa Integração Contínua?

Mas tenho estatísticas: erros são detectados em 20% das montagens. E isso não ocorre porque nossos desenvolvedores escrevem código mal. Isso ocorre porque os desenvolvedores estão confiantes de que se cometerem algum erro, ele não acabará no desenvolvimento, mas será detectado por verificações automatizadas. Conseqüentemente, os desenvolvedores podem gastar mais tempo escrevendo códigos e coisas interessantes, em vez de executar e testar algo localmente.

Pratique a integração contínua. Mas com moderação.

A propósito, Nikolai Nesterov não apenas faz ótimos relatórios, mas também é membro do comitê do programa AppsConf e ajuda outras pessoas a preparar discursos significativos para você. A integridade e utilidade do programa da próxima conferência podem ser avaliadas por tópicos em cronograma. E para mais detalhes, visite o Infospace de 22 a 23 de abril.

Fonte: habr.com

Adicionar um comentário