5 pontos por GN⁺ 2023-10-31 | 1 comentários | Compartilhar no WhatsApp
  • O backend geralmente começa como um monólito, mas quando várias equipes de funcionalidade passam a mexer na mesma base de código, o acoplamento aumenta e a velocidade de mudança pode cair
  • Microsserviços são uma forma de dividir serviços por função de negócio para obter deploy independente e autonomia de equipes pequenas
  • Se os serviços ficarem pequenos demais, a carga operacional cresce mais do que os benefícios, e o nome “micro” pode até atrapalhar o julgamento
  • Uma adoção total traz uma ampla gama de custos: padronização, provisionamento de recursos, proteção para chamadas remotas, CI/CD, operação e até consistência eventual
  • Em geral, é mais seguro aprender bem os limites dentro de um monólito e separar aos poucos quando as dores do crescimento ficarem maiores; uma abordagem microservices-first faz sentido quando já há experiência e uma plataforma preparada

Limitações que aparecem quando o monólito cresce

  • O backend de uma aplicação JavaScript moderna de página única normalmente começa oferecendo uma API HTTP RESTful e usando um banco de dados relacional como um único serviço web stateless
  • Esse serviço é composto por componentes ou bibliotecas que implementam diferentes funções de negócio
  • Quanto mais equipes de funcionalidade participam da mesma base de código, maior tende a ser o acoplamento entre componentes e mais fácil fica haver sobreposição entre áreas de trabalho das equipes
    • A produtividade cai, e fica mais difícil prever o impacto das mudanças
  • Quando a base de código fica complexa o suficiente, ninguém mais entende tudo por completo, então implementar novas funcionalidades e corrigir bugs passa a levar muito tempo
  • Mesmo que o backend esteja dividido em bibliotecas por equipe, mudar uma biblioteca no fim ainda leva ao redeploy do serviço
    • Se entrar um bug como vazamento de memória, o serviço inteiro pode ser afetado
    • Se um build com problema for revertido, a velocidade de todas as equipes é impactada, não só da equipe que introduziu o bug

A autonomia trazida pelos limites entre serviços

  • Uma forma de reduzir as dores de crescimento de um backend monolítico é dividir o backend em um conjunto de serviços com deploy independente
  • Os serviços se comunicam por APIs, e APIs criam limites mais difíceis de violar do que os limites entre componentes dentro do mesmo processo
  • Essa arquitetura é chamada de arquitetura de microsserviços, mas a expressão micro pode induzir ao erro
    • Os serviços não precisam necessariamente ser pequenos
    • Serviços com funcionalidade demais limitada podem gerar mais carga operacional do que benefícios
  • Um nome mais apropriado poderia ser service-oriented architecture, mas esse nome também carrega bagagem antiga

Velocidade gerada por equipes pequenas e serviços independentes

  • Ao dividir o backend em serviços por função de negócio, cada serviço pode ser desenvolvido e operado por uma pequena equipe única
  • Equipes pequenas são mais eficazes porque o custo de comunicação aumenta ao quadrado conforme o tamanho da equipe
  • Quando cada equipe define seu próprio cronograma de releases e controla sua base de código, a coordenação entre equipes diminui e a tomada de decisão fica mais rápida
  • Se a base de código do serviço for pequena, ela é mais fácil de entender pelos desenvolvedores e o tempo de adaptação de novos contratados também diminui
    • Bases de código menores ajudam a reduzir lentidão em IDEs, o que também melhora a produtividade do desenvolvedor
  • Graças a limites fortes entre serviços, o desenvolvedor só precisa entender uma pequena parte do backend para alterá-la, e não o sistema inteiro
  • Cada serviço pode escalar de forma independente e escolher a stack tecnológica mais adequada às próprias necessidades
    • Quem consome a API não precisa se preocupar com como a funcionalidade foi implementada internamente
    • Fica mais fácil experimentar e avaliar novas tecnologias sem afetar outras áreas do sistema
  • Cada microsserviço pode ter seu próprio modelo de dados e seu próprio armazenamento de dados
    • O desenvolvedor pode alterar o schema sem impactar outros serviços

Os custos reais adicionados pelos microsserviços

  • Microsserviços adicionam muito mais partes móveis ao sistema como um todo, e esse custo não é grátis
  • O custo de adotar microsserviços por completo só vale a pena quando pode ser amortizado de forma distribuída entre dezenas de equipes de desenvolvimento
  • Experiência de desenvolvimento

    • É possível usar linguagens, bibliotecas e armazenamentos de dados diferentes em cada serviço, mas isso pode dificultar a manutenção da aplicação
    • Se as stacks de software forem totalmente diferentes, fica mais difícil para um desenvolvedor migrar de uma equipe para outra
    • Para oferecer funcionalidades comuns necessárias a todos os serviços, como logging, é preciso manter bibliotecas para cada linguagem adotada
    • É necessário algum nível de padronização
    • É possível incentivar de forma leve o uso de certas tecnologias oferecendo uma boa experiência de desenvolvimento para equipes que sigam a linguagem e o portfólio tecnológico recomendados
  • Provisionamento de recursos

    • Para suportar muitos serviços independentes, é preciso conseguir criar com facilidade servidores, armazenamentos de dados e outros recursos genéricos
    • Não se deve deixar cada equipe inventar seu próprio jeito de criar recursos
    • Os recursos provisionados também precisam ser reconfigurados, e lidar com isso exige bastante automação
  • Comunicação

    • Chamadas remotas têm custo alto e introduzem novas formas de o sistema falhar
    • Para se proteger contra falhas, são necessários mecanismos defensivos como timeouts, retries e circuit breakers
    • Para reduzir a perda de desempenho da comunicação em rede, também é preciso usar processamento assíncrono e batching
    • Esses fatores aumentam a complexidade do sistema
    • Monólitos também podem sofrer problemas parecidos por causa do acesso de clientes remotos e do uso de APIs de terceiros, mas em escala menor
  • Integração contínua, entrega contínua e deploy

    • Integração contínua garante que alterações de código sejam mescladas na branch principal depois que builds e testes automáticos forem executados
    • Depois que a alteração é mesclada, ela deve ser automaticamente publicada e implantada em um ambiente parecido com produção
    • Nesse ambiente, devem ser executados testes de integração e end-to-end para verificar se o microsserviço não quebra outros serviços dos quais depende
    • Testar um microsserviço individual não é mais difícil do que testar um monólito, mas o teste de integração de todos os microsserviços é muito mais difícil
    • Quando serviços individuais interagem, podem surgir comportamentos muito sutis e inesperados
  • Operação

    • Diferentemente de um monólito, alocar uma equipe de operações separada para cada equipe responsável por um serviço custa muito mais caro
    • Normalmente, a equipe que desenvolve o serviço também assume o on-call dele
    • Em cada sprint, a equipe precisa decidir o que priorizar entre trabalho de desenvolvimento e carga operacional, e isso gera atrito
    • Depurar falhas do sistema também fica mais difícil
    • Não dá para subir a aplicação inteira na máquina local e depurá-la passo a passo
    • Como há mais partes móveis, também há mais formas de falha
    • Logging e monitoramento de qualidade tornam-se importantes em todos os níveis
  • Consistência eventual

    • Quando a aplicação é dividida em vários serviços, o modelo de dados deixa de existir apenas em um único armazenamento de dados
    • Atualizar atomicamente registros em armazenamentos de dados diferentes e garantir consistência forte é lento, caro e difícil de implementar
    • Essa arquitetura normalmente precisa aceitar consistência eventual

Quando separar

  • Dividir uma aplicação em serviços aumenta bastante a complexidade do sistema como um todo
  • Em geral, é melhor começar com um monólito e só quebrá-lo quando houver motivo suficiente para isso
  • Como é difícil definir corretamente os limites entre serviços, costuma ser mais fácil mover esses limites dentro do monólito até encontrar o ponto adequado
  • Quando o monólito estiver maduro o suficiente e as dores do crescimento começarem a ficar grandes, será possível extrair microsserviços um a um
  • Uma abordagem microservices-first só é adequada quando já existe experiência prévia, e quando a plataforma necessária já foi construída ou o tempo para construí-la foi levado em conta

1 comentários

 
GN⁺ 2023-10-31
Opiniões do Hacker News
  • Concordo em geral com o texto, mas, vendo pelo outro lado, há casos em que vale a pena arcar com o custo: você pode isolar problemas de compatibilidade com dependências de terceiros antigas em um serviço separado e evitar uma refatoração dolorosa ou uma reimplementação própria; impedir que restrições de deploy de um sistema crítico de alta disponibilidade bloqueiem o deploy de outros sistemas; e isolar restrições de design que grandes clientes não conseguem mudar
    Não quer dizer que seja grátis; quer dizer que pode ser um custo que vale pagar para não transformar um monólito simples em um monte de lixo, não deixá-lo balançando com deploys arriscados, ou não ficar preso a um parceiro de negócios com uma stack técnica pior

    • Para mim, isso parece simplesmente ter um ou dois serviços. Não acho que isso seja o mesmo que “microsserviços”
      Microsserviços não são a abordagem de fazer com que os componentes internos sejam, por padrão, serviços em vez de bibliotecas ou classes?
    • Para acrescentar mais um ponto, há a vantagem de poder usar facilmente linguagens de programação diferentes. Nem toda linguagem se encaixa bem em todo problema
      Se um serviço de inferência de machine learning for em Python, a UI com renderização server-side em Rails e um serviço com muito I/O e concorrência em Go, a carga extra de separar esses três em serviços distintos pode ser justificada
    • Há muitas formas de projetar bem, e isso não significa que se deva adotar microsserviços precipitadamente
      Eu até gosto de microsserviços, mas otimização prematura e escala prematura podem ser tão ruins quanto a dívida técnica que surge quando depois é preciso otimizar em uma direção completamente diferente
    • No caso 1, não entendo por que extrair para um serviço separado seria melhor do que encapsular com uma interface que tenha uma API clara
    • Esses casos parecem se aplicar a menos de 10% da base de código total
  • O momento de extrair algo para um serviço separado é quando surge um problema que não pode ser resolvido de forma administrável sem fazer isso
    Aumentar a complexidade arquitetural para forçar limites não pode ser a solução para falta de disciplina organizacional, mas empresas de tecnologia de médio porte tratam isso assim o tempo todo. Se limites de domínio fracos estão causando problemas, extrair serviços provavelmente não vai resolver bem

    • “O último momento responsável é uma estratégia de adiar uma decisão até o ponto em que o custo de adiá-la ainda mais se torna maior do que o custo de decidir agora”
      Citação: https://www.oreilly.com/library/view/software-architects-han...
    • Dizem que aumentar a complexidade arquitetural para forçar limites não é solução para falta de disciplina organizacional, mas na prática isso é feito o tempo todo
      CI/CD que bloqueia PRs até os testes passarem também é uma solução técnica cara para resolver um problema de disciplina organizacional
    • Parece uma SISP procurando um problema. Ou como jogar uma solução em cima de um problema sem entender a causa raiz
    • No HN parece haver um meme generalizado de que microsserviços nunca podem ser justificados, o que é estranho porque o setor como um todo não é assim
      Todo mundo aceita como válido que a resolução de nomes de domínio seja feita por um serviço externo, e quase ninguém integra um resolver DNS recursivo e cache ao monólito. Mas essa separação de responsabilidades, mesmo sendo antiga, não costuma ser aceita como exemplo
    • Sempre achei que este é o melhor exemplo de execução adiada. É surpreendente ver com que frequência as empresas erram nisso
      O problema parece ser que, quanto mais “bom” é o funcionário, mais vontade ele tem de demonstrar valor, o que leva a overengineering e, no fim, vira um inferno
  • Microsserviços
    grug se pergunta por que cérebros grandes pegam o problema mais difícil, o de decompor corretamente um sistema, e ainda colocam chamadas de rede no meio
    para grug isso parece muito confuso
    https://grugbrain.dev/#grug-on-microservices

    • grug parece nunca ter passado por situações em que grandes equipes pisam nos domínios e modelos de dados umas das outras, ficam presas a implementações específicas, e lançar funcionalidades por equipe exige um enorme esforço organizacional. Microsserviços e a abordagem em que cada um controla seu próprio armazenamento de dados aumentam a velocidade das equipes
      “Queremos modernizar a abordagem de FOO_TABLE por SCALE_REASONS e migrar de MySQL para DynamoDB, mas 32 das 59 equipes acessam FOO_TABLE diretamente ou chamam diretamente métodos private da nossa classe. Como as prioridades são diferentes, essas equipes não conseguem migrar para usar FOO_SERVICE nem mudar suas consultas para usar tabelas particionadas. Agora escalar FOO_TABLE vira um trabalho de vários trimestres, e precisamos permitir que as equipes atualizem devagar. Talvez daqui a 1 ou 2 anos possamos aposentar a abordagem antiga que está pegando fogo agora. Até lá, aproveite o on-call”
      Com microsserviços, a equipe percebe que a tabela não escala, mas os dados são fornecidos por uma API. No sprint seguinte, planeja e executa a migração, e os usuários da API sentem que ficou muito mais rápido
    • Tipos estáticos não são indispensáveis para autocomplete. A JetBrains tem IDEs que oferecem autocomplete mesmo em linguagens como Ruby ou Python
      Se você abrir o REPL do Ruby moderno, já obtém, em termos de autocomplete e verificação de sintaxe, boa parte do que esperaria de uma IDE para linguagem tipada estaticamente
    • Introduzir chamadas de rede é algo poderoso. Na prática, cria-se um limite intransponível imposto fisicamente, e os dois serviços precisam tratar um ao outro como isolados
      Isolamento não deve ser visto como algo trivial; é um dos recursos mais poderosos que se pode colocar em software. Pode melhorar desempenho, criar limites de falha e fornecer limites de segurança
      Isso é o mesmo conceito fundamental do modelo de atores. Em vez de dois componentes compartilharem e modificarem a memória um do outro, dois sistemas isolados, como atores ou microsserviços, comunicam-se apenas por meio de um protocolo definido
  • Acho que as pessoas entendem modularidade de forma errada. Modularidade é importante, mas passei a pensar que existe outro princípio arquitetural importante: o princípio do vórtice único
    Em um sistema de software, um vórtice é um loop no fluxo de dados. Se você envia dados para algum lugar e recebe de volta o resultado processado, ou se é afetado por esses dados de alguma forma, existe um vórtice. Uma variável mutável é um exemplo de vórtice bem pequeno
    O princípio do vórtice único significa que, idealmente, um sistema de software deveria ter apenas um vórtice; em outras palavras, todos os componentes deveriam saber em que direção o seu vórtice gira
    Quando se juntam módulos que formam dois vórtices, a composição é fácil se as direções dos vórtices combinam; se forem opostas, fica complicado porque é preciso decidir qual será a direção do novo vórtice. Por isso, o melhor é que os vórtices de todos os módulos tenham a mesma direção e formem um único vórtice
    Esse princípio generaliza ideias como o padrão Flux, CQRS, event sourcing e imutabilidade

    • Ótimo ponto, e daria para escrever vários textos só sobre esse assunto. O serviço A pode chamar B, B pode chamar C, e C pode voltar a chamar A; aí surgem problemas
      Ou algo inesperado pode acontecer em A e acabar bloqueando C. Idealmente, um pai deveria chamar apenas seus filhos e não depender deles; se isso falha, a arquitetura também falhou
    • Gosto desse conceito
      Ao olhar para um diagrama de arquitetura, metade da batalha é entender o que é assíncrono/síncrono, push/pull, e a direção e a ordem do fluxo
      Barramentos de serviços corporativos e filas de mensagens parecem soluções para criar vórtices onde as duas direções não se encaixam
    • Esse conceito de vórtice é interessante. Fico curioso se há livros ou materiais online que valham a pena estudar
    • Não entendi bem o penúltimo parágrafo, especialmente a parte da justificativa. Fico curioso se você poderia explicar em mais detalhes
  • Há um trecho que diz que o problema é “o número de bibliotecas que precisam ser mantidas para fornecer funcionalidades comuns necessárias a todos os serviços, como logging, uma para cada linguagem adotada”
    Esse é o maior motivo pelo qual abandonamos microserviços. Com as ferramentas de 2023, especialmente em ambientes puramente cloud native ou FaaS de escala infinita, gastar largura de banda mental com essa preocupação é um completo desperdício. Isso vale ainda mais quando a base de clientes é formada por bancos e instituições financeiras, que examinam duramente cada dependência de terceiros
    Hoje operamos com uma única distribuição binária monolítica em .NET, com cerca de 250 MB comprimida com gzip, e não há nenhum sinal de rachadura. Se você está preocupado, de forma minuciosa, com uma distribuição SaaS de 10 a 100 MB dizendo coisas como “meu exe não cabe mais no L2”, pode ficar tranquilo. A jornada do software monolítico ainda nem começou
    Se chegar o momento de reescrever uma dessas pilhas de lixo, não seria muito mais fácil ter tudo em um único lugar, com cada commit globalmente consistente?

    • Vejo isso como um falso dilema. A maioria das organizações de microserviços pelas quais passei mantinha apenas 2 ou 3 linguagens aprovadas por motivos como esse, e, se uma equipe mostrasse que não havia outra opção, a liderança podia permitir uma exceção
      Microserviços não significam terra sem lei, nem que cada equipe possa agir sem considerar a organização como um todo. Pode e deve haver regras para manter algum grau de consistência entre equipes
    • Na verdade, isso é muito mais fácil com microserviços. Há uma interface clara a ser mantida, e o código não está entrelaçado com o restante do monólito como uma trança francesa
      O melhor código é aquele que é fácil jogar fora e reescrever. Na prática, código antigo passa por mais mãos, piora mais e, acima de tudo, ninguém quer mantê-lo
    • O que importa é quantos desenvolvedores trabalham nesse monólito. O tamanho do binário normalmente não é o motivo pelo qual equipes começam a dividir um monólito
    • A frase “não seria muito mais fácil se tudo estivesse em um único lugar e cada commit fosse globalmente consistente?” sempre me parece meio engraçada. Os dois lados costumam dizer isso, mas raramente pensam pela perspectiva do outro
      Quem prefere microserviços diz que é mais fácil alterar ou reescrever porque há um contrato claro sobre como o serviço deve funcionar e porque a base de código daquele serviço é muito menor
      O lado do monólito diz que é mais fácil alterar ou reescrever porque tudo é um grande novelo, então, para mudar um fio, basta saber onde esse fio se cruza com os outros
      Não sei quem está certo. É provável que o monólito seja melhor para veteranos que passaram anos olhando a base de código no microscópio, e microserviços sejam melhores para os demais
    • Ninguém diz que todos os microserviços não podem usar a mesma linguagem
  • Do ponto de vista de gerenciamento de releases, a migração de um monólito para microserviços muitas vezes acontece pelos motivos errados
    O único motivo realmente válido para a mudança parece ser um problema de escalabilidade, como um gargalo de desempenho. O resto é apenas transferir a complexidade do desenvolvimento de software para a manutenção do sistema
    Claro que os desenvolvedores vão gostar, porque diminui bastante a necessidade de se coordenar com outras equipes. Mas deixar claro quando e como uma funcionalidade é implementada, devidamente testada em todos os microserviços, ativada em produção e gerenciada de forma centralizada fica muito mais difícil se a comunicação entre equipes de desenvolvimento não for madura o suficiente. E essa imaturidade muitas vezes é justamente o motivo real para dividir o monólito em primeiro lugar

    • Há muitos motivos válidos e muitos motivos errados. Se há vários stakeholders, requisitos de negócio mudando constantemente e mais de 10 desenvolvedores, pode haver bons motivos para ter unidades que possam ser implantadas, testadas e lançadas independentemente
      Por outro lado, lidar com vários microserviços com poucos desenvolvedores e um contexto bem definido é sofrido
      A afirmação de que “o resto é transferir a complexidade do desenvolvimento de software para a manutenção do sistema” faz sentido se o software estiver em desenvolvimento ativo. Desenvolvimento é caro. O custo de manter sistemas distribuídos para uma equipe grande pode ser menor do que o custo de desenvolver um monólito enorme; no fim, depende da situação
    • Esse também é o único motivo pelo qual queremos separar esta parte do app em um componente à parte. Ela ficou grande demais para ser mantida de forma eficaz, e o restante do app ficará como está
  • Onde está o texto “O custo dos monólitos”? Não vejo isso aqui. É só porque todo mundo está implementando microsserviços de forma ignorante que só esse problema aparece
    Se todo mundo estivesse implementando monólitos de forma ignorante, haveria uma quantidade absurda de textos do tipo “monólitos são ruins”
    As pessoas não entendem que os dois sistemas acabam gerando a mesma quantidade de problemas. É a diferença entre fazer um elefante trabalhar e fazer 1000 ratos trabalharem. Ambos terão problemas; os problemas só serão diferentes
    Escolher um dos dois não faz os problemas desaparecerem. Qualquer lado vai ter problemas, e você precisa escolher um e fornecer soluções. Se a arquitetura for o maior obstáculo de uma empresa, eu gostaria de trabalhar lá

    • O motivo de hoje estarmos mergulhados demais em microsserviços é que no passado houve uns 8 trilhões de textos dizendo monólitos são ruins. Agora é uma reação a perceberem que a relação custo-benefício não serviu para eles
  • Se um monólito estiver bem decomposto, em que ele difere de microsserviços colocados no mesmo lugar? Provavelmente só na interface. Chamadas de função viram RPC, e você aceita um pouco de overhead para obter benefícios como tratar componentes separadamente, por exemplo para aplicar patches
    Em que microsserviços distribuídos diferem de microsserviços no mesmo local? O deploy é mais complexo, mas você consegue posicionar os processos de forma inteligente em hardware mais adequado. Os modos de falha aumentam, mas você consegue maior tolerância a falhas
    Não há resposta universal aqui. Se você precisa dos benefícios, pague o custo. Vejo esses debates de microsserviços versus monólitos como resultado de aplicar mal um padrão, da falta de ferramentas que facilitariam a vida ou, na maioria das vezes, de continuar sem refatorar e redesenhar um software de 10 anos até ele ficar doloroso de trabalhar, independentemente da arquitetura inicial

    • Sair de um monólito para microsserviços não é uma mudança trivial, por melhor que ele tenha sido decomposto no início. Claro que, se o design for ruim, a transição fica mais difícil
      Dizer que “chamadas de função viram RPC” parece simples, mas no momento em que isso acontece o app cliente precisa lidar com todos estes caminhos de execução: servidor DNS inacessível, falha ao resolver hostname, host inacessível, conexão recusada, autenticação recusada, certificado TLS não confiável, limite de taxa excedido, 301 movido permanentemente, atraso na preparação do resultado e timeout
      Mesmo em uma aplicação bem decomposta, para lidar com isso de forma robusta provavelmente será necessário redesenhá-la para permitir filas assíncronas, limitação da taxa de requisições, cache de resultados, retries com backoff e logging, credenciais de cliente configuráveis, trust stores configuráveis, URLs de recursos configuráveis e registro de falhas
      Em chamadas de função locais, também serão necessárias funções RPC e parâmetros adicionais para fornecer dados que antes estavam no contexto. Além disso, a UI do monólito talvez precise comunicar ao usuário latências e falhas de rede que antes eram impossíveis
      Refatorar até o monólito mais bem feito para microsserviços exige um esforço considerável
    • Por trás da frase “chamadas de função viram RPC” vêm novos modos de falha e muito mais encanamento
      É seguro tentar novamente essa chamada RPC? E backoff exponencial? O load balancer da API está funcionando corretamente? Então também é preciso monitoramento. Como fazer tracing entre microsserviços? Agora passa a ser necessário algo como OpenTelemetry
      Quanto mais difícil é depurar com breakpoints em uma arquitetura de microsserviços? Como reverter uma transação de banco de dados entre dois microsserviços? Uma simples chamada de função de repente fica muito mais complexa
    • Ao discutir microsserviços, quem é a favor quase sempre esquece a parte micro, que é central ao conceito. Serviços em si todo mundo já conhece e, se precisar, cria; não é um conceito que precise de convencimento
      Toda vez que defendem esse conceito, deixam de fora do cálculo a fragmentação criada pela exigência de que os serviços sejam muito pequenos. Mais concretamente: se você tem um monólito e um microsserviço, isso não são microsserviços. A palavra microsserviços implica que tudo está dividido em pequenos serviços e que não há monólito
      A maior parte da argumentação pró-microsserviços desmorona no momento em que se percebe que eles precisam necessariamente ser “micro”. E, se você abandona essa exigência, não sobra nenhuma proposta nova ou profunda
    • Do ponto de vista do desenvolvedor, a diferença está nas interfaces. Existem todo tipo de ferramentas para manter um monólito sincronizado e correto, mas as ferramentas que ajudam na comunicação entre processos não conseguem fazer avaliação estática e também não são nem um pouco interativas
      Do ponto de vista operacional, dizer que “o deploy é mais complexo” é um eufemismo enorme. Cada pacote é algo que precisa ser gerenciado separadamente, com características e problemas próprios
    • Você perde transações atômicas. Por causa disso, toda operação de negócio fica algumas ordens de magnitude mais complexa
  • Assim como desenvolvedores front-end acham que não dá para criar uma “aplicação web moderna” sem frameworks ou bibliotecas de front-end como React/Vue/Svelte, hoje parece circular a ideia de que um “monólito” é como executar uma massa de piche gigantesca e assustadora em uma única instância, que “não escala”; isso não faz sentido
    Outra coisa que se nota é que a quantidade total de código fica muito maior, e a maioria dos serviços acaba sendo 20% código de negócio/domínio e 80% tratamento de envio e recebimento de mensagens de rede. Por mais que você esconda, isso continua lá, e de algum modo é preciso lidar com a rede
    Assim como a loucura do front-end, esse culto aos microsserviços só vai acabar quando a economia quebrar e não houver mais dinheiro para sustentar essas torres de Babel da perdição
    Dito isso, microsserviços também têm seu lugar. Eles fazem sentido dentro de algumas empresas que obtêm mais valor do que o custo

    • O que as pessoas deixam passar sobre microsserviços é que o objetivo normalmente não é resolver um problema técnico, mas sim problemas de organização e pessoas
      Há benefícios técnicos, como escalabilidade independente por serviço, mas o maior benefício é estabelecer fronteiras claras de propriedade e evitar acoplamento excessivo desnecessário
      Se uma equipe pequena está criando um único produto, é provável que o problema organizacional que microsserviços resolvem ainda não exista, então talvez eles não sejam necessários. Nesse caso, microsserviços são otimização prematura: você está pagando um custo para resolver um problema que ainda não existe
    • React/Vue/Svelte não são frameworks, são bibliotecas de view, e vou defender essa posição até o fim
      Indo além, a complexidade de front-end está toda na cabeça: https://bower.sh/front-end-complexity
    • Concordo que muitos sites exageram no uso de JavaScript e frameworks. Mas, ao criar uma aplicação web de nível desktop, fico curioso sobre o que se deveria usar para não virar uma bagunça enorme ou acabar reinventando conceitos que já existem nesses frameworks
  • O texto parece partir do pressuposto de que a organização de desenvolvimento está completamente quebrada e fora de controle. Coisas como não decidir o que fazer durante o sprint, introduzir às escondidas bibliotecas de terceiros e linguagens desconhecidas, e implantar silenciosamente em produção mudanças incompatíveis
    Se os desenvolvedores não forem idiotas, microsserviços também parecem ser mais fáceis

    • Infelizmente, é bastante comum haver idiotas dentro da equipe, ou uma equipe inteira trabalhando no mesmo projeto ser idiota
      Tenho certeza de que microsserviços seriam mais fáceis se você trabalhasse em uma equipe formada por desenvolvedores inteligentes e competentes. Claro que, nesse caso, tudo ficaria mais fácil
    • Todo desenvolvedor inevitavelmente é um idiota nos primeiros meses em um novo emprego. Isso porque leva tempo para absorver as informações necessárias para entender como o sistema existente funciona