8 minutos de leitura
O Bossabox lida com diversas contas e clientes criando produtos digitais ao mesmo tempo, utilizando squads remotos e tecnologias diferentes. Percebemos que boa parte dos esforços dos desenvolvedores em projetos eram resultantes de retrabalhos que surgiam após migrar a aplicação de um servidor para outro, isso sem contar o tempo necessário para configurar o servidor e fazer a migração em si. Essas demoras não só impactam o prazo final, como também diminuem a agilidade do time para resolver questões que efetivamente agregam valor para o cliente. Pesquisamos e percebemos que não tínhamos estruturado um processo eficiente e automatizado de DevOps, o que se mostrou a raíz de diversos desafios que vínhamos encontrando.
O DevOps pode ser definido de algumas formas:
Coleção de frameworks e ferramentas, embebidos na filosofia de entregar produtos de forma cada vez mais rápida, confiável e compatível com as necessidades do usuário;
Interface entre o time de desenvolvimento e o time de operações;
Essas definições só contam parte da história ou mostram uma faceta mais conceitual. Na prática, DevOps permite que um produto codado localmente ou em um servidor de staging – uma réplica do ambiente de produção, porém não disponível aos usuários – possa ser rapidamente testados, enviado para produção (disponibilizado para o uso dos usuários, seja de forma gradual ou indiscriminada), validado com os usuários, e que feedbacks sejam prontamente recolhidos, implementados no produto e levados em consideração para as próximas features ou releases que serão desenvolvidos, tudo isso em um período de tempo relativamente curto.
Um bom DevOps faz com que o caos que um Deploy representava não faça mais sentido, pois os períodos de testes e implementação de releases ou novas features tornam-se muito mais curtos.
Ciclos mais curtos de desenvolvimento permitem avaliações mais rápidas de incrementos menores no produto. Verifica-se se as decisões tomadas pelo time de produto estão alinhadas com as necessidades do usuário e se a forma como foi concebida pelo time de design e executada pelo time de código é a solução mais adequada.
O valor que isto traz para o negócio é enorme, já que a equipe poderá avaliar suas decisões em períodos de tempo mais curtos e balizar de acordo com o que foi verificado no mercado. Startups precisam ter um bom processo de DevOps, pois não podem se dar ao luxo de aguardar meses para implementar novas features e verificar se o seu produto será bem aceito pelo mercado.
Antes de qualquer coisa, entenda o processo completo para desenvolver um produto em sua empresa, quais são os times, metodologias, tecnologias, cultura. Em seguida, entenda onde estão as limitações e crie um novo modelo. Esse é um ótimo momento para fazer mudanças não somente processuais, mas também culturais. Proponha esse modelo para sua equipe, receba os feedbacks e crie novas versões, até obter um processo que faça sentido para toda a equipe. Assim que tiver com este novo processo definido, comece a avaliar as partes mais específicas do DevOps.
“Continuous Integration“, “Continuous Delivery” e “Continuous Deployment” representam o core do DevOps, e para entendê-los, precisamos compreender as seguintes etapas: Código Finalizado, Testes Unitários, Integração, Teste de Aceite e Deploy para Produção.
O código é geralmente armazenado e versionado em um repositório online, que utiliza Git. O BossaBox utiliza e recomenda o Gitlab, principalmente se você tem interesse em aplicar DevOps na sua empresa – o porquê vai ficar muito claro daqui a pouco. Existe um modelo de ramificação para Git chamado “Gitflow“, que é o framework recomendado para organizar repositórios Git em geral. É bastante comum times que não o utilizam apresentarem perdas de arquivos e terem que refazê-los. Incorpore-o no seu processo de desenvolvimento!
Os Testes Unitários são uma das formas mais simples de testes que pode-se realizar. De forma geral, criam-se testes que definem inputs para uma função ou conjunto delas e um output esperado. Caso o output da função criada seja igual ao output proposto, o teste é aceito. Caso contrário, o teste é reprovado. Descobre-se a taxa de sucesso dos testes e qual porcentagem do código total foi testado. Essas duas taxas indicam se o seu código está mais ou menos protegido contra problemas ao inseri-lo em produção. No entanto, lembre-se: não existe esse mito de código “bug free“. O que se pode fazer é tomar medidas para tentar encontrar a maior parte possível desses problemas (testes) e, caso algum não seja evitado, ter sempre uma forma de contorná-lo ou tirar o acesso dos usuários à ele, muitas vezes voltando à uma versão anterior (rollback). Os teste funcionam como um critério qualificador: se as funções passarem nos testes unitários, elas devem seguir para futuras avaliações, caso contrário seu avanço no processo deve ser bloqueado.
A Integração é a junção do novo trecho do código com o que já foi criado. Isso ocorre caso o código passe pelos Testes de Integração geralmente compostos pelos mesmos testes que foram criados para os trechos antigos e novos do código, mais testes para verificar se o código antigo e o novo estão se relacionando corretamente. Isso é importante para evitar que uma função que funcionava perfeitamente quebre quando um novo trecho do código for inserido. Como se a situação não fosse suficientemente ruim, você geralmente só vai perceber que essa função antiga quebrou quando já estiver em produção. Você terá que fazer o rollback e lidar com o cliente e os seus usuários reportando tal problema.
O Teste de Aceite já é algo bastante mais sensível. Considere o Teste de Aceite como um acordo entre os diferentes players de como devem ser as entregas. Podem ser manuais, como o líder verificar o código antes de aprová-lo para Deploy, podem ser automáticos, como um script que tenta verificar se o front-end está semelhante ao layout. Independente de qual Teste de Aceite o seu time irá utilizar, trate de defini-los muito bem e em equipe antes da primeira linha de código ser escrita. Esse alinhamento irá atribuir responsabilidade aos membros do time e aumentará a qualidade e assertividade do produto entregue.
O deploy para produção significa enviar essa nova versão do código para o ambiente de produção, sendo acessível aos usuários. É necessário ter alguns cuidados: o banco de dados presente no ambiente de produção pode ser diferente do staging. Caso somente os dados estejam diferentes, é importante verificar se há a necessidade de criar alguma nova entrada. Por exemplo, se foi inserido um novo campo com banner, é necessário adicionar a imagem do banner no banco de dados. No entanto, se houver uma mudança na estrutura do banco de dados, é importante atualizar a estrutura do banco de dados do ambiente de produção. Também é preciso considerar se estão sendo utilizados bancos relacionais ou não relacionais no produto, pois cuidados diferentes devem ser tomados.
A diferença de “Continuous Integration“, “Continuous Delivery” e “Continuous Deployment” é simples. O primeiro irá abordar a etapa até a integração. O “Continuous Delivery” e o “Continuous Deployment” vão até a etapa de Deploy para a Produção, a diferença é que o primeiro faz o Deploy quando há um comando manual para o Deploy ocorrer e o segundo ocorre de forma automática – se passar nos Testes de Aceite já será feito o deploy.
Alerto que “Continuous Deployment” é muito perigoso na maioria dos casos, pois mesmo que haja uma cerimônia clara para todos pegarem uma parte do seu tempo e testarem o que foi lançado, um fluxo constante de incrementos pode ser atrelado à um fluxo constante de bugs adicionais, o que pode fazer com que a vida do time de desenvolvimento fique confusa e menos produtiva.
Não podemos esquecer o feedback do usuário. Tudo isso foi feito para que possamos validar o produto com o usuário. Podemos classificar o feedback do usuário em duas formas: intencional e não intencional. Um exemplo de feedback intencional seria deixar um botão para o cliente clicar e deixar um comentário ou relatar um bug. Um feedback não intencional seria, por exemplo, uma ferramenta de mapa de calor. Ambas as técnicas devem ser adotadas para capturar o máximo de valor possível do usuário.
Bom, entendemos o que é o DevOps, mas como começar um na prática? Eu diria que a melhor opção para iniciar é unir as seguintes ferramentas: Gitlab CI/CD, Google App Engine e UserSnap.
O Gitlab é o gerenciador de repositório baseado em Git escolhido pelo BossaBox por diversos motivos, mas um dos principais é o seu foco no DevOps. O Gitlab CI/CD funciona por meio de pipelines. Você definirá jobs, tarefas que devem ser executadas dentro do pipeline. Definirá quais branches irão disparar quais Jobs. Coleções de jobs criam Stages. Vamos exemplificar, com 3 Stages: Staging, Testing e Deploy. O Staging irá fazer o Deploy no ambiente de Staging, o Testing permitirá fazer testes contra essa versão e o Deploy vai fazer o deploy na produção caso passe nos testes, caso contrário irá apagar a versão que estava sofrendo os testes. Para entender melhor a diferença de stage e job, o stage Testing irá ter 2 jobs, Testes Unitários e Testes de Aceite. Caso passe nos dois, irá ser feito o deploy, se não passar em algum, é cancelado. Importante lembrar que são permitidos gatilhos manuais, de forma a clicar um botão na interface do Gitlab CI/CD e aprovar ou não uma versão enviada, funcionando como um Teste de Aceite manual, bastante útil para front-end ou para líderes aprovarem ou não a qualidade do código inspecionando por ele mesmo.
Utilizar o Gitlab CI/CD faz com que desenvolvedoras e desenvolvedores já façam praticamente o processo inteiro de DevOps só ao utilizar o Gitflow. E por não utilizar ferramentas externas para DevOps, como a ferramenta de integração contínua “Jenkins”, o DevOps torna-se algo natural, dito isso, fica claro o porquê do Gitlab ser tão valioso.
O Gitlab irá se encarregar de executar os comandos do DevOps. Agora, você precisa decidir como você irá fazer o Deploy do seu aplicativo, seja no Staging ou Produção. O Deploy tende a ser tão complicado pois o sistema operacional, a versão da linguagem e de pacotes complementares, o hardware, praticamente tudo é diferente entre dois servidores, por exemplo, a máquina local do desenvolvedor e o servidor do cliente. Para resolver esse problema, surgiram os containers e o Kubernetes.
De forma bastante simplificada, um container irá utilizar uma imagem para criar uma máquina virtual (pega uma parte do servidor e faz interpretar como se fosse um servidor isolado). Uma imagem pode ser utilizada para carregar dois servidores “idênticos” em duas máquinas completamente diferentes, ou até mesmo dois servidores completamente diferentes na mesma máquina. O Docker é a principal solução para containers hoje, sendo considerado quase um padrão na indústria.
Agora considere que parte do seu código está em uma versão pré-histórica de PHP, outra em uma versão atual, uma parte do código novo foi codado em Ruby e o front-end está em React. Com as tecnologias antigas, isso seria no mínimo uma grande dor de cabeça. Não mais. Você pode criar diferentes contêineres, cada um com uma imagem específica para o código que será tratado, e fazer eles “se conversarem”. Ótimo. Mas e se nós precisarmos aumentar a capacidade de uma certa parte do código? E se o código em um container está apresentando problemas? Você precisa de alguma forma para automatizar o gerenciamento dos containers. Foi aí que surgiu o Kubernetes, uma tecnologia considerada, assim como o Docker, um dos padrões da indústria.
Parece que utilizando o Docker + Kubernetes teremos uma solução completa. Praticamente sim, no entanto configurá-los pode ser bastante maçante. A ideia é que o Deploy seja um comando, não uma tarefa. É aí que entra o Google App Engine (GAE).
O GAE é “uma plataforma para desenvolver e hospedar aplicações WEB na infraestrutura do Google”. Basicamente você cria alguns arquivos de configuração padrão, seleciona a pasta, envia para o GAE e ele faz a configuração inteira do seu produto. O GAE utiliza, dentro de sua estrutura, o Docker e o Kubernetes (que foi criado pela Google há um bom tempo). Assim, o seu time poupa tempo e esforço, mantendo um deploy extremamente confiável e estável.
Ainda por cima, ao utilizar o Google App Engine – que já desempenha a função de servidor, você não precisará se preocupar com banco de dados, já que o Google Cloud oferece esses serviços Cloud de forma integrada e com uma ótima documentação. Se você escolher o ambiente flexível, o GAE oferecerá auto-scaling (aumentar número de instâncias de um serviço automaticamente quando for necessário), auto-balancing (redirecionar usuários de um serviço para outro para não sobrecarregar um específico), health-checking (verifica se o serviço está rodando corretamente), entre muitos outros. O GAE cobra pelo uso da infraestrutura, não pelo tempo em que o serviço está ativo nela. Assim, se o seu produto estiver no início de sua jornada e tiver poucos acessos, a sua conta será pequena. Seu produto está decolando? O GAE irá se encarregar de deixá-lo disponível para todos que queiram utilizá-lo, sem problema para escalar!
Pelos benefícios que oferece, o GAE é uma das melhores soluções para web apps hoje. Caso queira sair do GAE e ir para outro servidor, é possível exportar os arquivos de configuração do Docker, por exemplo, para facilitar essa migração. Assim, pode utilizá-lo sem medo, você não ficará preso à ele.
Por último, precisamos coletar feedbacks do usuário e enviá-los para o time de desenvolvimento fazer as devidas correções. A ferramenta UserSnap realiza essa função de forma exemplar: você pode adicionar um botão em seu produto ou instalar um plugin no Chrome, o usuário aciona o UserSnap, o qual irá gerar um snapshot interativo do que o usuário está vendo, de forma que pode deixar um comentário geral sobre a página que está visualizando, deixar uma forma de contato, destacar algo e deixar um comentário específico, além de coletar uma série de informações que ajudam os desenvolvedores a identificar o bug, como browser e versão utilizada, data e hora. Por último, ele enviará esse feedback diretamente para o Gitlab do projeto. Praticamente tudo centralizado no Gitlab.
O DevOps é algo que deve ser desenhado com base em quem o utilizará. Um DevOps muito rígido para uma startup pode gerar perda de produtividade, da mesma forma que um DevOps muito flexível pode comprometer um produto por integrar features defeituosas. Entenda as suas necessidades, desenhe os seus processos e aproveite para estabelecer uma metodologia bem definida de desenvolvimento. Só depois descubra quais ferramentas são mais apropriadas para você e sua equipe. Somente dessa forma o DevOps trará benefícios expressivos ao seu time, caso contrário se tornará mais uma ferramenta subutilizada que rapidamente será engavetada.
Por último, vou deixar um vídeo do Canal no YouTube do GitLab que introduz o assunto com uma demo.
Espero que goste!
Times de Tecnologia
4 minutos de leitura
Ler artigoMarketing e Vendas
3 minutos de leitura
Ler artigo