Arquitetando com Buzzwords
Fabiano Guizellini Modos
Arquiteto de Software na HBSIS
@fmodos
Por que Arquitetando com Buzzwords?
Contextualização
• Objetivo do sistema
Informatizar mais de 600 planilhas Excel
• Tamanho do sistema atualmente
~200 tipos de entidades (tabela)
~600 relacionamentos entre as tabelas
~3000 colunas (~1500 colunas são fórmulas customizáveis)
~1 tela de cadastro por entidade (~200 telas)
• Usuários podem Adicionar, Editar e Excluir registros
Cache
Qual a vantagem?
Acesso rápido a dados e economia de CPU
Qual a desvantagem?
Risco de acessar dados inconsistentes/desatualizados
Gânglio Basal – cache do cérebro
Local Cache Shared Cache
Como lidar com Cache em serviços
distribuídos?
Menos concorrência
Cache menor
Risco maior de dado desatualizado
Mais fácil para manter consistência
Difícil identificar quem é o DONO
da informação
Onde utilizamos Local Cache?
Fórmula modo edição:
Fórmula traduzida para o usuário:
Como mantemos dados consistentes usando
Local Cache?
Publish Subscribe Message Pattern
Fonte: http://www.enterpriseintegrationpatterns.com/patterns/messaging/PublishSubscribeChannel.html
Como utilizamos PubSub para atualizar
LocalCache?
Publisher
Subscriber
Subscriber
CRUD -> C(reate) R(ead) U(pdate) D(delete)
@Path("/cadeira")
public class CadeiraRest {
@Inject
CadeiraService cadeiraService;
@POST
public Response novaCadeira(CadeiraVO cadeiraVo) {
return Response.status(Status.CREATED).entity(cadeiraService.save(cadeiraVo)).build();
}
@GET
public Response buscarTodasCadeiras() {
return Response.status(Status.OK).entity(cadeiraService.findAll()).build();
}
@PUT
public Response alterarCadeira(CadeiraVO cadeiraVo) {
return Response.status(Status.OK).entity(cadeiraService.alterarCadeira(cadeiraVo)).build();
}
@DELETE
@Path("{id}")
public Response excluirCadeira(@PathParam("id")Integer id) {
cadeiraService.excluirCadeira(id);
return Response.status(204).build();
}
}
@Service
public class CadeiraService {
@Inject
CadeiraRepository cadeiraRepository;
public Cadeira novaCadeira(CadeiraVO cadeiraVo) {
return cadeiraRepository.insert(Cadeira.of(cadeiraVo));
}
public List<Cadeira> findAll() {
return cadeiraRepository.findAll();
}
public Cadeira alterarCadeira(CadeiraVO cadeiraVo) {
return cadeiraRepository.save(Cadeira.of(cadeiraVo));
}
public void excluirCadeira(@PathParam("id")Integer id) {
cadeiraRepository.delete(id);
}
}
CQRS -> Command Query Resource Segregation
A forma que tu grava o dado é diferente da forma que tu lê.
http://www.kennybastani.com/2017/01/building-event-driven-
microservices.html
Pontos Ken Pontos Modos
100 50
Source Target Golpe
Ken Modos Haduken
Source Target Golpe Pontos Data/Hora
Ken Modos Haduken -50 03-05-2017
00:47:00
Command
Event
Snapshot
Command -> uma
intenção
Event -> algo que
ocorreu
Snapshot -> salva o
valor atual do
agregado
CQRS - Exemplos de código
• https://github.com/sdaschner/scalable-coffee-shop
• https://github.com/cer/event-sourcing-examples
• https://github.com/gregoryyoung/m-r
To CRUD or to CQRS?
Como utilizamos CQRS
ChangeRequestCommand:
{
modelId : ‘123’,
table : ‘cadeira’,
field : ‘valor’,
value : ‘50’
}
Command
Event Publica
Calcula Fórmulas
Atualiza Valor
Fórmulas
Event Sourcing
Log de todas operações executadas em um aggregate
public void testEventSourcing(){
long fightID = 123;
Fight fight = fightService.getById(fightID);
Fight tempFight = new Fight():
Assert.assertNotEquals(fight.getPointsPlayer1(), tempFight.getPointsPlayer1());
Assert.assertNotEquals(fight.getPointsPlayer2(), tempFight.getPointsPlayer2());
List<FightEvent> fightEvents = fightEventService.getEventsByFightID(fightID);
for(FightEvent event : fightEvents){
tempFight.apply(FightCommand.of(event));
}
Assert.assertEquals(fight.getPointsPlayer1(), tempFight.getPointsPlayer1());
Assert.assertEquals(fight.getPointsPlayer2(), tempFight.getPointsPlayer2());
}
SQL NOSQL
Diagrama Classe Diagrama Relacional Diagrama NoSQL
-Deve permitir cadastro de Dish informando nome, descrição e lista de
ingredientes.
-Deve permitir que usuários logados através do email e senha insiram
comentários em um Dish.
Estudo de Caso
Consulta de Dados
SQL NoSQL
select d.name, d.description from dish d where id=1
select i.name from ingredient i where i.dish_id=1
select c.text, u.nickname, u.name from comment c, user
u where c.user_id = u.id and c.dish_id = 1
db.getCollection(‘Dish’).find({_id : 1})
Inconsistência de Dados
O que acontece se o usuário “JOSÉ” atualizar o nickname para “JOÃO”?
SQL NoSQL
update user set nickname = ‘JOÃO’ where id=1 db.getCollection(‘User’).update({_id : 1},
{$set : {nickname : ‘JOÃO’}})
{name: “Dish Test”
ingredients : [“arroz”],
comments : Array[
{
text : ‘Comentario do José’
user : {
nickname : ‘JOSÉ’
}
]
Como resolvemos?
-Utilizando o Visitor Design Pattern que
veremos nos próximos capítulos
Concorrência de alteração
SQL NoSQL
public void addComment(Dish dish, User user, String text){
Comment comment = Comment.of(dish, user, text);
commentRepository.insert(dish);
}
public void addComment(Dish dish, User user, String text){
Comment comment = Comment.of(user, text);
dish.addComment(comment);
dishRepository.save(dish);
}
• Syncronized??? Please no
syncronized(dish.getId(){
Comment comment = Comment.of(user, text);
dish.addComment(comment);
dishRepository.save(dish);
}
• Codigo com update do mongodb
mongoTemplate.updateFirst(queryId(dish.getId()), new Update().addToSet(comment), “Dish”)
• Fila de processamento
Como resolvemos?
-Devido uma regra de negócio toda alteração
somente pode ser atualizada na planilha em datas
pré definidas, dessa forma possuímos serviços
agendados que atualizam os Snapshots(Planilha) de
forma síncrona.
Concorrência de alteração
Controle Transação MongoDB???
“Aquilo que você conhece não pode te
machucar” – Livro: A lógica do cisne negro
Como resolvemos?
-Agrupamos todas as informações em um registro
-Processos batch, temos um controle de execução
que gera log de cada step e consegue continuar de
onde parou
Como alterar registros de um agregado não
estruturado?
Visitor Design Pattern
class ApplyChangeVisitor implements Visitor{
ChangeRequestCommand change = ...
public void visit(Entidade e){
if(e.getId().equals(change.getModelId()){
e.setFieldValue(change.getField(), change.getValue());
}
}
}
class abstract Entidade {
public void accept(Visitor visitor){
visitor.visit(this);
//busca associações e invoca accept
refEntidade.accept(visitor);
}
}
Entidade planilha = ....
ChangeRequestCommand change = ....
planilha.accept(new ApplyChangeVisitor(change));
Editing/Publishing Pattern
https://martinfowler.com/articles/two-stack-cms/#edit-publish
Como utilizamos Editing/Publishing
• Criamos um conceito de View por cada usuário
• Comandos de alteração são armazenados no Editing da View do
usuário
• Publishing é a versão aprovada compartilhada por todos usuários
View Usuário
= Comandos Editing
+ Versão Publishing
"My feeling is that when we prepare a program, it can be like
composing poetry or music; as Andrei Ershov has said [9],
programming can give us both intellectual and emotional
satisfaction, because it is a real achievement to master
complexity and to establish a system of consistent rules."
Computer Programming as an Art Donald Knuth, 1974
Obrigado!
@fmodos
Referências
• http://www.kennybastani.com/2017/01/building-event-driven-
microservices.html
• http://cqrs.nu/Faq
• http://www.enterpriseintegrationpatterns.com/ramblings/eip1_examples_
updated.html
• https://martinfowler.com/articles/201701-event-driven.html
• https://pt.wikipedia.org/wiki/Visitor_Pattern
• https://twitter.com/gregyoung
• https://docs.mongodb.com/manual/
• https://martinfowler.com/articles/two-stack-cms/#edit-publish

Arquitetando com buzzwords

  • 1.
    Arquitetando com Buzzwords FabianoGuizellini Modos Arquiteto de Software na HBSIS @fmodos
  • 2.
    Por que Arquitetandocom Buzzwords?
  • 3.
    Contextualização • Objetivo dosistema Informatizar mais de 600 planilhas Excel • Tamanho do sistema atualmente ~200 tipos de entidades (tabela) ~600 relacionamentos entre as tabelas ~3000 colunas (~1500 colunas são fórmulas customizáveis) ~1 tela de cadastro por entidade (~200 telas) • Usuários podem Adicionar, Editar e Excluir registros
  • 4.
    Cache Qual a vantagem? Acessorápido a dados e economia de CPU Qual a desvantagem? Risco de acessar dados inconsistentes/desatualizados
  • 5.
    Gânglio Basal –cache do cérebro
  • 6.
    Local Cache SharedCache Como lidar com Cache em serviços distribuídos? Menos concorrência Cache menor Risco maior de dado desatualizado Mais fácil para manter consistência Difícil identificar quem é o DONO da informação
  • 7.
    Onde utilizamos LocalCache? Fórmula modo edição: Fórmula traduzida para o usuário:
  • 8.
    Como mantemos dadosconsistentes usando Local Cache? Publish Subscribe Message Pattern Fonte: http://www.enterpriseintegrationpatterns.com/patterns/messaging/PublishSubscribeChannel.html
  • 9.
    Como utilizamos PubSubpara atualizar LocalCache? Publisher Subscriber Subscriber
  • 10.
    CRUD -> C(reate)R(ead) U(pdate) D(delete) @Path("/cadeira") public class CadeiraRest { @Inject CadeiraService cadeiraService; @POST public Response novaCadeira(CadeiraVO cadeiraVo) { return Response.status(Status.CREATED).entity(cadeiraService.save(cadeiraVo)).build(); } @GET public Response buscarTodasCadeiras() { return Response.status(Status.OK).entity(cadeiraService.findAll()).build(); } @PUT public Response alterarCadeira(CadeiraVO cadeiraVo) { return Response.status(Status.OK).entity(cadeiraService.alterarCadeira(cadeiraVo)).build(); } @DELETE @Path("{id}") public Response excluirCadeira(@PathParam("id")Integer id) { cadeiraService.excluirCadeira(id); return Response.status(204).build(); } } @Service public class CadeiraService { @Inject CadeiraRepository cadeiraRepository; public Cadeira novaCadeira(CadeiraVO cadeiraVo) { return cadeiraRepository.insert(Cadeira.of(cadeiraVo)); } public List<Cadeira> findAll() { return cadeiraRepository.findAll(); } public Cadeira alterarCadeira(CadeiraVO cadeiraVo) { return cadeiraRepository.save(Cadeira.of(cadeiraVo)); } public void excluirCadeira(@PathParam("id")Integer id) { cadeiraRepository.delete(id); } }
  • 11.
    CQRS -> CommandQuery Resource Segregation A forma que tu grava o dado é diferente da forma que tu lê. http://www.kennybastani.com/2017/01/building-event-driven- microservices.html
  • 12.
    Pontos Ken PontosModos 100 50 Source Target Golpe Ken Modos Haduken Source Target Golpe Pontos Data/Hora Ken Modos Haduken -50 03-05-2017 00:47:00 Command Event Snapshot Command -> uma intenção Event -> algo que ocorreu Snapshot -> salva o valor atual do agregado
  • 13.
    CQRS - Exemplosde código • https://github.com/sdaschner/scalable-coffee-shop • https://github.com/cer/event-sourcing-examples • https://github.com/gregoryyoung/m-r
  • 14.
    To CRUD orto CQRS?
  • 15.
    Como utilizamos CQRS ChangeRequestCommand: { modelId: ‘123’, table : ‘cadeira’, field : ‘valor’, value : ‘50’ } Command Event Publica Calcula Fórmulas Atualiza Valor Fórmulas
  • 16.
    Event Sourcing Log detodas operações executadas em um aggregate public void testEventSourcing(){ long fightID = 123; Fight fight = fightService.getById(fightID); Fight tempFight = new Fight(): Assert.assertNotEquals(fight.getPointsPlayer1(), tempFight.getPointsPlayer1()); Assert.assertNotEquals(fight.getPointsPlayer2(), tempFight.getPointsPlayer2()); List<FightEvent> fightEvents = fightEventService.getEventsByFightID(fightID); for(FightEvent event : fightEvents){ tempFight.apply(FightCommand.of(event)); } Assert.assertEquals(fight.getPointsPlayer1(), tempFight.getPointsPlayer1()); Assert.assertEquals(fight.getPointsPlayer2(), tempFight.getPointsPlayer2()); }
  • 17.
  • 18.
    Diagrama Classe DiagramaRelacional Diagrama NoSQL -Deve permitir cadastro de Dish informando nome, descrição e lista de ingredientes. -Deve permitir que usuários logados através do email e senha insiram comentários em um Dish. Estudo de Caso
  • 19.
    Consulta de Dados SQLNoSQL select d.name, d.description from dish d where id=1 select i.name from ingredient i where i.dish_id=1 select c.text, u.nickname, u.name from comment c, user u where c.user_id = u.id and c.dish_id = 1 db.getCollection(‘Dish’).find({_id : 1})
  • 20.
    Inconsistência de Dados Oque acontece se o usuário “JOSÉ” atualizar o nickname para “JOÃO”? SQL NoSQL update user set nickname = ‘JOÃO’ where id=1 db.getCollection(‘User’).update({_id : 1}, {$set : {nickname : ‘JOÃO’}}) {name: “Dish Test” ingredients : [“arroz”], comments : Array[ { text : ‘Comentario do José’ user : { nickname : ‘JOSÉ’ } ] Como resolvemos? -Utilizando o Visitor Design Pattern que veremos nos próximos capítulos
  • 21.
    Concorrência de alteração SQLNoSQL public void addComment(Dish dish, User user, String text){ Comment comment = Comment.of(dish, user, text); commentRepository.insert(dish); } public void addComment(Dish dish, User user, String text){ Comment comment = Comment.of(user, text); dish.addComment(comment); dishRepository.save(dish); } • Syncronized??? Please no syncronized(dish.getId(){ Comment comment = Comment.of(user, text); dish.addComment(comment); dishRepository.save(dish); }
  • 22.
    • Codigo comupdate do mongodb mongoTemplate.updateFirst(queryId(dish.getId()), new Update().addToSet(comment), “Dish”) • Fila de processamento Como resolvemos? -Devido uma regra de negócio toda alteração somente pode ser atualizada na planilha em datas pré definidas, dessa forma possuímos serviços agendados que atualizam os Snapshots(Planilha) de forma síncrona. Concorrência de alteração
  • 23.
    Controle Transação MongoDB??? “Aquiloque você conhece não pode te machucar” – Livro: A lógica do cisne negro Como resolvemos? -Agrupamos todas as informações em um registro -Processos batch, temos um controle de execução que gera log de cada step e consegue continuar de onde parou
  • 24.
    Como alterar registrosde um agregado não estruturado? Visitor Design Pattern class ApplyChangeVisitor implements Visitor{ ChangeRequestCommand change = ... public void visit(Entidade e){ if(e.getId().equals(change.getModelId()){ e.setFieldValue(change.getField(), change.getValue()); } } } class abstract Entidade { public void accept(Visitor visitor){ visitor.visit(this); //busca associações e invoca accept refEntidade.accept(visitor); } } Entidade planilha = .... ChangeRequestCommand change = .... planilha.accept(new ApplyChangeVisitor(change));
  • 25.
  • 26.
    Como utilizamos Editing/Publishing •Criamos um conceito de View por cada usuário • Comandos de alteração são armazenados no Editing da View do usuário • Publishing é a versão aprovada compartilhada por todos usuários View Usuário = Comandos Editing + Versão Publishing
  • 27.
    "My feeling isthat when we prepare a program, it can be like composing poetry or music; as Andrei Ershov has said [9], programming can give us both intellectual and emotional satisfaction, because it is a real achievement to master complexity and to establish a system of consistent rules." Computer Programming as an Art Donald Knuth, 1974
  • 28.
  • 29.
    Referências • http://www.kennybastani.com/2017/01/building-event-driven- microservices.html • http://cqrs.nu/Faq •http://www.enterpriseintegrationpatterns.com/ramblings/eip1_examples_ updated.html • https://martinfowler.com/articles/201701-event-driven.html • https://pt.wikipedia.org/wiki/Visitor_Pattern • https://twitter.com/gregyoung • https://docs.mongodb.com/manual/ • https://martinfowler.com/articles/two-stack-cms/#edit-publish