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