Browse Source

Microservice artifacts

master
Julio Biason 5 years ago
parent
commit
eab6898383
  1. 2
      config.toml
  2. 89
      content/code/microservices-artifact-input-state.md
  3. 94
      content/code/microservices-artifact-input-state.pt.md

2
config.toml

@ -28,8 +28,6 @@ highlight_code = true
default_language = "en" default_language = "en"
languages = [ languages = [
{code = "en", rss = true},
{code = "en", search = false},
{code = "pt", rss = true}, {code = "pt", rss = true},
{code = "pt", search = false}, {code = "pt", search = false},
] ]

89
content/code/microservices-artifact-input-state.md

@ -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).

94
content/code/microservices-artifact-input-state.pt.md

@ -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…
Cancel
Save