Lições Aprendidas Construindo Sistemas Distribuídos com CQRS e Event Sourcing

Patrick Lee Scott Blocked Desbloquear Seguir Seguindo 9 de janeiro

S anos everal atrás, eu tive uma idéia, ou mais de uma unidade realmente. Talvez até uma obsessão. Eu queria construir o santo graal da eficiência no desenvolvimento. Não precisava ser para todos. Eu queria isso pra mim.

Eu queria construir sistemas tolerantes a falhas altamente escaláveis, constituídos por serviços simples que fossem sustentáveis, maleáveis, resistissem ao teste do tempo e, mais importante, fossem fáceis para os humanos entenderem.

Eu queria que meus serviços fossem facilmente testáveis, e eu não queria pensar em como eles funcionavam na produção.

Eu queria que eu e meus colegas de equipe pudéssemos entregar códigos de alta qualidade rapidamente. Quando o código é entregue mais rapidamente, isso significa que sua empresa pode experimentar mais rapidamente e, portanto, encontrar ideias vencedoras mais rapidamente.

Este é basicamente o ponto inteiro do livro “The Lean Startup”.

Construir. A medida. Aprender. Repetir. E assim continua, desde a inicialização até a empresa.

Para vencer, você precisa construir, medir, aprender, repetir, repetir e repetir.

Dá vantagens competitivas aos nossos negócios.

E esperançosamente, isso significa que todos ganham mais, o que significa que nós (ou talvez eu) podemos nos concentrar no que realmente queremos: curtir a vida, escalar, viajar, escrever, passar tempo com minha linda namorada e sermos honestos, provavelmente programando mais alguns … ou demais.

No entanto, não podemos ser apenas mais rápidos. Não podemos nos sacrificar pela qualidade.

Nosso código basicamente alimenta todas as coisas, e todas as coisas não podem estar quebrando o tempo todo! Especialmente quando estou na praia!

Acontece que essas coisas são mais fáceis de dizer do que de fazer. Não é fácil ir lendo o Domain Driven Design e saber o que diabos isso realmente significa na prática.

Eu ouvi os outros dizerem que o tempo gasto em compreender e ser capaz de implementar as técnicas do DDD é equivalente a obter um PhD.

Eu li pela primeira vez DDD em 2007, quando eu estava no segundo ano da faculdade. Eu nem diria que sou um especialista em DDD agora – no entanto, existem alguns conceitos REALMENTE úteis do DDD, e os idiomas de hoje são muito mais poderosos e expressivos do que eram em 2003, quando o livro e seus exemplos foram escritos.

Não é até agora, vários anos depois, que descobri como fazê-lo bem. E o mais importante, já administrei alguns sistemas de produção usando essas técnicas e formalizei minhas visões e abordagens sobre o assunto para poder compartilhar o que aprendi com os outros!

Aqui está a minha opinião: é complicado, mas principalmente por causa da relação sinal-ruído.

Há muito barulho. Deixando de lado os problemas de modelagem, isso ainda deixa literalmente centenas de bibliotecas e abordagens para construir microsserviços porque basicamente significa apenas "um serviço realmente pequeno e focado".

Eu quero ser o sinal forte nesse barulho que você pode seguir para o sucesso.

Além disso, ter um monte de serviços significa um monte de novas dores de cabeça em geral!

Mais serviços para testar!
Mais integrações para testar!
Mais implantações para implantar!
Mais bancos de dados para provisionar!
Mais caches para invalidar!
Mais tudo!

O ato de fazer serviços simples torna sua arquitetura e operações mais complexas.

Apenas faz.

É assim que funciona.

Contudo…

Isso não significa que precisa ser complicado.

Analogia rápida: Alguém se lembra de CSS Sliding Doors Technique?

Isso é quando o CSS era horrível e levava cerca de 100 linhas de código para fazer cantos arredondados.

Agora, é uma linha de código.

As coisas tendem a ficar mais fáceis ao longo dos anos.

E ainda assim, ainda é difícil encontrar um consenso sobre como construir microsserviços!

Mas não se preocupe, estou aqui para direcioná-lo para três áreas-chave que ajudarão você a lidar com a fera de várias cabeças.

1. Aprenda mais padrões de design!

A próxima coisa em engenharia de software é sempre sobre os ombros de seus antecessores. Sem as mentes e pensamentos de milhares de engenheiros que vieram antes do próximo conjunto de pensamentos e padrões, não seria possível.

Se você não ama os padrões já, bem, estou surpreso que você seja um engenheiro! Se você se deparar com um problema, é provável que alguém já tenha resolvido o problema, ou pelo menos alguma variedade dele.

Os padrões de projeto são essenciais para a construção de sistemas altamente escalonáveis e tolerantes a falhas que sejam humanos !

No meu trabalho diário, faço uso de todos os tipos de padrões o tempo todo! Aqui estão vários padrões impressionantes que vêm à mente: Sourcing de Eventos, Padrão de Repositório, Singleton, Fábrica, CQRS, Disjuntores, POJOs e muito mais!

Além dos padrões clássicos, também encontrei alguns padrões de “microsserviço” nos meus anos que ajudam a pensar em projetar grandes sistemas para empresas a partir de uma visão de nível mais alto.

Não há melhor recurso que o clássico "Livro Azul" para você começar com os conceitos. Tão popular que pode ser usado por uma cor e outros engenheiros saberão do que você está falando: Design orientado a domínio: Combater a complexidade no coração do software: Eric Evans .

Quanto aos padrões específicos de microsserviço, aqui estão alguns dos mais comuns que uso: Esses cinco padrões de microsserviços fazem de você um engenheiro melhor.

Se movendo…

2. Objetos são importantes, mas você sabe o que é realmente importante? Eventos e Comandos.

Comandos são como as coisas acontecem. Eventos são o que aconteceu.

Comandos e Eventos são as duas mensagens.

Entidades são o que os eventos aconteceram. Agregados são coleções de entidades relacionadas.

Acontece que todas essas coisas são realmente importantes.

Muitas vezes, com o foco nos princípios OO, você ouvirá pessoas falando sobre Entidades e talvez Agregados, mas os Eventos e Comandos estão perdidos! Isso é ainda pior quando você está apenas atualizando um banco de dados com o novo estado. Toda a história do mundo que você modelou está perdida a cada UPDATE .

Eu acho muito triste. ?

Antes que isso fosse compreendido, os ORMs eram populares, o que tem sido referido como o “Vietnã da Ciência da Computação” por alguns. Nós não vencemos a guerra com ORMs.

O Vietnã da Ciência da Computação · Blog de Ted Neward

Mapeamento Objeto-Relacional é o Vietnã da Ciência da Computação · Coding Horror

Muitos proponentes do Design Dirigido por Domínio evoluíram seu pensamento ao longo dos anos para se afastar do foco nos Substantivos e começaram a inaugurar uma nova era de Eventos. Confira as obras de Greg Young, Udi Dahan e Rinat Abdullin. Até mesmo o Grupo do Google “DDD” foi renomeado para CQRS / ES + AR (Segregação de Responsabilidade por Consulta de Consulta com Terceirização de Eventos em Raízes Agregadas)!

Eventos são a linguagem dos sistemas distribuídos … E a vida realmente.

Ao modelar o mundo, você precisa modelar os Eventos e Comandos do mundo também. Eventos e comandos funcionam muito bem como a linguagem de um sistema distribuído.

Quando eu visualizo sistemas, eu gosto de imaginar formas de papel sendo preenchidas e passadas entre os atores humanos e isso é essencialmente um sistema distribuído, e uma maneira fácil de pensar na consistência final.

inventory.product.catalog rende inventory.product.cataloged

 bus.on (' inventory.product.cataloged ', reactToTheFactThatThisEventHappened) ` 

Expandindo isso, eu também quero introduzir uma equação matemática muito simples:

 estado = leftFold ([… previousEvents]) 

O estado é a dobra esquerda dos eventos anteriores.

Para aqueles de vocês que falam JavaScript:

 const eventsourcing = (eventos, instantâneo = {}) => 
eventos
.reduce ((estado, evento) =>
Object.assign ({}, state, event.payload), instantâneo)

Os eventos são uma fonte normal e imutável de verdade para o seu domínio.

O estado atual, portanto, é derivado aplicando os eventos um sobre o outro sequencialmente.

Se você sabe tudo o que aconteceu em seu subconjunto do mundo – você está limitado contexto – então você pode determinar o estado desse mundo.

Aqui está um exemplo simples e bem planejado – imagine que você está construindo um robô que pega e coloca itens na superfície de uma mesa.

A tabela pode ser seu agregado .

Você está usando uma mesa agora? Nele, é provavelmente um laptop, ou talvez um controle remoto da TV.

O contexto , neste caso, é o problema em questão. Que queremos saber quais objetos estão em uma tabela e quais superfícies estão disponíveis para novos itens. Nosso modelo precisa apenas conter informações relevantes para essa tarefa.

Você pode imaginar que, se estivesse escrevendo um software para um warehouse, sua ideia do que é uma tabela e de quais informações você se importaria poderia ser muito diferente.

O contexto é importante. No DDD, isso é o que Evans se refere como um contexto limitado .

De qualquer forma, com o exemplo …

Vamos comandar o robô para colocar uma bola na mesa.

Para fazer isso, eu uso uma biblioteca chamada " servicebus ". Servicebus é muito legal porque permite que você use middleware para eventos, para que você possa adicionar facilmente coisas como lógica de tentativa ou desduplicação com suporte do Redis ou rastreamento com muito pouco esforço. Ele foi originalmente construído no RabbitMQ, mas também tenho trabalhado em uma versão Kafka que suporta os plugins originais.

 bus.send ('table.item.place', { 
tipo: 'bola',
propriedades: {color: 'red'},
position: {top: 1, left: 1, unit: 'inch'}
}

Quando isso acontece, o robô pode declarar com segurança: “Coloquei a bola na mesa! Está posicionado a 1 polegada da parte superior e a 1 polegada da esquerda! ”

Aconteceu.

Não pode acontecer.

É um fato imutável. A bola foi colocada na mesa. Período.

Vamos deixar o resto do mundo saber, para que eles possam responder ao evento se estiverem inscritos.

 bus.publish ('table.item.placed', {item}) 

Agora, quero enfatizar que é um fato imutável que esse evento ocorreu.

O jornal já foi publicado e enviado pela porta!

Se você quiser desfazê-lo, sua única opção é outro comando – table.item.remove

O que levaria ao evento table.item.removed para ser publicado quando concluído com sucesso.

Se você é um terceiro que não pode ver a tabela, mas você estava inscrito nos eventos que imutavelmente ocorreram sobre a tabela, você poderia determinar o estado atual da tabela.

Uma bola foi colocada na mesa e depois removida. O estado atual é uma tabela vazia.

Esse tipo de arquitetura baseada em eventos é conhecido como um sistema “Eventualmente Consistente”.

O terceiro não sabe instantaneamente assim que a bola é colocada na mesa, no entanto, recebe uma mensagem informando que o evento ocorreu. Depois que a mensagem foi recebida, o receptor pode determinar o novo estado da tabela.

É um padrão muito popular também. Em grande parte por causa do teorema CAP, que significa Consistência, Disponibilidade e Tolerância à Partição. A regra é que você só pode escolher dois. Diferentes partes do sistema podem otimizar para objetivos diferentes, e o sistema em geral geralmente se sacrifica na consistência.

Por exemplo, tudo bem se você não soubesse que Billy postou o novo Instagram até 23 segundos depois. Você finalmente consegue.

Embora eu esteja construindo serviços como este há anos, está recentemente fazendo outra rodada de tendências como “arquiteturas orientadas a eventos”.

Também está a um passo do CQRS. Tudo o que você precisa é inscrever-se em alguns fluxos de eventos e criar uma projeção dos dados adequados para o aplicativo em questão. O processo é chamado desnormalização e, portanto, eu chamo serviços que fazem isso "desnormalizadores".

O que me faz lembrar de uma história engraçada: uma vez alguém na folga onde eu saio, alguém perguntava sobre a CQRS e eu acidentalmente escrevi “desmoralizador”. Ele era como "há uma coisa séria chamada desmoralizador". ?

Faça um favor a si mesmo e leia este artigo ainda relevante de 2012: O Log: O que todo engenheiro de software deve saber sobre a abstração unificadora dos dados em tempo real | Engenharia do LinkedIn por Jay Kreps co-criador do Kafka.

3. Automatize suas operações e infraestrutura

DevOps – o cruzamento de Desenvolvimento e Operações – está em um renascimento.

Como mencionei anteriormente, com a simplicidade dos serviços, alguma complexidade necessariamente se move em suas operações e arquitetura.

Eu sabia que queria construir sistemas tolerantes a falhas altamente escaláveis, feitos de serviços simples que fossem sustentáveis, de longa duração, maleáveis e fáceis para os humanos entenderem.

Eu sabia que os padrões de microsserviços e Design dirigido por domínio me permitiriam cumprir todos esses objetivos, além de permitir que eu e minha equipe entregássemos consistentemente códigos de alta qualidade que resistissem ao teste do tempo.

No entanto, apenas executá-los na produção acabou por ser uma tarefa bastante monumental.

Eu era novo no DevOps e nem sabia por onde começar.

Depois do googling, me deparei com uma tonelada de cursos da AWS, havia cinco níveis diferentes de certificações, e cada um deles levava meses e centenas de dólares em aulas.

Isso não era uma ordem pequena. Eu sabia que o padrão de fato era tornar-se um arquiteto de soluções da AWS… o problema era o 5º nível de certificação da AWS e, até esse momento, basicamente só era implantado em provedores de PaaS como Heroku e Modulus ou alguém DevOps.

Então, finalmente, depois de passar anos descobrindo o suficiente de todo DDD, e CQRS / ES + AR, eu ainda tinha que me tornar um especialista em outra área completamente diferente, apenas para poder fazê-lo efetivamente.

Lembras-te daquelas portas de correr CSS de que falei? Os que tinham cerca de 100 linhas de código para criar uma guia em HTML e CSS com cantos arredondados.

Felizmente, as coisas ficam mais simples com o tempo.

É mais fácil do que nunca se tornar perigoso com o DevOps. Leia sobre a Minha jornada para DevOps Bliss, sem certificações inúteis da AWS e certifique-se de pegar seu curso gratuito de três semanas por e-mail no final!

Conclusão

Isso é tudo por hoje! Obrigado pela leitura. Se você tiver alguma dúvida, ou se você achou isso útil, eu adoraria ouvir suas opiniões nos comentários.

A melhor maneira de me ajudar a alcançar os outros é clicar e segurar o botão de palmas ou compartilhar nas redes sociais!

melhor,
Patrick Lee Scott

PS Jørn André Myrland fez uma ótima pergunta nos comentários – não deixe de conferir minha resposta para uma melhor foto de nível superior.

Texto original em inglês.