Julio Biason
5 years ago
3 changed files with 183 additions and 2 deletions
@ -0,0 +1,89 @@ |
|||||||
|
+++ |
||||||
|
title = "Microservices: Artifact = Input + State" |
||||||
|
date = 2019-12-26 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["microservices", "artifacts", "state"] |
||||||
|
+++ |
||||||
|
|
||||||
|
Designing microservices is a bit complicated because you have to think about |
||||||
|
different things when deciding which "domain" it will occupy. A recent |
||||||
|
discussion with coworkers about our current microservices design led me to |
||||||
|
rethink how to think about microservices. |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
This may sound a bit weird for those already working with microservices -- or |
||||||
|
that managed to build a good view of the building of microservices -- but when |
||||||
|
the word "artifact" popped up in a discussion, it "clicked" with a bunch of |
||||||
|
other stuff I had in mind about the topic. |
||||||
|
|
||||||
|
One fact that kept confusing me was that a lot of literature about |
||||||
|
microservices talk about "domain separation" and how to figure out each |
||||||
|
domain. Now, although there are a few tricks -- like "if it is a noun, it is a |
||||||
|
domain" -- not everything is clear cut. Some domains are actually subdomains |
||||||
|
of a larger domain, so you keep wondering if you should split those or keep |
||||||
|
them into a single microservice, since splitting them would, invariably, |
||||||
|
making the microservices coupled (something you want to avoid when building |
||||||
|
microservices). |
||||||
|
|
||||||
|
And that's where "artifact" felt into place. For a while, I had the impression |
||||||
|
that microservices had to be built "backwards", in the sense that first you |
||||||
|
have to think in what you _need_ and then check what you _have_ -- in other |
||||||
|
words, you have to think on your outputs before checking your inputs. And an |
||||||
|
"artifact" is, in the end, just the output of the microservice. |
||||||
|
|
||||||
|
In our case, we are dealing with games. Each game has a narration, it has an |
||||||
|
score, it has statistics and it has a roster. Even if it falls into the "it's |
||||||
|
a noun!" rule, it actually resembles the required output of our system: we |
||||||
|
have a request that gets the current narration of a game (which can be polled |
||||||
|
from time to time or -- as we are currently working on -- pushed towards |
||||||
|
clients); one request returns the match score (which, again, can be polled or |
||||||
|
pushed); one request retrieves the match statistics, which is not frequently |
||||||
|
updated or displayed, so it doesn't need constant updates; and so on. Each one |
||||||
|
of those is a different microservice, because each one of those is a different |
||||||
|
artifact. |
||||||
|
|
||||||
|
Alright, if those are artifacts, where does "state" gets into this? The state |
||||||
|
is the amount of information a microservice has to keep in order to build the |
||||||
|
artifact. For example, in the narration, each time a new narration comes in, |
||||||
|
it has to be added to a game list of narrations in order to produce the |
||||||
|
narration of the whole match. The state can also help this microservice into |
||||||
|
dropping duplicate narrations. |
||||||
|
|
||||||
|
One "nice" effect of the state is that you can, in theory at least, be able to |
||||||
|
recognize that even with an input, if there was no change in the state, there |
||||||
|
should be no change in the artifact and, thus, no output is necessary. |
||||||
|
|
||||||
|
Another thing to keep in mind about the state is that you don't need to keep |
||||||
|
it in memory; you can use any kind of storage: keep the narrations in a |
||||||
|
database, keep it on a disk, keep in memory as a cache, or all the above. You |
||||||
|
pick whatever it is _easier_ to manipulate said state to produce the artifact. |
||||||
|
The thing to keep in mind is "If this microservice crashes, will it be able to |
||||||
|
rebuild its previous state when it restarts?" |
||||||
|
|
||||||
|
And, finally, the inputs. Those may sound a bit obvious at first (is your |
||||||
|
microservice generating data out of thin air?), but keep in mind is that one |
||||||
|
input can be be the source of more than one microservice. For example, a |
||||||
|
narration may be consumed by the narration microservice to produce the whole |
||||||
|
game narration, but it may also be consumed by the score microservice, |
||||||
|
listening to goal narrations to update its state (if the narration is not a |
||||||
|
goal, there is no change in score, there is no change in the state and there |
||||||
|
is no artifact generation). |
||||||
|
|
||||||
|
Returning to artifacts, do not worry if more than one microservice doing |
||||||
|
almost the same thing, but generating a complete different artifact. As an |
||||||
|
example, imagine that you want to use push notifications to report new goals. |
||||||
|
Although this is very close to the score microservice, it produces a different |
||||||
|
artifact (the push notification vs the update score request) and, by this, |
||||||
|
should be a complete different microservice. It may even sound wasteful (doing |
||||||
|
the same thing twice), but it would decouple things if you need some other |
||||||
|
information in the score (say, adding the name of the players who did the |
||||||
|
goals) or if you change the artifact consumer (say, you change from an in-hour |
||||||
|
implementation of pushing to Apple and Google to using a service for this, |
||||||
|
like Azure). |
||||||
|
|
||||||
|
This change in the my way of thinking about microservices design help me |
||||||
|
rethink the way we are building our microservices at work, and it is also |
||||||
|
helping me rethink some things on a personal project (which I hope to finish |
||||||
|
and show it next year). |
@ -0,0 +1,94 @@ |
|||||||
|
+++ |
||||||
|
title = "Microserviços: Artefato = Entrada + Estado" |
||||||
|
date = 2019-12-26 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["microserviços", "artefatos", "estado"] |
||||||
|
+++ |
||||||
|
|
||||||
|
Projetar microserviços é um pouco complicado porque temos que pensar sobre |
||||||
|
as coisas que cada "domínio" vai ocupar. Uma discussão entre os |
||||||
|
desenvolvedores aqui sobre nossos projetos de microserviços me levou a |
||||||
|
repensar como pensar microserviços. |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
Isso pode soar um pouco estranho para aqueles que já estão trabalhando com |
||||||
|
microserviços -- ou que conseguiram ter uma boa visão da construção de |
||||||
|
microserviços -- mas quando foi citado "artefato" na discussão, "caiu a ficha" |
||||||
|
com outras coisas que eu estava pensando sobre o tópico. |
||||||
|
|
||||||
|
Um fato que continua me confundindo é que a literatura sobre microserviços |
||||||
|
começa a falar sobre "separação de domínios" e como definir cada domínio. |
||||||
|
Embora haja alguns truques -- como "se é um substantivo, é um domínio" -- nada |
||||||
|
é realmente tão óbvio. Alguns domínios são, na verdade, sub domínios de um |
||||||
|
domínio maior, e aí você fica se perguntando se deve separar esses domínios ou |
||||||
|
mantê-los num único microserviço, já que separá-los iria, invariavelmente, |
||||||
|
criar microserviços acoplados (algo que você quer evitar quando está usando |
||||||
|
microserviços). |
||||||
|
|
||||||
|
E é aí que "artefato" encaixou no resto das coisas. Por algum tempo, eu tive a |
||||||
|
impressão que microserviços tem que ser construídos "de trás pra frente", no |
||||||
|
sentido de que primeiro você precisa pensar nas coisas que você _precisa_ e |
||||||
|
depois verificar o que você _tem_ -- em outras palavras, você pensa primeiro |
||||||
|
nas saídas do microserviço e depois olha o que tem de entrada. E um "artefato" |
||||||
|
é, no final, simplesmente a saída do microserviço. |
||||||
|
|
||||||
|
No nosso caso, nós estamos lidado com jogos. Cada jogo tem uma narração, tem |
||||||
|
um placar, tem estatística e tem uma escalação. Mesmo que essa explicação |
||||||
|
caia na regra do "é um substantivo!", na verdade ela reflete a saída do nosso |
||||||
|
sistema: nos temos uma requisição que retorna a narração atual do jogo (que |
||||||
|
pode ser atualizada por polling ou -- como estamos trabalhando agora -- feito |
||||||
|
"push" diretamente para os clientes); uma requisição para retornar o placar |
||||||
|
(que, de novo, pode ser por "polling" ou "push"); uma requisição que retorna |
||||||
|
as estatísticas, que não são atualizadas ou exibidas de forma tão frequente, |
||||||
|
e por isso não precisam de atualizações visuais constantes; e assim por |
||||||
|
diante. Cada um desses é um microserviço diferente, porque cada um desses é um |
||||||
|
artefato diferente. |
||||||
|
|
||||||
|
Bom, se esses são os artefatos, onde é que o "estado" entra nessa história? O |
||||||
|
estado é o conjunto de informações que o microserviço precisa ter para |
||||||
|
produzir o artefato. Por exemplo, na narração, cada vez que uma nova narração |
||||||
|
entra, ela precisa entrar na lista de narrações do jogo para que seja |
||||||
|
produzida a narração da partida inteira. O estado também pode ajudar o |
||||||
|
microserviço a remover narrações duplicadas. |
||||||
|
|
||||||
|
Um efeito "legal" do estado é que você pode, pelo menos na teoria, perceber |
||||||
|
que mesmo com uma nova entrada, se não houve alteração do estado, então não |
||||||
|
vai haver alteração do artefato e não é preciso ter nenhuma saída. |
||||||
|
|
||||||
|
Outra coisa a se ter em mente sobre o estado é que ele não precisa ser mantido |
||||||
|
em memória; você pode usar qualquer tipo de armazenamento: mantenha as |
||||||
|
narrações num banco de dados, no disco, na memória em cache ou todos os |
||||||
|
anteriores. Decida usar o que ficar mais _fácil_ de ser manipulado para |
||||||
|
produzir o artefato. Uma coisa a se manter em mente sobre isso é "Se esse |
||||||
|
microserviço morrer, ele vai conseguir voltar ao mesmo estado quando for |
||||||
|
reiniciado?" |
||||||
|
|
||||||
|
E, finalmente, as entradas. Essas podem parecer meio óbvias a princípio (o seu |
||||||
|
microserviço está gerando dados do nada?), mas mantenha em mente que uma |
||||||
|
entrada pode ser a origem de dados de mais de um microserviço. Por exemplo, |
||||||
|
uma narração pode ser consumida pelo microserviço de narrações para produzir a |
||||||
|
narração inteira da partida, mas também ser consumida pelo microserviço de |
||||||
|
placar, que fica escutando narrações de gols para atualizar seu estado (se a |
||||||
|
narração não for de gol, não há alteração de placar, não há alteração de |
||||||
|
estado e não há geração do artefato). |
||||||
|
|
||||||
|
Voltando aos artefatos, não se preocupe se mais de um microserviço faz |
||||||
|
basicamente a mesma coisa que outra, mas gera um artefato completamente |
||||||
|
diferente. Como exemplo, imagine que você quer que sejam feitas notificações |
||||||
|
por push quando acontece um gol. Embora seja um serviço bem parecido com o |
||||||
|
microserviço de placar, ele produz um artefato diferente (a notificação por |
||||||
|
push vs a requisição de atualização de placar) e, por isso, deveria ser um |
||||||
|
microserviço completamente diferente. Até pode soar meio desnecessário (ter |
||||||
|
serviços fazendo a mesma coisa, duas vezes), mas isso desacopla as coisas se |
||||||
|
você precisar mais informações no placar (por exemplo, adicionando o nome de |
||||||
|
cada jogador que fizeram gols) ou mudar o consumidor do artefato (por exemplo, |
||||||
|
mudando a implementação do push para, ao invés de fazer as chamadas |
||||||
|
diretamente paras a APIs da Apple e Google, fazer chamadas para um serviço que |
||||||
|
já faça tudo isso, como o da Azure). |
||||||
|
|
||||||
|
Essa mudança na minha forma de pensar como construir microserviços me ajudou a |
||||||
|
pensar nos nossos microserviços no trabalho, e também está me ajudando a |
||||||
|
repensar algumas saídas em um projeto pessoal (que eu espero terminar e |
||||||
|
mostrar no ano que vêm). |
Loading…
Reference in new issue