Setor: Entrega de compras de mercado
Produtos da JetBrains usados: TeamCity
Tamanho da organização: 10,000
País: Holanda
“Estávamos procurando uma solução gerenciada para todos os nossos casos de utilização de CI. Além disso, também precisávamos de agentes auto-hospedados, para controlarmos qual software e quais ferramentas exatas estamos executando. O TeamCity Cloud com agentes auto-hospedados nos proporcionou uma solução sob medida que nossa equipe de mais de 300 engenheiros usa com prazer e que eleva nossa produtividade a um novo patamar.”
— Ivan Babiankou, Engenheiro de Software, Picnic
Meu nome é Ivan Babiankou. Sou engenheiro de software na Picnic e parte da equipe da plataforma Java. Estive envolvido na escolha do sucessor da nossa solução anterior de CI e na implementação da migração.
O aplicativo Picnic revoluciona a maneira como as pessoas fazem suas compras de mercado. Depois de começar em só uma cidade holandesa, a Picnic agora atende a mais de 200 cidades em três países – Alemanha, França e Holanda. A Picnic não usa lojas físicas e depende de uma abordagem inteiramente pelo aplicativo para tornar as compras de mercado fáceis e simples para milhões de usuários.
Além do aplicativo móvel voltado para o usuário, nós desenvolvemos a maioria dos outros sistemas críticos para nosso negócio, incluindo uma solução interna para a administração de depósitos. Também desenvolvemos a maioria das ferramentas de planejamento de rotas para entregadores, ajudamos estes a dirigirem com segurança, otimizamos as rotas para coletar os pedidos de compra no depósito, etc.
Atualmente, a Picnic emprega mais de 300 desenvolvedores. A plataforma tecnológica da empresa inclui Java, Python, Swift, Kotlin, TypeScript, Angular, React, Android, iOS, MongoDB e Spring Boot, dentre outros.
Começamos a avaliar o JetBrains TeamCity no final de 2021, pois estávamos ficando maiores do que a nossa solução anterior de CI estava suportando. Tínhamos dois pontos muito problemáticos: builds lentos e longas filas de espera para o build. Nos momentos de pico, alguns builds ficavam na fila até por uma hora antes de começarem a ser executados.
Na nossa solução antiga, a principal abordagem para corrigir essa situação era aumentar substancialmente o número e o tamanho dos agentes de build, para diminuir o tempo total de build. Porém, essa solução não era escalável, porque não resolvia o problema central da velocidade de build. Decidimos procurar uma nova solução que pudesse fazer isso melhor e mais rapidamente.
Para substituir nossa solução de CI, procuramos por um sistema que desse suporte a toda a nossa plataforma tecnológica e nos ajudasse a padronizar a maneira como compilamos e testamos nossos aplicativos. Usamos Java e Python no desenvolvimento de aplicativos de back-end, GitHub como nosso VCS e também Kotlin, Swift e React Native para o desenvolvimento de aplicativos móveis.
Começamos com uma lista longa de 10 provedores de soluções e a reduzimos para uma lista curta de 3: CircleCI, TeamCity e GitHub Actions. Nosso objetivo principal era minimizar o tempo na fila e melhorar o desempenho da CI reduzindo o tempo de build.
Outro requisito era termos agentes auto-hospedados. Durante a análise, percebemos que nossa solução antiga não atualizava as ferramentas nos agentes muito rapidamente. Estávamos gastando 2–5 minutos a cada build só com instalação de ferramentas. Considerando que um build demora em média uns 9 minutos, não faz sentido gastar mais 3 minutos instalando as ferramentas antes disso. Foi assim que chegamos à ideia de termos agentes auto-hospedados, nos quais teríamos as ferramentas mais recentes, um desempenho apropriado e basicamente tudo de que precisaríamos para iniciar nossos builds sem mais delongas.
Também era um pré-requisito para nós que a solução de CI estivesse na nuvem. Na Picnic, estamos tentando gerenciar o mínimo possível de sistemas. Com a CI, queríamos ter uma solução gerenciada que não tivéssemos que executar nós mesmos. Ao mesmo tempo, agentes auto-hospedados na nuvem nos permitiriam ter controle sobre qual software e quais ferramentas exatas estamos executando. Eles nos dão a flexibilidade de controlar todo o ambiente de build – o hardware utilizado e as ferramentas exatas pré-instaladas –, sem termos que gerenciar o servidor de CI.
Temos cerca de 300 usuários de CI, a maioria dos quais são ativos e fazem commit de forma intensa em quase 200 projetos. Esses projetos seguem uma estrutura bastante hierárquica no TeamCity, com mais de 120 raízes de VCS.
Temos ainda 40 agentes de build para até 40 builds simultâneos. Executamos quase 1.100 builds por dia, com um tempo total diário de build de quase 10.000 minutos. Os agentes precisam de cerca de 2 minutos para se inicializarem e os builds raramente ficam na fila por mais tempo que isso.
Depois de um mês, isso perfaz quase 300.000 minutos de tempo de build.
Usamos o TeamCity para todo o desenvolvimento interno. Assim que você abre uma PR no GitHub, o CI faz o build, executa os testes de unidade, de integração e de componente, e lhe dá o retorno. É mais ou menos até aí que chegamos. Usamos o TeamCity até o ponto em que ele produz um artefato de build, para o qual é feito então o push para um repositório, para posterior implantação.
Todos os agentes regulares e os de Linux são executados no nosso provedor de nuvem – o AWS. Para os aplicativos de iOS, temos alguns Mac Minis ligados na rede do nosso escritório e conectados ao TeamCity. Na verdade, a equipe de iOS já usava o TeamCity localmente antes de migrarmos para o TeamCity Cloud.
Executamos agentes com instâncias sob demanda. Instâncias de spot ainda são uma opção muito atraente no horizonte, para melhorias futuras.
Preparamos nossas próprias imagens e usamos os Perfis de Nuvem do TeamCity para executar agentes auto-hospedados, que são, na verdade, máquinas EC2 no AWS. Usamos o TeamCity e o Packer para compilar imagens dos agentes no AWS.
Então, usamos esses agentes em conjunto com modelos de inicialização e perfis de nuvem no TeamCity para iniciar agentes de build sob demanda. No momento, esses agentes são descartáveis, usados em um único build.
Observamos que o tempo na fila era de 2 minutos, dos quais 1:30 minuto era esperando o agente de build ser provisionado no AWS. Ter agentes reutilizáveis de vida longa nos ajudaria a eliminar esse problema. Com isso, começaríamos a examinar instâncias de spot.
Temos a política de desabilitar edições na interface de usuário do TeamCity. Um dos nossos objetivos é padronizar os pipelines. Conseguimos isso usando configurações como código.
Todas as configurações de build são armazenadas nos seus respectivos repositórios, na forma de código em Kotlin. Desenvolvemos nossa própria DSL em cima da DSL de Kotlin do TeamCity, o que nos permite definir pipelines usando 20 linhas de código ou até menos.
Por exemplo, você tem o build principal do seu aplicativo em Java. Ele executa todos os testes, inclusive os de componentes. Se tudo correr bem, ele fará o upload dos artefatos de build para o repositório apropriado.
Além disso, temos uma tarefa separada para a análise estática do código e uma outra, noturna, para a análise estática do código que será usado no SonarCloud. Essas duas tarefas são partes de um pipeline-padrão. Para aplicativos em Java, é isso que você obtém de início se você definir apenas o básico para os seus pipelines.
Algumas das nossas equipes fazem muitos testes de componentes (BDD). Programamos esses testes em Python, enquanto o aplicativo principal é feito em Java. O aplicativo é empacotado em uma imagem do Docker. Então, inicializamos um ambiente do Docker Compose no agente de build, com infraestrutura real (bancos de dados, etc.), enquanto serviços de terceiros são simulados. Testes de comportamento são executados contra o aplicativo, executado no Docker Compose.
Na DSL do Kotlin fornecida com o TeamCity, você pode fazer quaisquer ajustes que quiser no pipeline de build. Você pode mudar as etapas, os gatilhos e muitas outras coisas.
Como norma, damos às equipes um padrão-ouro de pipelines, tal como a equipe da plataforma entende isso. Por exemplo, executamos os testes de componentes como partes do pipeline de build no mesmo agente, como partes da mesma tarefa.
Há equipes que têm centenas de testes de componentes, que, infelizmente, ainda não são executados em paralelo. Nesses casos, permitimos dividir os testes de comportamento em suítes de testes e configurá-los como uma cadeia de builds.
Assim, o build principal produz o artefato e executa testes de unidade e outros testes rápidos e simples. Se isso funcionar, você pode executar tantas suítes de teste em paralelo quantas você precisar para fazer testes com múltiplas instâncias em agentes diferentes.
Estas são as coisas que mais adoramos quando usamos o TeamCity:
Configuração de agentes-padrão de compilação. Quando começamos a examinar o TeamCity, notamos que o sistema usa agentes otimizados para computação com SSDs anexados a ele. Isso proporciona um desempenho superior ao de outros agentes de CI. Embora nós não utilizemos os agentes fornecidos com o TeamCity, isso nos estimulou a usar instâncias otimizadas para computação também nos nossos próprios agentes, resultando em um desempenho melhor.
Também adoramos o recurso do monitor de desempenho. Uma das maiores dificuldades das equipes reais que usam esses pipelines era como decidir entre usar uma instância pequena, média ou grande. Olhar o monitor de desempenho dá bons insights a esse respeito. Isto facilita a depuração.
Quanto aos problemas, seria bom se tivéssemos métricas globais dos projetos que estamos construindo no TeamCity, porque no momento, o TeamCity só fornece essas informações para cada projeto individualmente. Não temos como ver as métricas globais de todos os projetos em Java, por exemplo.
Além disso, a DSL do Kotlin envolve uma curva de aprendizado bem íngreme, especialmente para engenheiros não familiarizados com Java.
Agora que já migramos todos os projetos para o TeamCity, adoraríamos fazer mais experiências com agentes de build, instâncias de spot, etc.
Para fazer as coisas bem feitas, adoramos capturar métricas de build de forma sistemática. Todas essas métricas estão disponíveis no TeamCity. O que está nos impedindo de seguir em frente é não podermos ver métricas gerais de todos os projetos, nem ver como elas evoluem com o tempo.
Essas informações nos permitiriam tomar decisões para fazermos uma maior otimização: o que melhorar e em que devemos nos concentrar primeiro, e como nossos ajustes melhoram ou pioram o desempenho. Por ora, estamos pensando em desenvolver um serviço externo que agregue todas essas informações. Se isso já estivesse disponível como padrão, seria muito melhor!
Também estamos buscando uma otimização e tentando nos livrar daqueles minutos a mais gastos na inicialização do agente, seja através de agentes de vida longa ou introduzindo um pool de agentes que se inicializem com antecedência.
Outra coisa na qual estamos trabalhando na Picnic é em criarmos mais testes exaustivos. Esse vai ser outro projeto executado no TeamCity. Assim que conseguirmos isso, precisaremos analisar novamente se iremos ou não mover toda a nossa CI/CD para o TeamCity.
Tadeas Kriz, CTO e Co-fundador, Brightify
Nossas revisões de código melhoraram significativamente e conseguimos aproveitar os webhooks do Space com o TeamCity para desenvolver cada branch revisado e implantá-lo em nosso controle de qualidade, para que o branch possa ser testado antes do merge. Agora, também é mais fácil acompanhar quem está ausente do escritório.
Piotr Polus, chefe de tecnologia para front-end, Miquido
Escolhemos a JetBrains por três motivos: conveniência de uso, configurabilidade e fácil disponibilidade de plug-ins.
Wooseong Kim, Líder de Canal APAC e Gerente de Parcerias, Tangunsoft
A JetBrains ajuda você a escrever código limpo, profissional e sustentável da mais alta qualidade.