Faça deploy sexta-feira à tarde

Marcio Frayze
13 min readApr 23, 2020

--

Existe um suposto conselho de sabedoria que diz que não deveríamos publicar uma nova versão em produção às sextas-feiras, especialmente no final da tarde. Inicialmente aparenta ser uma boa sugestão, mas fica um pouco nebulosa quando analisamos sua origem e implicações.

O surgimento da lenda

Infelizmente muitas empresas já passaram por esta situação: uma publicação é feita em produção sexta-feira e o sistema passa a ter um comportamento inesperado. As pessoas responsáveis são contactadas e começam a analisar a situação. Depois de algum tempo sem entender o que está acontecendo ou chegando a conclusão que a correção levará muito tempo, resolvem fazer um rollback da publicação para versão anterior. A consequência disso é que aparecem erros ainda piores e o sistema como um todo entra em colapso. Todo time passa então o final da tarde e boa parte do final de semana tentando resolver os problemas decorrentes desta publicação.

Uma pessoa com olhar mais desatento mas com poder de decisão é então a primeira a dar uma “solução” para que o problema não ocorra mais: estão proibidas implantações às sextas-feiras!

Causa raiz

Uma analista mais experiente não terá dificuldades em perceber que o real problema da história anterior não era a publicação em si. A principal razão das pessoas evitarem as implantações às sextas-feiras é o medo. Caso ocorra algum problema, a colega que está em plantão será acionada e ninguém quer ser a pessoa que ocasionou este chamado.

Em geral este problema ocorre em projetos onde a implantação é um evento fora do comum, que precisa de atenção redobrada e que constantemente ocasionam incidentes. Estes sintomas precisam ser observados e tratados ao invés de considerados como algo normal. Não deveríamos sentir medo em nenhum momento do ciclo de desenvolvimento de softwares e incidentes não podem ser tratados como algo rotineiro.

Evitar encontrar as causas reais do problema, preferindo tirar conclusões precipitadas e simplistas, também costuma esconder um outro medo. É fácil apontar o dedo para uma pessoa e dizer que ela executou um comando errado ou escreveu algumas linhas de código defeituosas e encerrar a análise ali, sem a necessidade de nenhuma ação, limitando-se a “dar uma bronca” em uma das pessoas do time. Enquanto encontrar a causa raiz exige esforço, dedicação e muitas vezes expõe problemas muito mais graves. E este medo de encarar os problemas reais pode fazer com que o time prefira colocar a culpa em eventos pontuais ao invés de encarar os problemas estruturais do projeto, time ou empresa.

Por isso é muito importante sempre utilizar o método dos Cinco Porquês para evidenciar que a causa geradora dos problemas é muito mais profunda.

Se esta for a situação da empresa onde você atua, existe uma série de problemas que precisam ser trabalhados. Abaixo abordo as principais causas raízes que encontro acontecendo nestas situações.

A culpa nunca é de uma única pessoa

Uma vez um analista júnior postou no reddit uma história de como foi o primeiro dia de trabalho após se formar. Foi dado um guia de como configurar o ambiente de desenvolvimento local e um dos passos na documentação dizia para executar um comando e copiar a url, nome de usuário e senha indicados na saída do programa. Estes dados deveriam ser utilizados para se conectar ao seu banco de dados de desenvolvimento.

Ele seguiu todas instruções, mas acabou cometendo um equívoco: digitou a url, nome de usuário e senha que estavam escritos no documento ao invés de utilizar os dados obtidos com a execução do comando. O resultado foi que ele, sem querer, conectou sua aplicação local ao banco de dados de produção.

O sistema possuía uma suíte de testes integrados automatizados que, ao serem executados, apagava toda a base de dados e preenchia as tabelas com dados falsos que seriam utilizados pelos testes.

Meia hora depois dele executar os testes, alguém percebeu algo estranho acontecendo: toda base de dados de produção havia sido perdida. A resposta do CTO foi culpar o novo funcionário, mandou ele ir embora e ameaçou processá-lo, enquanto o resto do time entrava em pânico tentando recuperar a base de dados e… a restauração do backup não funcionava.

O novo funcionário cometeu alguma falha? Claro que sim. Não seguiu corretamente o guia de como configurar sua estação de trabalho. Mas não precisamos ir muito longe para observar que vários outros erros tiveram que acontecer para que esta falha pontal causasse uma catástrofe irrecuperável em produção. Por que a criação do ambiente de desenvolvimento não era automatizado? Por que o guia de desenvolvimento continha dados sigilosos de produção? Por que não havia nenhuma regra de firewall bloqueando o acesso ao banco de produção diretamente da estação de trabalho? Por que a restauração do banco de produção não funcionou? Por que demorou meia hora até alguém perceber que toda base de produção havia sido apagada? Uma análise minimamente mais profunda nos mostra que várias pessoas erraram durante o processo. O novo funcionário foi apenas mais um que errou.

Fail safe

Fail safe é um recurso de design ou prática da engenharia que, ao ocorrer alguma falha, permite que os eventuais danos sejam minimizados drasticamente. Isso não significa que falhas não irão ocorrer, mas sim que o design do sistema visa mitigar ao máximo os efeitos negativos causados pelos problemas.

Um exemplo de fail safe é a forma como são construídos os elevadores. Engenheiras se esforçam ao máximo para criar um sistema seguro e o mais resiliente possível, mas nós sabemos que eventualmente problemas vão acontecer. São milhões de elevadores ao redor do mundo e o cabo de algum deles vai eventualmente apresentar problemas e se romper. Mas graças ao fail safe, os freios são acionados automaticamente assim que a tensão do cabo for perdida, evitando a queda do elevador. Mas nem sempre foi assim. A engenharia foi amadurecendo ao longo dos anos e continua evoluindo.

Estes tipos de questionamentos e preocupações parecem ser mais recorrentes quando construímos coisas físicas. O que acontece se este cabo do elevador se romper? Como e quanto o airbag é capaz de minimizar o risco de morte da motorista em um acidente frontal de carro? E do passageiro que está no assento traseiro? E se a batida for de lado? E se essa peça se desprender do brinquedo, existe o risco de uma criança pequena engolir e se sufocar?

Aos poucos estas indústrias começaram a se regular e a segurança dos elevadores, carros, motos, pontes, brinquedos e outras coisas geradas a partir da engenharia vem se tornando cada vez maior.

Quando estamos falando de software, dificilmente estaremos trabalhando diretamente com questões que poderiam ferir uma pessoa. Embora isso esteja em plena ascensão, como por exemplo a construção de carros autônomos e outras áreas da inteligência artificial e da mecatrônica, a realidade é que maioria das pessoas desenvolvedoras vão passar a carreira sem atuar neste tipo de projeto. Mas fica a questão: será que nós não deveríamos tentar fazer sistemas mais fail safe? Será que o custo financeiro de conseguir fazer isso não compensa o impacto financeiro (e social) que temos que lidar quando algo dá errado? Ao desenvolver um sistema, quanto você analisa e tenta mitigar os cenários de falhas?

Problemas de rede irão acontecer. Seu banco de dados ficará indisponível. Alguém vai pular um dos passos da documentação. Pessoas vão escrever códigos com erros de implementação. O que você faz para minimizar essas possibilidades? E quando elas ocorrerem, como garante que o impacto será o menor possível?

Falhas na infraestrutura

Algumas empresas e times ainda subestimam o valor da automação de seus servidores, preferindo configura-los manualmente. Invariavelmente isso leva ao esquecimento de uma configuração e a falta de padronização entre os ambientes, além da falta de documentação atualizada, que são essenciais para tratar as situações de catástrofes.

Outra consequência é que o ambiente de desenvolvimento, testes, homologação e produção podem estar com configurações diferentes. Uma variável de ambiente faltando, uma regra de firewall pendente, bibliotecas, drivers ou mesmo o servidor de aplicação com configurações desatualizadas, etc. E muitas vezes este tipo de problema acaba sendo exposto apenas quando uma nova publicação é feita.

A solução para a situação relatada acima é conhecida: automatize o processo utilizando o conceito de infraestrutura como código (infrastructure as code).

No passado as pessoas que trabalhavam no setor de operações passavam o dia instalando e configurando servidores manualmente. Com o decorrer do tempo, esta forma de trabalho se mostrou insustentável. Aos poucos foram surgindo soluções para tentar automatizar este processo, com ferramentas como puppet, ansible, chef, entre outras.

Nos últimos anos containers e orquestradores de containers (em especial, o kubernetes) vem ganhando cada vez mais adeptos e o dia a dia das pessoas que trabalham mais próximos da operação mudou drasticamente, cada vez se aproximando mais do perfil de pessoas desenvolvedoras. Em contrapartida, as pessoas que trabalham diretamente com o desenvolvimento foram aprendendo mais sobre essas mesmas ferramentas e conforme os silos se quebravam, nascia a cultura DevOps.

Falta de testes automatizados

Já mencionei em vários artigos a importância dos testes automatizados e como se tornam ainda mais relevantes quando aplicados na forma de TDD. Neste artigo volto a falar um pouco sobre isso.

Um sistema sem uma boa suíte de testes automatizados é um projeto que eu tenho medo de fazer qualquer manutenção ou evolução. Não importa o quão boa seja a arquitetura ou as pessoas envolvidas no projeto. Sem testes automatizados, não tenho nenhuma garantia que a menor e mais simples das alterações não irá gerar algum impacto negativo. As vezes este impacto pode aparecer pelo simples fato do projeto ter sido recompilado: uma dependência transitiva pode ter sido atualizada e começado a gerar algum tipo de problema, por exemplo. Testes de fumaça podem (ou não) encontrar a falha.

Claro que não necessariamente os testes automatizados vão pegar todos os erros — não vão. Mas ajudam a minimizar os riscos. E o maior benefício não é evitar bugs de produção, mas sim gerar confiança suficiente para que o time se sinta seguro para implementar as mudanças necessárias. Sabe aquele pedaço do código que ninguém sabe exatamente por que está ali mas todos tem medo de apaga-lo ou altera-lo? Com testes automatizados, esse tipo de situação desaparece.

Mas o maior benefício não é apenas evitar bugs de produção, é sobre a confiança que você começa a fazer mudanças no sistema. Antigas bases de código são frequentemente lugares aterrorizantes, onde os desenvolvedores temem mudar o código de trabalho. Mesmo corrigir um bug pode ser perigoso, porque você pode criar mais bugs do que corrigir. Em tais circunstâncias não é apenas horrivelmente lento para adicionar mais recursos, você também acaba com medo de refatorar o sistema, aumentando assim a Dívida Técnica, e entrando em uma espiral de piora constante onde cada mudança torna as pessoas mais temerosas de mais mudanças.— Martin Fowler.

Imagine que você estivesse entrando hoje em um time que já tem um sistema em produção. Qual dos dois seguintes cenários iria preferir encontrar? Um projeto com código legado (sem testes automatizados) ou um que possui uma vasta cobertura de testes bem escritos que servem como uma rede de segurança, evitando que eventuais falhas que você venha a cometer passem despercebidas e cheguem em produção, além de te ajudar a entender o que cada parte do sistema faz? Qual dos dois você iria preferir trabalhar? Eu com certeza o segundo. E se a sua resposta for igual a minha, então lhe pergunto: por que seu time ainda não está praticando TDD?

Arquitetura inadequada

A arquitetura de um sistema deve levar em consideração diversos fatores, mas é importante ter em mente que eles variam de acordo com as necessidades de cada projeto. O livro building evolutionary architectures aborda bastante esta questão mas, para este artigo, vou limitar o escopo para alguns problemas que vejo ocorrendo de forma mais recorrente. Existem várias formas de adotar uma arquitetura ruim para o sistema. Abaixo listo as duas principais que vejo acontecendo com frequência.

Um erro comum é tentar fazer o famoso BDUF (Big Design UpfrontGrande Design Antecipado), muito usado em sistemas desenvolvidos através do modelo em cascata. Neste cenário, as arquitetas do sistema elaboram um modelo que tenta englobar todos os futuros possíveis problemas, tentando prever todas as eventuais necessidades. O resultado costuma ser uma arquitetura muito complexa e que, embora tenha nascido para ser muito flexível e abrangente, em geral não conseguem se adequar muito bem aos inevitáveis imprevistos que irão aparecer ao longo do percurso. E a consequência é que o time precisa conviver com essa complexidade desnecessária ao longo do projeto.

Isso aconteceu, por exemplo, em um dos projetos que tive oportunidade de acompanhar. Um dos módulos era um grande sistema de consultas com quase dez anos de vida, e implementar uma nova consulta era muito difícil. Um dos colegas então se recusou a construir uma nova consulta da forma como eram feitas até então e propôs uma mudança significativa na arquitetura que simplificaria todo o processo. Durante esta investida, ele fez a pergunta que ninguém havia feito até então: por que estavam fazendo daquela forma? Por que seguiam aquela arquitetura tão desnecessariamente complexa? Ao buscar a origem descobriram que o time anterior, que havia modelado o sistema, estava tentando implementar uma solução extremamente genérica, onde a usuária final poderia acessar uma interface web e customizar as pesquisas através de uma espécie de Domain-Specific Language (Linguagem de domínio específico). Com o tempo, viram que não havia necessidade de algo tão complexo e abandonaram a ideia, mas já era tarde… toda complexidade do modelo original ficou impregnado no sistema e o permeia quase uma década depois.

Uma alternativa ao Grande Design Antecipado é seguir as práticas de design simples e arquitetura evolucionária. O Martin Fowler fala bastante sobre isso neste artigo (em inglês).

Outro erro comum é simplesmente ter uma arquitetura ruim. Sistemas com alto acoplamento e baixa coesão, muito confusos, sem uma estrutura clara e uniforme, que não segue os princípios da linguagem ubíqua, … ou de forma mais resumida, um sistema construído por amadores remunerados. Se o seu time é composto apenas por analistas com pouco conhecimento sobre arquitetura de software, será quase impossível alcançar uma qualidade mínima desejada que permitiria a construção de softwares com alto grau de manutenibilidade.

Um time inexperiente e amador talvez consiga entregar uma primeira versão do projeto em produção e talvez o custo inicial seja até menor desta forma. Mas sofrerão horrores devido aos bugs e terão muitas dificuldades para manter e estender o software.

Softwares enferrujam

Um problema recorrente é o time esquecer que softwares enferrujam. Quando uma pessoa precisa dar manutenção em um objeto físico, fica bem fácil para todas pessoas envolvidas entender a importância de dar atenção para manutenção deste objeto. Por exemplo um carro. Toda motorista sabe que precisa calibrar o pneu, trocar o óleo, fazer as revisões, etc. Uma proprietária atenta sabe que não deve esperar até o veículo apresentar problemas para dar manutenção. Quando o pneu está gasto, precisamos trocá-lo antes que fure.

Mas quando o assunto é desenvolvimento de software, infelizmente muitas vezes este tipo de cuidado é negligenciado. Alguns times e empresas possuem uma cultura de não atuar de forma preventiva, se preocupando apenas quando o problema aparece para a usuária final (ou, fazendo o paralelo com o carro, só quando o pneu estoura e ficamos largados no meio da estrada).

As vezes pode ser difícil explicar para pessoas com perfil mais de gestoras o tamanho da importância do time ter tempo para atuar na manutenção da aplicação. Com o tempo a dívida técnica se acumula, até se tornar inviável. E como qualquer dívida, quando antes for paga, menor será a dor de cabeça.

Por isso é importante que você, líder técnico ou líder de projeto, proteja seu time deste time do dívida. Não deixe o seu sistema enferrujar.

Confie em seu time

É necessário ter confiança em seu time para que seja possível fazer uma publicação do seu sistema sexta-feira à tarde. E a melhor forma de fazer isso é através de uma boa cultura da empresa e uma estrutura organizacional adequada. Se ainda estiver trabalhando com um modelo extremamente hierárquico, será muito mais difícil fazer publicações com frequência. Quando o time tem autonomia para realizar as ações que julguem adequadas, ficará muito mais fácil chegar em uma situação que permite fazer publicações a qualquer instante.

Os sinais de hesitação precisam ser observados, já que expressa que existe algo está errado no processo de desenvolvimento do seu sistema. Mais uma vez, tente encontrar a causa raiz que gera esta aflição.

Vinte porcento da semana

Se considerarmos apenas os dias úteis, cada dia da semana equivale a 20% do tempo. Se você evitar fazer publicações toda sexta-feira, estará evitando publicações em 20% do tempo.

Um agravante é que as alterações que poderiam ter sido entregues na sexta vão ficar para segunda-feira, o que muitas vezes gera um acumulo de entregas. Como a comunidade ágil já tenta nos avisar a muitos anos, quanto menor a entrega em produção, mais fácil será todo o processo de publicação, monitoramento e atuação em caso de falhas. Aproveite estes 20% da semana para fazer entregas menores e mais seguras.

Comemore a nova funcionalidade

Salvo engano a primeira vez que ouvi isso foi em uma palestra do Martin Fowler: deveríamos comemorar a implantação de uma nova funcionalidade, e não o fato de termos feito uma publicação com sucesso, sem derrubar todo o sistema.

Fazer publicações que não causam efeitos colaterais negativos deveria ser a norma e, portanto, não deveriam ser motivos para comemoração. Afinal, ao não tirar o sistema do ar estamos fazendo nada mais do que o básico que deveria ser exigido do nosso trabalho.

Esteja preparada para fazer rollback

Problemas vão acontecer. Você precisa estar preparada para perceber o quanto antes e ser capaz de voltar para versão anterior da aplicação de forma semi automatizada (ou completamente automatizada).

Fazer isso exige atenção o tempo inteiro. Um dos cuidados que muitas vezes vejo sendo negligenciado é com a estrutura do seu banco de dados. Uma nova publicação pode exigir que a estrutura de uma tabela seja modificada. Mas se um dos campos simplesmente mudar de nome, a versão anterior da aplicação deixaria de funcionar nesta nova estrutura. Ou seja, caso fosse feito um rollback, seria necessário também voltar a estrutura de banco (o que em alguns casos pode não ser tão simples). Para isso, existem estratégias para criar designs de bancos de dados evolucionários.

Monitoramento é essencial

É muito importante não negligenciar a importância do monitoramento de seus sistemas. Este recursos tem dois papeis fundamentais: o primeiro é tornar seu time capaz de ter uma reação o mais rápido possível em caso de falhas graves. O segundo é servir de insumo para se antecipar às falhas, agindo de forma ativa, antes que elas ocorram.

Mas não basta ter a infraestrutura. O time precisa ter a cultura de acompanhar e entender tudo que está se passando, diariamente. Mais uma vez, abraçando a cultura DevOps.

Conclusões

Neste momento deve ter ficado claro para leitora que praticar o desenvolvimento de software de forma a permitir implantações às sextas-feiras não é fácil e nem todos os times e sistemas possuem maturidade o suficiente para alcançar este objetivo. Mas deveria ser o objetivo de todos e cabe ao time todo, em especial a líder técnica, observar as razões de por que não conseguiram atingir ainda este objetivo ainda e quais são os próximos passos necessários para caminhar mais um pouco nesta direção.

Obrigado por ler até aqui! Se gostou deste texto, tenho mais alguns publicados em minha página do medium e também mantenho um podcast onde falo sobre livros que impactaram na minha carreira.

--

--

Marcio Frayze
Marcio Frayze

Written by Marcio Frayze

Entusiasta de programação extrema e autor do projeto segunda.tech.

No responses yet