đŸ‡§đŸ‡· Modelo de ConcorrĂȘncia Orientado ao NegĂłcio

Criar um design de software multi serviços pode te levar a algumas dores de cabeça quando pensamos em concorrĂȘncia. Nesse post vou descrever os modelos tĂ©cnicos de concorrĂȘncia mais famosos e uma proposta diferente ao vĂȘ-los, para que possamos pensar melhor no design dos nossos sistemas.

Veja abaixo os modelos de concorrĂȘncia, benefĂ­cios e desafios.

Pessimista

Esse modelo de concorrĂȘncia propĂ”e que ninguĂ©m pode alterar o estado de um objeto enquanto ele estĂĄ sendo alterado por outro processo, significando que todas as transaçÔes subsequentes interessadas no objeto, terĂŁo que esperar sua vez na fila para fazer o que precisam.

Essa abordagem em alguns casos Ă© ruim pois vocĂȘ bloqueia o dado, nĂŁo pode escalar e as vezes acontece que um dado processo decide tirar fĂ©rias enquanto segura a fila de processos interessados no mesmo objeto, forçando que alguĂ©m resolva o problema manualmente.

Otimista

Esse modelo propÔe que dada duas ou mais transaçÔes em um mesmo objeto, somente uma transação ganha: ou a primeira, ou a segunda ganha. Existe um lado ruim desse modelo é que in qualquer um dos casos, um dos processos perde dado.

Existem duas estratégias para o modelo otimista:

NegĂłcio

Todos os modelos acima tem seus prĂłprios desafios, mas precisamos de um modelo focado no negĂłcio, que pode lidar com ambos os mundos: otimista e pessimista.

Para entender a ideia proposta, veja primeiro o exemplo de uma transação abaixo:

1: Begin Transaction
2: Read Entity A
3: Read Entity B
4: Update Entity C com dado de A e B
5: Commit Transaction

Olhando para o exemplo vemos que uma vez que o dado é lido, não é possível garantir que o estado de C serå completamente consistente com A e B, pois A e B podem ter seus estados totalmente modificados ao final da transação, não sendo mais consistente com C.

A questĂŁo que fica Ă©: Essa inconsistĂȘncia Ă© importante para o negĂłcio ?

Na maioria das vezes assumimos que se colocarmos transaçÔes em todos os lugares, tudo serĂĄ consistente. Isso se deve ao fato de que como os ORM’s se tornaram largamente utilizados nos nossos sistemas, desenvolvedores começaram a falar:

Ah! NĂŁo tem problema, eu nĂŁo preciso me preocupar com o banco de dados, pois o ORM cuida disso pra mim. Eu vou focar no negĂłcio!

Essa frase nĂŁo Ă© totalmente verdade. De fato, precisamos nos preocupar com o negĂłcio, e se vocĂȘ estĂĄ desenvolvendo um sistema em um domĂ­nio colaborativo, onde outro processo pode mudar o estado da entidade que vocĂȘ estĂĄ para usar, entĂŁo vocĂȘ precisa pensar em concorrĂȘncia, que Ă© parte do negĂłcio e muito relacionado ao funcionamento do banco de dados.

EntĂŁo, para ter um modelo de concorrĂȘncia orientado ao negĂłcio, a primeira regra:

Mas o modelo de concorrĂȘncia tĂ©cnico nĂŁo Ă© o suficiente, vocĂȘ ainda tem que codificar de uma maneira que evite falhas no negĂłcio pela sua escolha tĂ©cnica.

A abordagem proposta para resolver esse problema é dividir a sua transação em pequenas partes, fazendo somente uma coisa por vez com uma porção de dado.

1: Recebe uma mensagem (comando/evento)
1: Obtém o Objeto de Domínio
2: Altera o estado do Objeto de DomĂ­nio
3: Commit (possivelmente publicando Eventos de DomĂ­nio)

É muito importante nĂŁo tocar em vĂĄrios objetos de domĂ­nio, porque toda vez que vocĂȘ acessa outro objeto de domĂ­nio na mesma transação, mais probabilidade de problemas de concorrĂȘncia Ă© adicionada. Se vocĂȘ precisa mudar mais estados em seus objetos de domĂ­nio, vocĂȘ deve olhar para os eventos de domĂ­nio.

Em essĂȘncia: Relacionamento entre seus objeto de domĂ­nio, te darĂĄ problemas de concorrĂȘncia. EntĂŁo, pense com bastante cuidado nos seus bounded contexts, pois eles vĂŁo remover relacionamento de objetos de domĂ­nio desnecessĂĄrios e, por design a maioria dos desafios de concorrĂȘncia serĂŁo extintos.

Essa abordagem nos salva em vårios casos, mas em um nível de abstração mais acima, precisamos de pensar um pouco mais adiante: As vezes o negócio requer que em um dado processo, somente uma transação ganha. Veja um exemplo abaixo:

Em um dado domĂ­nio colaborativo onde um cliente fez um pedido, e o negĂłcio Ă© proativo ao fazer o envio do produto tendo dois fornecedores de entrega diferentes em caso de demora. A seguinte racing condition pode aparecer:

1: User faz um pedido
2: Solicita envio para o fornecedor #1
4: Fornecedor #1 demora muito, solicita envio p/ fornecedor #2
5: Fornecedor #2 responde na hora que foi enviado
6: Solicita o cancelamento para o fornecedor #1
7: Ao mesmo tempo, fornecedor #1 responde que o pedido foi enviado

Nesse cenĂĄrio vocĂȘ tem uma racing condition e ambos fornecedores vĂŁo entregar o produto. NĂŁo existe outra maneira de sair desse problem de concorrĂȘncia, senĂŁo achar um motivo de negĂłcio.

Existe uma série de soluçÔes possíveis:

Considerando a lista acima, vocĂȘ pode notar que estĂĄvamos falando sobre um problema tĂ©cnico de racing condition entre duas solicitaçÔes, e agora tentamos achar um motivo de negĂłcio para o problema: polĂ­tica de estorno. Baseado nisso, o domain expert Ă© capaz de decidir em qual regra seguir nesses casos.

Se eu puder dar uma sugestĂŁo, nem tudo Ă© resolvido por uma decisĂŁo tĂ©cnica. As vezes vocĂȘ precisa achar um motivo de negĂłcio para o problema e consertĂĄ-lo como parte do seu processo de negĂłcio.

Se vocĂȘ estĂĄ desenvolvendo um sistema de um usuĂĄrio Ășnico, vocĂȘ nĂŁo precisa se preocupar com concorrĂȘncia, mas esse nĂŁo Ă© o caso da maioria.

Finalizando: NĂŁo subestime a concorrĂȘncia no seu software, pois existe negĂłcio escondido nela.

Me siga no Twitter @_arleypadua.

Esse artigo tambĂ©m estĂĄ disponĂ­vel em InglĂȘs.

Software Engineer and passionate about distributed systems

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store