Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Complexity Hell: Técnicas para lidar com micros...

Complexity Hell: Técnicas para lidar com microserviços legados, iFood Lunch & Learn

More Decks by Jessica Pauli de C Bonson

Other Decks in Technology

Transcript

  1. • Graduação / Mestrado em Ciências da Computação • 10+

    anos de experiências em diversas techstacks e projetos OLÁ! Eu sou Jéssica Bonson Staff Engineer @ iFood
  2. Tópicos 1. Monolithic Hell 2. Complexity Hell 3. Como lidar

    com a complexidade? 4. Técnicas para lidar com microserviços legados
  3. • …mas novas demandas por features e escala vão chegando…

    Arquitetura de Monolito e isso é bom, quer dizer que o produto está sendo um sucesso!
  4. • Monolito é uma boa solução para um produto simples

    • …mas e quando o produto deixa de ser simples? Monolithic Hell
  5. • Tentar entender o sistema é intimidador • Baixa produtividade

    ◦ Testes lentos, filas para deploy, incidentes constantes, testes manuais, conflitos em merges… • Bugs em produção são comuns ◦ E é normal levar dias para achar e consertar eles • Baixa escalabilidade e desperdício de recursos ◦ Uma parte do sistema precisa de mais memória, outra de mais CPU… • Baixa resiliência e tolerância a falhas • Sistema com techstack e bibliotecas desatualizadas Como saber se você está em um?
  6. • Monolitos ainda são uma boa opção para aplicações simples.

    • E é possível atrasar a deterioração do monolito, usando: ◦ Boas práticas de desenvolvimento de software ◦ Código modular, com responsabilidades bem definidas ◦ Boa cobertura de testes automatizados ◦ Equilíbrio de foco entre entrega de features e melhorias de débitos técnicos Disclaimers!
  7. • À medida que uma aplicação se torna mais complexa,

    uma arquitetura de microserviços permite mais escalabilidade, resiliência e produtividade. Arquitetura de Microserviços
  8. • Quando se fala em microserviços é comum focar em

    como construir a arquitetura do zero, dados os requisitos de produto ou a partir de um monolito. • Mas e se a própria arquitetura de microserviços se torna legada? Complexity Hell
  9. • Tentar entender o sistema é intimidador ◦ Mas agora

    você também tem que entender várias bases de código e a relação entre elas • Baixa produtividade ◦ Dependências entre serviços, serviços inchados, responsabilidades espalhadas… • Bugs em produção são comuns ◦ Mas agora eles se espalham entre serviços • Baixa escalabilidade e desperdício de recursos ◦ Uma parte de um serviço precisa escalar com requisições sync, outra com async, outra usa mais CPU… • Baixa resiliência e tolerância a falhas ◦ Requisições síncronas criam gargalos e dependências temporais • Sistema com techstack e bibliotecas desatualizadas Os sintomas são parecidos, mudam os detalhes
  10. • Os mesmos cuidados com monolito também se aplicam para

    microserviços. ◦ modularidade, testes automatizados, boas práticas, não acumular débitos… • Quanto mais complexa a arquitetura, mais rápido ela se tornará legada. ◦ Busque simplicidade! Cuidados
  11. • Complexidade se refere mais ao que é difícil manter

    do que ao que é difícil fazer. • Tem forte impacto na velocidade de desenvolvimento, na resiliência e na escalabilidade. O que é complexidade?
  12. • Requisitos funcionais podem ser implementados de várias formas. ◦

    Diferentes decisões técnicas acarretam diferentes complexidades. • Existe pouca relação entre os requisitos funcionais e a escolha de arquitetura. Decisões Técnicas
  13. • Todas essas arquiteturas podem atender os requisitos funcionais. Microserviços

    com Orquestração Microserviços com Coreografia Monolito “Monolito Distribuído”
  14. • Se não há relação entre os requisitos funcionais e

    a arquitetura, então para que ela serve? • A arquitetura define os requisitos não-funcionais do produto, ou seja, a qualidade do sistema. ◦ A decomposição das responsabilidades da aplicação e os relacionamentos entre elas determinam as -ilities. Requisitos Não-Funcionais
  15. • Velocidade de desenvolvimento ◦ debuggability, maintainability, extensibility, testability, deployability,

    code quality… • Confiança ◦ availability, reliability, durability, resiliency, fault tolerance, data consistency… • Escalabilidade ◦ modularity, capacity, throughput, performance, operability… • Segurança • Custo Requisitos Não-Funcionais
  16. • Não existe ‘bala de prata’, toda decisão de arquitetura

    tem prós e contras. • Perguntas a serem respondidas: ◦ Os ‘contras’ são aceitáveis? ◦ Os ‘prós’ são necessários? ▪ Cuidado com a otimização prematura! Trade-Offs de Arquitetura
  17. • É algo vivo, que evolui à medida que o

    produto cresce. ◦ Não tente criar algo perfeito e eterno • O que não quer dizer que é para fazer de qualquer jeito! • Não temos como impedir as mudanças, mas podemos guiá-las e planejar para elas. O que é arquitetura?
  18. • Responsabilidades bem-definidas • Princípio de ‘Information hiding’ Como planejar

    para mudanças? “Be worried about what happens between the boxes, and be liberal in what happens inside.” Martin Fowler
  19. ‘Information hiding’ a nível de domínios Promotions Recommendations Sales Fácil

    de mudar Difícil de mudar Marketing Domain Customer Domain Stock Domain
  20. Por que quebrar um microserviço? • Microserviços legados tem problemas

    muito semelhantes a monolitos legados… ◦ …mas com algumas complexidades a mais • Importante ter um mindset de “arquitetura sacrificável” ◦ O código precisar ser sacrificado é sinal de sucesso do produto ◦ Ainda é importante ter qualidade, para o código se deteriorar mais lentamente ◦ Modularidade é essencial ◦ Evita otimização prematura
  21. Como quebrar um microserviço? • Motivo? ◦ Complexidade Procure por

    domínios ◦ Performance Procure por bottlenecks ◦ Time to market Procure por volatilidade • Trade-off entre benefício e dificuldade da refatoração
  22. Como não quebrar um microserviço? • Não faça refatorações “Big

    Bang” ◦ Além dos riscos ao colocar em produção, também há o risco de nunca colocar em produção. Por isso, faça mudanças incrementais. “Se você fizer uma refatoração Big Bang, a única coisa garantida é o Big Bang.” Martin Fowler
  23. Como quebrar por domínio? • Muitas fontes e literatura explicam

    como modelar uma arquitetura do zero, a partir das regras de negócio, ou como quebrar e modificar um sistema dado que você sabe onde mexer…
  24. Como identificar domínios a partir do código? • …mas e

    quando as regras de negócio não foram bem definidas, e o código só foi surgindo? Como entender ele e descobrir onde quebrar as responsabilidades?
  25. Como identificar domínios a partir do código? • Exemplo prático

    com a aplicação ‘Call Records API’ ◦ Github: shorturl.at/ehp03 ◦ “Uma API que recebe detalhes de chamadas telefônicas e calcula a conta mensal para um número de telefone”
  26. 1) Análise das Dependências do Código • Objetivo: Visualizar mais

    facilmente quais são os domínios que já existem no código. • Passos: ◦ Entender a estrutura do programa dado só classes, métodos e como eles se comunicam. ◦ Considerar apenas código que implementa regras de negócio, e que é chamado por outras partes do código (‘público’). ◦ Categorizar as dependências em grupos. ◦ Não se prenda a detalhes técnicos da linguagem ou do algoritmo.
  27. Call Records API • ~1000 linhas de código Python (~600

    com implementação das regras de negócio) • ~2h para entender o código
  28. 2) Fluxo das Dependências do Código • Objetivo: Visualizar como

    os domínios do código interagem, para mapear os contextos que existem no código. • Passos: ◦ Cada componente aparece apenas uma vez ◦ Ligue cada componente ao componentes que ele interage ◦ Organize o diagrama para os componentes ficarem em ‘clusters’, tentando não deixar que as linhas se sobreponham ▪ Se as linhas estão muitos sobrepostas, isso indica que o código não está modular, e é boa ideia refatorá-lo para consertar isso antes de quebrá-lo.
  29. 3) Mapear Responsabilidades e Domínios • Objetivo: Entender como a

    implementação dos requisitos pode ser quebrada em domínios • Questões: ◦ Os contextos identificados são sobre quais responsabilidades e entidades? ◦ Um serviço deve ter uma responsabilidade única e bem-definida. Dado isso, esses contextos deveriam estar nesse serviço, ou em outros? ◦ Quais são os requisitos funcionais que esse serviço está implementando? ◦ Quais interações externas ocorrem com esses contextos? ▪ Quais são as chamadas síncronas e assíncronas que o código recebe e faz? ▪ De quais domínios externos essas chamadas fazem parte?
  30. Tipos de Refatoração • Decomposição (‘quebrar’) ◦ Strangler Fig Pattern

    ◦ Branch by Abstraction Pattern • Modificação ◦ Parallel Run Pattern ◦ Expand-Contract Pattern • Combinação
  31. Branch by Abstraction Pattern • Usado como preparação para o

    Strangler Fig Pattern “Monolith To Microservices”, Sam Newman Técnica de Decomposição:
  32. Parallel Run Pattern • É importante comparar resultados e acompanhar

    o uso. • Podem receber as mesmas requisições e só um ser usado, ou funcionar como um canário. Service 1 App Service 1 App Service 2 Service 2 App Técnica de Modificação:
  33. Expand-Contract Pattern • Exemplo: Renomear um campo A para B

    1. Adiciona o campo B, sem usar 2. Escrita tanto em A como em B 3. Leitura apenas em B 4. Aguardar/Corrigir bugs 5. Remover campo A Técnica de Modificação:
  34. “Arquitetura é o que acontece, não o que é planejado.

    Se você não participa do processo de implementar a arquitetura na prática, você não é um arquiteto, é um sonhador.” Martin Fowler