BT

Disseminando conhecimento e inovação em desenvolvimento de software corporativo.

Contribuir

Tópicos

Escolha a região

Início Artigos Sete duras lições aprendidas na migração de um monólito para microservices

Sete duras lições aprendidas na migração de um monólito para microservices

Favoritos

Pontos Principais

  • Mesmo em 2020, há uma boa chance de ainda termos de trabalhar com pelo menos um sistema legado. Nesse caso, provavelmente estaremos pensando em migrar para uma arquitetura de microservices;

  • Em alguns casos, o melhor é pular a migração, por exemplo, se a maior parte do desenvolvimento está acontecendo nos novos sistemas de qualquer maneira e poucos desenvolvedores precisam interagir com o código legado;

  • Devido à complexidade geral e à dificuldade em fazer estimativas sólidas, não é uma boa ideia tornar um projeto de refatoração um "projeto" oficial com uma data de início e de término definidas. Mas ainda precisaremos do suporte top-down para o esforço, além da necessidade de planejar o trabalho para que possamos fazer um progresso consistente;

  • Se eles ainda não existem, escrever testes automatizados antes da refatoração é uma das melhores coisas que podemos fazer para facilitar o processo e ter certeza de que o novo sistema se comporta da maneira esperada;

  • Atenha-se a padrões conhecidos ao construir o sistema conhecido e resista ao impulso de ir direto ao ponto mais complicado. O pioneirismo em uma abordagem totalmente nova para microservices é caro e o refactore o manterá ocupado o suficiente.

Ao longo dos anos, fiz parte e observei de perto esforços para migrar sistemas legados monolíticos para uma arquitetura de microservices. Através dessas experiências por muitas vezes amargas, aprendi sobre muitas armadilhas e desafios envolvidos no processo. Um desses esforços acabou me custando uma quantia considerável de dinheiro pessoal e, sem dúvida, foi um fator-chave para o fim da empresa envolvida. Não vou entrar em detalhes, mas tenho certeza que não quero que outras pessoas passem pelas mesmas experiências.

Por isso, gostaria de tentar passar algumas das lições que aprendi, na esperança de que a migração e os dias difíceis que virão da refatoração seja os melhores possíveis. Embora já tenha sido dito muita coisa sobre o assunto, ainda há alguns conselhos que gostaria que alguém tivesse me dado, alguns dos quais não tinha ouvido antes.

Sou cofundador de uma empresa chamada Garden. Buscamos facilidades para os desenvolvedores nas tarefas de testar, revisar e solucionar problemas de aplicações de microservices na cloud native (nosso produto principal é open source, e você pode verificar se ele é interessante e útil na sua empresa) e, por isso, passo muito tempo trabalhando com os usuários que estão passando por esse mesmo processo de migração. Além disso, por meio dessas interações, aprendi algumas lições importantes que acho que valem a pena serem compartilhadas.

Sejamos honestos. Mesmo em 2020, muitas, se não a maioria, das empresas maduras ainda executam um sistema legado de missão crítica, cada vez mais difícil de dimensionar, operar e manter. Frequentemente, são sistemas multifuncionais complexos que têm muita responsabilidade. Esses sistemas são conhecidos como monólitos, uma palavra agora sinônimo de aplicações que não seguem arquiteturas de desenvolvimento modernas, não atendem aos requisitos de escalabilidade e/ou não correspondem às estruturas empresariais. Muitas pessoas trabalhando em uma base de código fortemente acoplada podem criar gargalos sérios e retardar o desenvolvimento, além do acoplamento poder causar problemas de confiabilidade e escala.

Portanto, é perfeitamente razoável pensar em migrar o legado para uma arquitetura de microservices. Aqui estão alguns pontos que sugiro que considere ao contemplar e planejar os próximos passos. Comece com o conselho número um.

#1 Talvez seja melhor não migrar

Considere se realmente precisa dividir o monólito e, se fizer, certifique-se de fazer pelos motivos corretos. Existem muitos bons motivos para uma refatoração, mas aqui estão alguns sinais de que pode, ou deve, evitá-la:

  • A maior parte do desenvolvimento de recursos novos já estão ocorrendo nos sistemas novos. Talvez não tenha um problema de velocidade de desenvolvimento e o sistema legado seja apenas responsável por coisas que não precisam de muita iteração;
  • O sistema ainda atende às necessidades de escalabilidade. Mesmo que ele não tenha uma tecnologia de ponta, talvez ainda lide com a carga atual ( e a esperada). Monólitos podem ser eficientes, já que geralmente não dependem de redes e APIs de alto nível para comunicação interna;
  • Não possui tantos desenvolvedores que precisam trabalhar nisso. Isso pode ocorrer porque uma única equipe é responsável por tudo, ou não está em uma grande empresa, o que poderia sobrecarregar a esteira de desenvolvimento e criar gargalos no processo;
  • É bem projetado e arquitetado. Os sistemas monolíticos tendem a se tornar um novelo de lã, com acoplamento entre as diferentes partes e que possui grande complexidade de compreensão. Mas talvez tenha conseguido evitar essas armadilhas comuns e manter uma boa estrutura o tempo todo.

Claro, se confirmar que está na frente destes quatro motivos, a conclusão é óbvia. Apenas não migre. Considere os microservices para projetos futuros e mantenha o foco nos problemas reais de negócios, deixe o sistema sólido fazer aquilo que deve fazer.

No entanto, não estaríamos lendo isso e considerando uma refatoração em primeiro lugar. A realidade é complexa e provavelmente nenhuma ou até três desses pontos correspondem à atual situação. Se não houve nenhum dos motivos acima, não terá muita escolha. Para qualquer coisa entre todos ou nenhum, há um julgamento a ser feito e pode ter outros bons motivos para prosseguir.

É necessário comparar os desafios em relação ao custo da migração. O custo estimado deve incluir pelo menos o seguinte:

  • O custo das horas do desenvolvedor. Este é o fator mais óbvio, mas geralmente é difícil de ser estimado;
  • O retorno da oportunidade talvez não cubra os custos das horas gastas no novo desenvolvimento. Acho que isso é frequentemente esquecido ou subestimado. A empresa está competindo com outras, e qualquer tempo gasto sem desenvolvimento deve ser considerado com cuidado;
  • Custo de novas ferramentas e processos. Principalmente se não tiver uma infraestrutura de microservices madura e em produção, deverá considerar o custo de adoção das novas metodologias e o investimento em ferramentas e infraestrutura necessários.

Considere todos esses fatores, faça uma estimativa e, em seguida, multiplique-a por cerca de três vezes para contabilizar toda a incerteza envolvida.

Se tudo isso pesar menos do que as dores de cabeça que está sofrendo hoje, vá em frente. Se ainda não tiver certeza, talvez os conselhos a seguir possam ajudá-lo a decidir se vale a pena o esforço.

#2 Não transforme isso em um projeto

Essa afirmação talvez precise de um pouco mais de explicação. O que quero dizer com projeto é algo que programamos e planejamos, reservando muitas semanas de tempo de desenvolvimento e assim por diante. Ou seja, algo em que esperamos trabalhar continuamente, sem interrupções e com datas de início e término. Transformar toda a migração em um projeto, com o objetivo de concluí-lo, é uma resposta comum ao problema técnico que geralmente considero um erro.

Existem alguns motivos para isso:

  1. Provavelmente pararia e reservaria o tempo de um grupo pequeno da empresa para trabalhar neste projeto de dívida técnica. Eles podem estar animados para fazer isso porque esses podem ser problemas de engenharia interessantes que a equipe gostaria de resolver há algum tempo. Entretanto, isso pode desconectar essas pessoas de outros desenvolvimentos em andamento e, às vezes, pode resultar em atrito porque os objetivos são diferentes do resto da empresa;
  2. Se colocar toda a empresa no projeto, irá parar ou irá retardar qualquer desenvolvimento no que diz respeito aos usuários/clientes. Além disso, provavelmente terá mais mãos do que o necessário exacerbando quaisquer problemas de gargalo que tenha com o monólito. Em última análise, o problema será a desaceleração do novo desenvolvimento, que ocasionará o próximo motivo;
  3. Vai demorar mais do que pensa. Ou mais do que a equipe pensa, até mesmo mais do que os engenheiros mais experientes e capazes imaginam. É muito fácil cair na armadilha de subestimar a complexidade de um projeto de refatoração. E é fácil esquecer toda a lógica sutil e pequenos nuances gradualmente incorporados no código enquanto está migrando na arquitetura de alto nível.

Ao invés de torná-lo um projeto, sugiro torná-lo um esforço contínuo. É uma distinção importante porque um esforço não tem necessariamente um cronograma e, idealmente, não bloqueia outros projetos, passando a ser uma meta de negócios.

#3 Comprometimento com o esforço

Isso só funciona se se comprometer com o esforço e não o deixar de lado sucessivas vezes ao priorizar o trabalho. Comprometer-se com o esforço significa envolver a empresa e garantir que o trabalho seja um tema cultural.

É muito fácil ter pessoas concordando com você dentro de uma reunião, com o esforço sendo forte no começo e, em seguida, o esforço perder prioridade por demandas concorrentes no próximo sprint, semana, trimestre, etc.

Aquilo que é urgente tende a derrotar aquilo que é importante no nosso dia-a-dia, então é necessário continuar batendo o tambor para evitar ser abafado pelo desfile interminável de urgência.

Aqui estão algumas coisas específicas que podemos fazer para garantir que a empresa permaneça comprometida com o esforço:

  • Reserve um tempo para definir o escopo do trabalho necessário e dividi-lo em partes independentes e gerenciáveis com objetivos claramente definidos. Isso tornará mais fácil o desenvolvimento paralelo a outros projetos, reduzindo o risco de cada etapa;
  • Certifique-se de que o trabalho tenha o apoio da alta gestão e, se o monólito for fundamental para a empresa, é imprescindível que seja visto como uma prioridade estratégica. A diretoria precisa entender as vantagens, bem como o impacto iminente de evitar o esforço. Em muitos casos, estará evitando problemas desastrosos de dimensionamento ou de produtividade. Nesse contexto, um esforço sustentado de refatoração pode não parecer tão ruim;
  • Divulgue o progresso. Se segmentou o trabalho em partes gerenciáveis, deve ter uma noção do progresso à medida que conclui cada parte. Isso é recompensador para a equipe, riscar uma linha da lista de pendências é uma sensação muito agradável, e também evita a sensação de que a refatoração é um buraco sem fundo, que provavelmente causaria muita desilusão.

#4 Escreva testes

É comum e perfeitamente normal faltarem testes automatizados em qualquer sistema, incluindo os sistemas legados. Se teve o prazer de refatorar o código que já tinha ótimos testes, vai gostar disso. Talvez tenha percebido ou sequer tenha notado, já que o processo deve ter sido muito tranquilo.

Sem testes automatizados, é muito difícil avaliar se o novo código tem o mesmo comportamento que o código anterior. Esse é um cenário aplicável caso esteja realmente reescrevendo, talvez em uma nova linguagem de programação, ou apenas movendo o código antigo de um lugar para outro. Até mesmo as refatorações mais triviais podem criar problemas sutis ou inconsistências, não importa quão habilidosos sejam os desenvolvedores.

Se não se sentir confortável com a cobertura de teste atual, comece abordando esse problema. Escrever bons testes reduzirá drasticamente o esforço e também é uma ótima maneira de entender melhor a base de código, a estrutura, as complexidades e as idiossincrasias, que com certeza irá descobrir.

Se possui um bom número de testes escritos, certifique-se de aprofundar o nível de cobertura. Os testes analisam o sistema externo, por exemplo, no nível da API, ou apenas testam o código das camadas mais inferiores da aplicação? Os testes unitários, embora sejam importantes, tem um valor um pouco menos direto quando chegamos ao ponto de dividir e mover o código. Uma boa integração e testes ponta a ponta que não fazem suposições sobre a implementação podem ser mantidos como estão e usados como benchmark durante a migração.

#5 Devagar, transforme o monólito em um proxy

Este é um conselho dividido em duas partes. A primeira é fazer a divisão incrementalmente. Não presuma que possa fazer uma migração em massa com sucesso e, em seguida, aperte um botão e tudo ficará ótimo. É simplesmente muito arriscado. Descubra onde estão os pontos de acesso, os maiores gargalos ou outros desafios, descubra-os um por um.

A segunda parte talvez seja opcional e nem sempre é aplicável, mas recomendo fortemente manter o monólito como uma fachada para os novos serviços enquanto isso for viável. A vantagem dessa abordagem é manter a mesma interface no que diz respeito ao usuário/consumidor do serviço e permite manter a mesma integração e testes ponta a ponta durante todo o processo.

Uma alternativa a essa abordagem é primeiro fazer um proxy, com apenas o monólito por trás dele, e então começar a rotear para serviços diferentes conforme os remove e/ou adiciona novos. A estratégia depende do sistema atual e para onde está indo. Em ambos os casos, pode se beneficiar da migração gradual do monólito sem que os usuários saibam e sintam.

Assim, mesmo quando mover as funcionalidades para serviços recém-construídos, o monólito ainda pode existir em toda a refatoração, e talvez por algum tempo depois dela, servindo como fachada para uma nova funcionalidade ou para funcionalidades já existentes, sendo na forma de proxy.

#6 Siga os padrões conhecidos

É tentador ir do legado a tecnologia mais avançada. E é um desejo compreensível, porque desta vez, está preparando e planejando o futuro, para que não haja outra refatoração em breve.

Recomendo cautela neste ponto. Considere seguir um caminho já estabelecido. Do contrário, pode irá lutar contra dois problemas ao mesmo tempo e será pego novamente no buraco sem fundo. A maioria das empresas não podem se dar ao luxo de serem pioneiras em novas tecnologias ou tentar fazê-la desconsiderando o caminho crítico para os negócios.

Pela mesma razão, muitas vezes é aconselhável evitar a reescrita em uma nova linguagem (ou mesmo algo aparentemente inofensivo, como passar do Python 2 para o 3) no mesmo projeto, pois será duplamente difícil depurar quaisquer diferenças de comportamento encontradas ao longo do caminho.

Aconteça o que acontecer, não tente inventar uma maneira totalmente nova de fazer microservices ou qualquer outra coisa. Se acha que precisa inventar a própria solução para o problema, ao invés de adotar uma solução conhecida, diria que provavelmente está indo pelo caminho errado. Continue procurando soluções que já existam, levante questionamentos e resolva o problema buscando soluções fora da empresa.

#7 Prepare o dinheiro para investir em ferramentas

Apesar de todas as limitações, uma arquitetura monolítica tem vários benefícios intrínsecos. Uma delas é que geralmente é simples. Ter um único pipeline e um único conjunto de ferramentas de desenvolvimento é algo trivial. Aventurar-se em uma arquitetura distribuída envolve muita complexidade adicional e há muitas partes a serem consideradas, principalmente se esta for a primeira vez em que está fazendo uma refatoração. Precisará compor um conjunto de ferramentas para tornar a experiência do desenvolvedor palatável, possivelmente escrever algumas por conta própria (embora deva alertar que deva evitar essa possibilidade) e levar em consideração a curva de aprendizado para tudo isso também.

É verdade que, operar uma arquitetura de microservices é muito diferente de operar um monólito, pois precisará investir em ferramentas de monitoramento e deverá planejar um período de aprendizado e ajuste à medida que a empresa acumula experiência operacional.

E essas diferenças operacionais são tanto organizacionais quanto técnicas. Se muitas equipes diferentes estão desenvolvendo e implantando serviços independentemente umas das outras, talvez também seja necessário repensar canais, formas e normas de comunicação.

Pode muito bem valer a pena, mas não deixe que esses "problemas não centrais" o peguem desprevenido.

Concluindo

Os sistemas legados fazem parte de nossa vida e sempre farão. O mundo evolui cada vez mais rapidamente e sempre seremos confrontados com algum tipo de dívida técnica. Só precisamos aceitar isso como parte de nossa existência como desenvolvedores.

O monólito é uma daquelas dívidas técnicas que a maioria de nós conhece, e é possível que estejamos enfrentando isso agora. Pode ou não ser um problema urgente, mas se realmente for, precisamos fazer um esforço para separá-lo gradualmente e certificá-lo de obter a adesão de todos os envolvidos.

Haverá dragões, mas ficará bem se fizer isso de maneira sensata e considerar as duras lições aprendidas daqueles que o antecederam. Fique tranquilo, você não está sozinho.

Acompanhe as novidade deste espaço para se aprofundar nos desafios técnicos envolvidos e algumas ideias sobre como mitigá-los.

E já que está aqui, talvez ache o Garden uma ferramenta útil, caso procure trabalhar com containers e Kubernetes durante a refatoração.

Sobre o autor

Jon Edvald é CEO e cofundador da Garden, que cria uma plataforma de desenvolvimento e teste open source para Kubernetes. Durante os mais de 10 anos de desenvolvimento de software, ocupou cargos de liderança em engenharia com Clue e QuizUp, sendo cofundador e CTO da CLARA (adquirida pela Jive Software). É apaixonado pela experiência de desenvolvedor, abstrações, música e música abstrata.

Avalie esse artigo

Relevância
Estilo/Redação

Conteúdo educacional

BT