SlideShare uma empresa Scribd logo
1 de 82
CQRS e Event Sourcing na
prática com RavenDB
Elemar Júnior
@elemarjr
elemarjr@ravendb.net
elemarjr@gmail.com
elemarjr.com
Olá, eu sou Elemar Jr
Eu gosto de
RavenDB
CQRS e Event Sourcing na prática
com RavenDB
Mas, vamos falar de
Vamos pensar em um cenário...
Precisamos criar um um cadastro
de funcionários...
Coisa simples...
Nome, Endereço Residencial e Salário
Começamos com um protótipo
[Route("api/[controller]")]
public class EmployeesController : Controller
{
[HttpGet]
public IEnumerable<Employee> Get()
{ /* .. */ }
[HttpGet("{id}")]
public Employee Get(string id)
{ /* .. */ }
[HttpPost]
public void Post([FromBody]Employee value)
{ /* .. */ }
[HttpPut("{id}")]
public void Put(string id, [FromBody]Employee value)
{ /* .. */ }
[HttpDelete("{id}")]
public void Delete(string id)
{ /* .. */}
}
Podemos modelar
uma API...
public class Employee
{
public string Id { get; set; }
public string Name { get; set; }
public Address HomeAddress { get; set; }
public decimal Salary { get; set; }
}
Definir o Modelo
[Route("api/[controller]")]
public class EmployeesController : Controller
{
[HttpGet]
public IEnumerable<Employee> Get()
{ /* .. */ }
[HttpGet("{id}")]
public Employee Get(string id)
{ /* .. */ }
[HttpPost]
public void Post([FromBody]Employee value)
{ /* .. */ }
[HttpPut("{id}")]
public void Put(string id, [FromBody]Employee value)
{ /* .. */ }
[HttpDelete("{id}")]
public void Delete(string id)
{ /* .. */}
}
public class EmployeesRepository
{
public Employee Load(string id)
{
using (var session = DocumentStoreHolder.Instance.OpenSession())
{
return session.Load<Employee>(id);
}
}
public void Save(Employee newEmployee)
{
using (var session = DocumentStoreHolder.Instance.OpenSession())
{
session.Store(newEmployee);
session.SaveChanges();
}
}
}
Implementar persistência....
Pronto!
Será que ficou bom?
Vejamos...
UI (HTML + Angular)
WebAPI
RavenDB
Presentation
Business
Persistence
Esse modelo não está anêmico?
public class Employee
{
public string Id { get; set; }
public string Name { get; set; }
public Address HomeAddress { get; set; }
public decimal Salary { get; set; }
}
Cadê a linguagem ubíqua?
[Route("api/[controller]")]
public class EmployeesController : Controller
{
[HttpGet]
public IEnumerable<Employee> Get()
{ /* .. */ }
[HttpGet("{id}")]
public Employee Get(string id)
{ /* .. */ }
[HttpPost]
public void Post([FromBody]Employee value)
{ /* .. */ }
[HttpPut("{id}")]
public void Put(string id, [FromBody]Employee value)
{ /* .. */ }
[HttpDelete("{id}")]
public void Delete(string id)
{ /* .. */}
}
Será que escala?
Será que é fácil de alterar?
Vamos tentar resgatar conceitos...
ViewModel
InputModel
Modelo expressa o domínio
public sealed class Employee
{
public Guid Id { get; private set; }
public FullName Name { get; private set; }
public decimal Salary { get; private set; }
public Address HomeAddress { get; private set; }
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public void RaiseSalary(decimal amount)
{ /* .. */ }
public void ChangeHomeAddress(Address address)
{ /* .. */ }
}
Modelo expressa o domínio
public sealed class Employee
{
public Guid Id { get; private set; }
public FullName Name { get; private set; }
public decimal Salary { get; private set; }
public Address HomeAddress { get; private set; }
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public void RaiseSalary(decimal amount)
{ /* .. */ }
public void ChangeHomeAddress(Address address)
{ /* .. */ }
}
Modelo expressa o domínio
public sealed class Employee
{
public Guid Id { get; private set; }
public FullName Name { get; private set; }
public decimal Salary { get; private set; }
public Address HomeAddress { get; private set; }
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public void RaiseSalary(decimal amount)
{ /* .. */ }
public void ChangeHomeAddress(Address address)
{ /* .. */ }
}
Consolidação da Linguagem
Ubíqua
public sealed class Employee
{
public Guid Id { get; private set; }
public FullName Name { get; private set; }
public decimal Salary { get; private set; }
public Address HomeAddress { get; private set; }
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public void RaiseSalary(decimal amount)
{ /* .. */ }
public void ChangeHomeAddress(Address address)
{ /* .. */ }
}
Voltando ao protótipo...
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public sealed class Employee
{
public Guid Id { get; private set; }
public FullName Name { get; private set; }
public decimal Salary { get; private set; }
public Address HomeAddress { get; private set; }
public Employee(Guid id, FullName name, decimal initialSalary)
{ /* .. */ }
public void RaiseSalary(decimal amount)
{ /* .. */ }
public void ChangeHomeAddress(Address address)
{ /* .. */ }
}
Consolidação da Linguagem
Ubíqua
Cadê o protótipo?
public void RaiseSalary(decimal amount)
{ /* .. */ }
Command
InputModel
Anatomia de um Comando
public sealed class UpdateEmployeeHomeAddressCommand :
EmployeeCommand
{
public Address HomeAddress { get; }
public UpdateEmployeeHomeAddressCommand(
EmployeeId id,
Address address) : base(id)
{
HomeAddress = address;
}
}
Command
InputModel
public class EmployeeCommandsHandler : IMessageHandler<RegisterEmployeeCommand>,
IMessageHandler<RaiseSalaryCommand>, IMessageHandler<ChangeHomeAddressCommand>
{
private readonly IEmployeeRepository _repository;
public EmployeeCommandsHandler(IEmployeeRepository repository)
{ _repository = repository; }
public void Handle(RegisterEmployeeCommand command)
{
var newEmployee = new Employee(command.Id, command.Name, command.InitialSalary);
_repository.Save(newEmployee);
}
public void Handle(RaiseSalaryCommand command)
{
var employee = _repository.Load(command.EmployeeId);
employee.RaiseSalary(command.Amount);
_repository.Save(employee);
}
public void Handle(ChangeHomeAddressCommand command)
{
var employee = _repository.Load(command.EmployeeId);
employee.ChangeHomeAddress(command.NewAddress);
_repository.Save(employee);
}
}
InputModel
Command
Chegamos ao Manifesto Reativo
Resolvemos comandos! O que
fazemos com consultas
Vamos lembrar...
ViewModel
Logo, seria natural...
E isso é CQRS
... mas e Event Sourcing?
Employee
RaiseSalaryCommand
SalaryRaisedEvent
Command
InputModel
Anatomia de um Evento
public class EmployeeHomeAddressChangedEvent
: VersionedEvent<Guid>
{
public Address NewAddress { get; }
public EmployeeHomeAddressChangedEvent(Address newAddress)
{
NewAddress = newAddress;
}
}
public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId>
{
public TSourceId SourceId { get; internal set; }
public DateTime When { get; private set; }
public int Version { get; internal set; }
public VersionedEvent()
{
When = DateTime.Now;
}
}
Anatomia de um Evento
public class EmployeeHomeAddressChangedEvent
: VersionedEvent<Guid>
{
public Address NewAddress { get; }
public EmployeeHomeAddressChangedEvent(Address newAddress)
{
NewAddress = newAddress;
}
}
public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId>
{
public TSourceId SourceId { get; internal set; }
public DateTime When { get; private set; }
public int Version { get; internal set; }
public VersionedEvent()
{
When = DateTime.Now;
}
}
Anatomia de um Evento
public class EmployeeHomeAddressChangedEvent
: VersionedEvent<Guid>
{
public Address NewAddress { get; }
public EmployeeHomeAddressChangedEvent(Address newAddress)
{
NewAddress = newAddress;
}
}
public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId>
{
public TSourceId SourceId { get; internal set; }
public DateTime When { get; private set; }
public int Version { get; internal set; }
public VersionedEvent()
{
When = DateTime.Now;
}
}
Stream de Eventos
EmployeeRegistered
HomeAddressUpdated
SalaryRaised
SalaryRaised
HomeAddressUpdated
SalaryRaised
Stream de Eventos
EmployeeRegistered
HomeAddressUpdated
SalaryRaised
SalaryRaised
HomeAddressUpdated
SalaryRaised
Por que não salvar?
Stream de Eventos
No RavenDB é fácil!
Stream de Eventos
No RavenDB é fácil!
... mas antes é preciso
Gerar os Eventos
Entidade/Agregado gera Eventos
public Employee(Guid id, FullName name, decimal initialSalary)
: this(id)
{
Throw.IfArgumentIsNull(name, nameof(name));
Throw.IfArgumentIsNegative(initialSalary, nameof(initialSalary));
Update(new EmployeeRegisteredEvent(name, initialSalary));
}
Entidade/Agregado gera Eventos
public void RaiseSalary(decimal amount)
{
Throw.IfArgumentIsNegative(amount, nameof(amount));
Update(new EmployeeSalaryRaisedEvent(amount));
}
Entidade/Agregado gera Eventos
public void ChangeHomeAddress(Address address)
{
Throw.IfArgumentIsNull(address, nameof(address));
Update(new EmployeeHomeAddressChangedEvent(address));
}
Atualiza estado a partir dos
Eventos
protected void Update(VersionedEvent<TId> e)
{
e.SourceId = Id;
e.Version = Version + 1;
_handlers[e.GetType()].Invoke(e);
Version = e.Version;
_pendingEvents.Add(e);
}
Atualiza estado a partir dos
Eventos
protected void Update(VersionedEvent<TId> e)
{
e.SourceId = Id;
e.Version = Version + 1;
_handlers[e.GetType()].Invoke(e);
Version = e.Version;
_pendingEvents.Add(e);
}
private Employee(Guid id) : base(id)
{
Handles<EmployeeRegisteredEvent>(OnEmployeeRegistered);
Handles<EmployeeSalaryRaisedEvent>(OnEmployeeSalaryRaised);
Handles<EmployeeHomeAddressChangedEvent>(OnEmployeeHomeAddressChanged);
}
Atualiza estado a partir dos
Eventos
protected void Update(VersionedEvent<TId> e)
{
e.SourceId = Id;
e.Version = Version + 1;
_handlers[e.GetType()].Invoke(e);
Version = e.Version;
_pendingEvents.Add(e);
}
private void OnEmployeeRegistered(EmployeeRegisteredEvent @event)
{
Name = @event.Name;
Salary = @event.InitialSalary;
}
private void OnEmployeeSalaryRaised(EmployeeSalaryRaisedEvent @event)
{
Salary += @event.Amount;
}
Atualiza estado a partir dos
Eventos
protected void Update(VersionedEvent<TId> e)
{
e.SourceId = Id;
e.Version = Version + 1;
_handlers[e.GetType()].Invoke(e);
Version = e.Version;
_pendingEvents.Add(e);
}
Stream de Eventos
EmployeeRegistered
HomeAddressUpdated
SalaryRaised
SalaryRaised
HomeAddressUpdated
SalaryRaised
Por que não salvar?
Application
(InputModel)
CommandHandler
(Command)
Entidade
(Evento)
Application
(InputModel)
CommandHandler
(Command)
Entidade
(Evento)
Application
(InputModel)
CommandHandler
(Command)
Entidade
(Evento)
Salvar um documento com
eventospublic void Save(Employee employee)
{
var head = GetHead(employee.Id);
var storedVersion = GetStoredVersionOf(head);
if (storedVersion != (employee.Version - employee.PendingEvents.Count()))
throw new InvalidOperationException("Invalid object state.");
if (head == null)
{
SaveNewEmployee(employee);
}
else
{
SaveEmployeeEvents(employee);
}
foreach (var evt in employee.PendingEvents)
Bus.RaiseEvent(evt);
}
Salvar um documento com
eventos
public JsonDocumentMetadata GetHead(Guid id)
{
string localId = $"employees/{id}";
return _store.DatabaseCommands.Head(localId);
}
public int GetStoredVersionOf(JsonDocumentMetadata
head)
{
return head
?.Metadata[EmployeeEntityVersion]
.Value<int>() ?? 0;
}
Salvar um documento com
eventospublic void Save(Employee employee)
{
var head = GetHead(employee.Id);
var storedVersion = GetStoredVersionOf(head);
if (storedVersion != (employee.Version - employee.PendingEvents.Count()))
throw new InvalidOperationException("Invalid object state.");
if (head == null)
{
SaveNewEmployee(employee);
}
else
{
SaveEmployeeEvents(employee);
}
foreach (var evt in employee.PendingEvents)
Bus.RaiseEvent(evt);
}
Salvar um documento com
eventos
private void SaveNewEmployee(Employee employee)
{
using (var session = _store.OpenSession())
{
var document = new EmployeeEvents(
employee.Id,
employee.PendingEvents
);
session.Store(document);
session.Advanced.GetMetadataFor(document)
.Add(EmployeeEntityVersion, employee.Version);
session.SaveChanges();
}
}
private void SaveEmployeeEvents(
Employee employee )
{
var patches = new List<PatchRequest>();
foreach (var evt in employee.PendingEvents)
{
patches.Add(new PatchRequest
{
Type = PatchCommandType.Add,
Name = "Events",
Value = RavenJObject.FromObject(evt, _serializer)
});
}
var localId = $"employees/{employee.Id}";
var addEmployeeEvents = new PatchCommandData()
{
Key = localId,
Patches = patches.ToArray()
};
var updateMetadata = new ScriptedPatchCommandData()
{
Key = localId,
Patch = new ScriptedPatchRequest
{
Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; "
}
};
_store.DatabaseCommands.Batch(new ICommandData[]
{
addEmployeeEvents,
updateMetadata
});
}
private void SaveEmployeeEvents(
Employee employee )
{
var patches = new List<PatchRequest>();
foreach (var evt in employee.PendingEvents)
{
patches.Add(new PatchRequest
{
Type = PatchCommandType.Add,
Name = "Events",
Value = RavenJObject.FromObject(evt, _serializer)
});
}
var localId = $"employees/{employee.Id}";
var addEmployeeEvents = new PatchCommandData()
{
Key = localId,
Patches = patches.ToArray()
};
var updateMetadata = new ScriptedPatchCommandData()
{
Key = localId,
Patch = new ScriptedPatchRequest
{
Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; "
}
};
_store.DatabaseCommands.Batch(new ICommandData[]
{
addEmployeeEvents,
updateMetadata
});
}
private void SaveEmployeeEvents(
Employee employee )
{
var patches = new List<PatchRequest>();
foreach (var evt in employee.PendingEvents)
{
patches.Add(new PatchRequest
{
Type = PatchCommandType.Add,
Name = "Events",
Value = RavenJObject.FromObject(evt, _serializer)
});
}
var localId = $"employees/{employee.Id}";
var addEmployeeEvents = new PatchCommandData()
{
Key = localId,
Patches = patches.ToArray()
};
var updateMetadata = new ScriptedPatchCommandData()
{
Key = localId,
Patch = new ScriptedPatchRequest
{
Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; "
}
};
_store.DatabaseCommands.Batch(new ICommandData[]
{
addEmployeeEvents,
updateMetadata
});
}
Salvar um documento com
eventospublic void Save(Employee employee)
{
var head = GetHead(employee.Id);
var storedVersion = GetStoredVersionOf(head);
if (storedVersion != (employee.Version - employee.PendingEvents.Count()))
throw new InvalidOperationException("Invalid object state.");
if (head == null)
{
SaveNewEmployee(employee);
}
else
{
SaveEmployeeEvents(employee);
}
foreach (var evt in employee.PendingEvents)
Bus.RaiseEvent(evt);
}
Carregar um documento com
eventos
public Employee Load(Guid id)
{
EmployeeEvents data;
using (var session = _store.OpenSession())
{
data = session.Load<EmployeeEvents>(id);
}
return new Employee(id, data.Events);
}
public Employee(Guid id,
IEnumerable<IVersionedEvent<Guid>> history)
: this(id)
{
LoadFrom(history);
}
Carregar um documento com
eventos
protected void LoadFrom(IEnumerable<IVersionedEvent<TId>> pastEvents)
{
foreach (var e in pastEvents)
{
_handlers[e.GetType()].Invoke(e);
Version = e.Version;
}
}
elemarjr.com
@elemarjr
linkedin.com/in/elemarjr
elemarjr@ravendb.net
elemarjr@gmail.com
Mantenha contato!
CQRS e Event Sourcing na
prática com RavenDB
Elemar Júnior
@elemarjr
elemarjr@ravendb.net
elemarjr@gmail.com
elemarjr.com

Mais conteúdo relacionado

Mais procurados

Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7Paulo Morgado
 
Tuga it 2016 - What's New In C# 6
Tuga it 2016 - What's New In C# 6Tuga it 2016 - What's New In C# 6
Tuga it 2016 - What's New In C# 6Paulo Morgado
 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and InferenceRichard Fox
 
Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2Technopark
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFabio Collini
 
FP 201 - Unit4 Part 2
FP 201 - Unit4 Part 2FP 201 - Unit4 Part 2
FP 201 - Unit4 Part 2rohassanie
 
C# 6.0 - April 2014 preview
C# 6.0 - April 2014 previewC# 6.0 - April 2014 preview
C# 6.0 - April 2014 previewPaulo Morgado
 
Category theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) DataCategory theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) Datagreenwop
 
OOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerOOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerMario Fusco
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo....NET Conf UY
 
Coding Guidelines - Crafting Clean Code
Coding Guidelines - Crafting Clean CodeCoding Guidelines - Crafting Clean Code
Coding Guidelines - Crafting Clean CodeGanesh Samarthyam
 
Developer Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoDeveloper Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoThe Software House
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftGiordano Scalzo
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondMario Fusco
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meetMario Fusco
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingMario Fusco
 

Mais procurados (20)

Oop objects_classes
Oop objects_classesOop objects_classes
Oop objects_classes
 
Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7
 
Tuga it 2016 - What's New In C# 6
Tuga it 2016 - What's New In C# 6Tuga it 2016 - What's New In C# 6
Tuga it 2016 - What's New In C# 6
 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and Inference
 
Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2
 
Java VS Python
Java VS PythonJava VS Python
Java VS Python
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
 
Why Learn Python?
Why Learn Python?Why Learn Python?
Why Learn Python?
 
FP 201 - Unit4 Part 2
FP 201 - Unit4 Part 2FP 201 - Unit4 Part 2
FP 201 - Unit4 Part 2
 
C# 6.0 - April 2014 preview
C# 6.0 - April 2014 previewC# 6.0 - April 2014 preview
C# 6.0 - April 2014 preview
 
Category theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) DataCategory theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) Data
 
OOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerOOP and FP - Become a Better Programmer
OOP and FP - Become a Better Programmer
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
 
Coding Guidelines - Crafting Clean Code
Coding Guidelines - Crafting Clean CodeCoding Guidelines - Crafting Clean Code
Coding Guidelines - Crafting Clean Code
 
Developer Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoDeveloper Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duo
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in Swift
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyond
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
Awt
AwtAwt
Awt
 

Destaque

DDD na prática :: Implementação tática – Entidades vs Objeto de Valor
DDD na prática :: Implementação tática – Entidades vs Objeto de ValorDDD na prática :: Implementação tática – Entidades vs Objeto de Valor
DDD na prática :: Implementação tática – Entidades vs Objeto de ValorJosé Roberto Araújo
 
TDC2016POA | Trilha .NET - O que esperar do C# 7
TDC2016POA | Trilha .NET - O que esperar do C# 7TDC2016POA | Trilha .NET - O que esperar do C# 7
TDC2016POA | Trilha .NET - O que esperar do C# 7tdc-globalcode
 
TDC2016POA \ Trilha Analise Negocios - Agregando valor sem trauma: como trans...
TDC2016POA \ Trilha Analise Negocios - Agregando valor sem trauma: como trans...TDC2016POA \ Trilha Analise Negocios - Agregando valor sem trauma: como trans...
TDC2016POA \ Trilha Analise Negocios - Agregando valor sem trauma: como trans...tdc-globalcode
 
TDC2016POA | Trilha .NET - .NET Entity Core 1.0
TDC2016POA | Trilha .NET - .NET Entity Core 1.0TDC2016POA | Trilha .NET - .NET Entity Core 1.0
TDC2016POA | Trilha .NET - .NET Entity Core 1.0tdc-globalcode
 
Inspeção e Adaptação no Scrum com Indicadores de Resultado e Direção | TDC PO...
Inspeção e Adaptação no Scrum com Indicadores de Resultado e Direção | TDC PO...Inspeção e Adaptação no Scrum com Indicadores de Resultado e Direção | TDC PO...
Inspeção e Adaptação no Scrum com Indicadores de Resultado e Direção | TDC PO...André Bueno
 
TDC 2016 |Trilha DevOps - Dissecando e entendendo pipelines de entrega de sof...
TDC 2016 |Trilha DevOps - Dissecando e entendendo pipelines de entrega de sof...TDC 2016 |Trilha DevOps - Dissecando e entendendo pipelines de entrega de sof...
TDC 2016 |Trilha DevOps - Dissecando e entendendo pipelines de entrega de sof...tdc-globalcode
 
Palestra: Big Data Open Source com Hadoop - FLISOL 2014 - Curitiba
Palestra: Big Data Open Source com Hadoop - FLISOL 2014 - CuritibaPalestra: Big Data Open Source com Hadoop - FLISOL 2014 - Curitiba
Palestra: Big Data Open Source com Hadoop - FLISOL 2014 - CuritibaMarcio Junior Vieira
 
TDC2016POA | Trilha Analise de Negocios - Como fatiar seu produto em estórias...
TDC2016POA | Trilha Analise de Negocios - Como fatiar seu produto em estórias...TDC2016POA | Trilha Analise de Negocios - Como fatiar seu produto em estórias...
TDC2016POA | Trilha Analise de Negocios - Como fatiar seu produto em estórias...tdc-globalcode
 
TDC2016POA | Trilha Agile - Agilidade além da TI: Um Relato de Experiencia
TDC2016POA | Trilha Agile - Agilidade além da TI: Um Relato de ExperienciaTDC2016POA | Trilha Agile - Agilidade além da TI: Um Relato de Experiencia
TDC2016POA | Trilha Agile - Agilidade além da TI: Um Relato de Experienciatdc-globalcode
 
TDC2016POA | Trilha Agile - Beyond borders: aplicando ágil em times distribuídos
TDC2016POA | Trilha Agile - Beyond borders: aplicando ágil em times distribuídosTDC2016POA | Trilha Agile - Beyond borders: aplicando ágil em times distribuídos
TDC2016POA | Trilha Agile - Beyond borders: aplicando ágil em times distribuídostdc-globalcode
 
TDC2016POA | Trilha Agile - Dual-Track Agile: incluindo o PO e o UX no seu pi...
TDC2016POA | Trilha Agile - Dual-Track Agile: incluindo o PO e o UX no seu pi...TDC2016POA | Trilha Agile - Dual-Track Agile: incluindo o PO e o UX no seu pi...
TDC2016POA | Trilha Agile - Dual-Track Agile: incluindo o PO e o UX no seu pi...tdc-globalcode
 
TDC2016POA | Trilha Analise de Negocios - Business Coach, o Analista de Negó...
TDC2016POA | Trilha Analise de Negocios -  Business Coach, o Analista de Negó...TDC2016POA | Trilha Analise de Negocios -  Business Coach, o Analista de Negó...
TDC2016POA | Trilha Analise de Negocios - Business Coach, o Analista de Negó...tdc-globalcode
 
TDC2016POA | Trilha Analise de Negocios - Inovando em negócios com foco na eX...
TDC2016POA | Trilha Analise de Negocios - Inovando em negócios com foco na eX...TDC2016POA | Trilha Analise de Negocios - Inovando em negócios com foco na eX...
TDC2016POA | Trilha Analise de Negocios - Inovando em negócios com foco na eX...tdc-globalcode
 
TDC2016POA | Trilha Agile - CHA com Scrum Master - Conhecimentos, Habilidades...
TDC2016POA | Trilha Agile - CHA com Scrum Master - Conhecimentos, Habilidades...TDC2016POA | Trilha Agile - CHA com Scrum Master - Conhecimentos, Habilidades...
TDC2016POA | Trilha Agile - CHA com Scrum Master - Conhecimentos, Habilidades...tdc-globalcode
 
TDC2016POA | Trilha Analise de Negocios - Estranho no ninho: Um brasileiro li...
TDC2016POA | Trilha Analise de Negocios - Estranho no ninho: Um brasileiro li...TDC2016POA | Trilha Analise de Negocios - Estranho no ninho: Um brasileiro li...
TDC2016POA | Trilha Analise de Negocios - Estranho no ninho: Um brasileiro li...tdc-globalcode
 
TDC2016POA | Trilha Agile - Agile Marketing: os resultados alcançados com pri...
TDC2016POA | Trilha Agile - Agile Marketing: os resultados alcançados com pri...TDC2016POA | Trilha Agile - Agile Marketing: os resultados alcançados com pri...
TDC2016POA | Trilha Agile - Agile Marketing: os resultados alcançados com pri...tdc-globalcode
 
TDC2016POA | Trilha .NET - Trazendo o poder dos containers ao mundo .NET
TDC2016POA | Trilha .NET -  Trazendo o poder dos containers ao mundo .NETTDC2016POA | Trilha .NET -  Trazendo o poder dos containers ao mundo .NET
TDC2016POA | Trilha .NET - Trazendo o poder dos containers ao mundo .NETtdc-globalcode
 
TDC2016POA | Trilha Agile - Ágil fora da TI: como expandir o Agil para as are...
TDC2016POA | Trilha Agile - Ágil fora da TI: como expandir o Agil para as are...TDC2016POA | Trilha Agile - Ágil fora da TI: como expandir o Agil para as are...
TDC2016POA | Trilha Agile - Ágil fora da TI: como expandir o Agil para as are...tdc-globalcode
 
TDC2016 POA | Trilha DevOps - Blue-Green Deployment com Docker
TDC2016 POA | Trilha DevOps - Blue-Green Deployment com DockerTDC2016 POA | Trilha DevOps - Blue-Green Deployment com Docker
TDC2016 POA | Trilha DevOps - Blue-Green Deployment com Dockertdc-globalcode
 
TDC2016POA | Trilha Analise de Negocios - Especificação por exemplo como fer...
TDC2016POA | Trilha Analise de Negocios -  Especificação por exemplo como fer...TDC2016POA | Trilha Analise de Negocios -  Especificação por exemplo como fer...
TDC2016POA | Trilha Analise de Negocios - Especificação por exemplo como fer...tdc-globalcode
 

Destaque (20)

DDD na prática :: Implementação tática – Entidades vs Objeto de Valor
DDD na prática :: Implementação tática – Entidades vs Objeto de ValorDDD na prática :: Implementação tática – Entidades vs Objeto de Valor
DDD na prática :: Implementação tática – Entidades vs Objeto de Valor
 
TDC2016POA | Trilha .NET - O que esperar do C# 7
TDC2016POA | Trilha .NET - O que esperar do C# 7TDC2016POA | Trilha .NET - O que esperar do C# 7
TDC2016POA | Trilha .NET - O que esperar do C# 7
 
TDC2016POA \ Trilha Analise Negocios - Agregando valor sem trauma: como trans...
TDC2016POA \ Trilha Analise Negocios - Agregando valor sem trauma: como trans...TDC2016POA \ Trilha Analise Negocios - Agregando valor sem trauma: como trans...
TDC2016POA \ Trilha Analise Negocios - Agregando valor sem trauma: como trans...
 
TDC2016POA | Trilha .NET - .NET Entity Core 1.0
TDC2016POA | Trilha .NET - .NET Entity Core 1.0TDC2016POA | Trilha .NET - .NET Entity Core 1.0
TDC2016POA | Trilha .NET - .NET Entity Core 1.0
 
Inspeção e Adaptação no Scrum com Indicadores de Resultado e Direção | TDC PO...
Inspeção e Adaptação no Scrum com Indicadores de Resultado e Direção | TDC PO...Inspeção e Adaptação no Scrum com Indicadores de Resultado e Direção | TDC PO...
Inspeção e Adaptação no Scrum com Indicadores de Resultado e Direção | TDC PO...
 
TDC 2016 |Trilha DevOps - Dissecando e entendendo pipelines de entrega de sof...
TDC 2016 |Trilha DevOps - Dissecando e entendendo pipelines de entrega de sof...TDC 2016 |Trilha DevOps - Dissecando e entendendo pipelines de entrega de sof...
TDC 2016 |Trilha DevOps - Dissecando e entendendo pipelines de entrega de sof...
 
Palestra: Big Data Open Source com Hadoop - FLISOL 2014 - Curitiba
Palestra: Big Data Open Source com Hadoop - FLISOL 2014 - CuritibaPalestra: Big Data Open Source com Hadoop - FLISOL 2014 - Curitiba
Palestra: Big Data Open Source com Hadoop - FLISOL 2014 - Curitiba
 
TDC2016POA | Trilha Analise de Negocios - Como fatiar seu produto em estórias...
TDC2016POA | Trilha Analise de Negocios - Como fatiar seu produto em estórias...TDC2016POA | Trilha Analise de Negocios - Como fatiar seu produto em estórias...
TDC2016POA | Trilha Analise de Negocios - Como fatiar seu produto em estórias...
 
TDC2016POA | Trilha Agile - Agilidade além da TI: Um Relato de Experiencia
TDC2016POA | Trilha Agile - Agilidade além da TI: Um Relato de ExperienciaTDC2016POA | Trilha Agile - Agilidade além da TI: Um Relato de Experiencia
TDC2016POA | Trilha Agile - Agilidade além da TI: Um Relato de Experiencia
 
TDC2016POA | Trilha Agile - Beyond borders: aplicando ágil em times distribuídos
TDC2016POA | Trilha Agile - Beyond borders: aplicando ágil em times distribuídosTDC2016POA | Trilha Agile - Beyond borders: aplicando ágil em times distribuídos
TDC2016POA | Trilha Agile - Beyond borders: aplicando ágil em times distribuídos
 
TDC2016POA | Trilha Agile - Dual-Track Agile: incluindo o PO e o UX no seu pi...
TDC2016POA | Trilha Agile - Dual-Track Agile: incluindo o PO e o UX no seu pi...TDC2016POA | Trilha Agile - Dual-Track Agile: incluindo o PO e o UX no seu pi...
TDC2016POA | Trilha Agile - Dual-Track Agile: incluindo o PO e o UX no seu pi...
 
TDC2016POA | Trilha Analise de Negocios - Business Coach, o Analista de Negó...
TDC2016POA | Trilha Analise de Negocios -  Business Coach, o Analista de Negó...TDC2016POA | Trilha Analise de Negocios -  Business Coach, o Analista de Negó...
TDC2016POA | Trilha Analise de Negocios - Business Coach, o Analista de Negó...
 
TDC2016POA | Trilha Analise de Negocios - Inovando em negócios com foco na eX...
TDC2016POA | Trilha Analise de Negocios - Inovando em negócios com foco na eX...TDC2016POA | Trilha Analise de Negocios - Inovando em negócios com foco na eX...
TDC2016POA | Trilha Analise de Negocios - Inovando em negócios com foco na eX...
 
TDC2016POA | Trilha Agile - CHA com Scrum Master - Conhecimentos, Habilidades...
TDC2016POA | Trilha Agile - CHA com Scrum Master - Conhecimentos, Habilidades...TDC2016POA | Trilha Agile - CHA com Scrum Master - Conhecimentos, Habilidades...
TDC2016POA | Trilha Agile - CHA com Scrum Master - Conhecimentos, Habilidades...
 
TDC2016POA | Trilha Analise de Negocios - Estranho no ninho: Um brasileiro li...
TDC2016POA | Trilha Analise de Negocios - Estranho no ninho: Um brasileiro li...TDC2016POA | Trilha Analise de Negocios - Estranho no ninho: Um brasileiro li...
TDC2016POA | Trilha Analise de Negocios - Estranho no ninho: Um brasileiro li...
 
TDC2016POA | Trilha Agile - Agile Marketing: os resultados alcançados com pri...
TDC2016POA | Trilha Agile - Agile Marketing: os resultados alcançados com pri...TDC2016POA | Trilha Agile - Agile Marketing: os resultados alcançados com pri...
TDC2016POA | Trilha Agile - Agile Marketing: os resultados alcançados com pri...
 
TDC2016POA | Trilha .NET - Trazendo o poder dos containers ao mundo .NET
TDC2016POA | Trilha .NET -  Trazendo o poder dos containers ao mundo .NETTDC2016POA | Trilha .NET -  Trazendo o poder dos containers ao mundo .NET
TDC2016POA | Trilha .NET - Trazendo o poder dos containers ao mundo .NET
 
TDC2016POA | Trilha Agile - Ágil fora da TI: como expandir o Agil para as are...
TDC2016POA | Trilha Agile - Ágil fora da TI: como expandir o Agil para as are...TDC2016POA | Trilha Agile - Ágil fora da TI: como expandir o Agil para as are...
TDC2016POA | Trilha Agile - Ágil fora da TI: como expandir o Agil para as are...
 
TDC2016 POA | Trilha DevOps - Blue-Green Deployment com Docker
TDC2016 POA | Trilha DevOps - Blue-Green Deployment com DockerTDC2016 POA | Trilha DevOps - Blue-Green Deployment com Docker
TDC2016 POA | Trilha DevOps - Blue-Green Deployment com Docker
 
TDC2016POA | Trilha Analise de Negocios - Especificação por exemplo como fer...
TDC2016POA | Trilha Analise de Negocios -  Especificação por exemplo como fer...TDC2016POA | Trilha Analise de Negocios -  Especificação por exemplo como fer...
TDC2016POA | Trilha Analise de Negocios - Especificação por exemplo como fer...
 

Semelhante a TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB

Implementing CQRS and Event Sourcing with RavenDB
Implementing CQRS and Event Sourcing with RavenDBImplementing CQRS and Event Sourcing with RavenDB
Implementing CQRS and Event Sourcing with RavenDBOren Eini
 
How to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeHow to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeDaniel Wellman
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEDarwin Durand
 
properties-how-do-i.pdf
properties-how-do-i.pdfproperties-how-do-i.pdf
properties-how-do-i.pdfShaiAlmog1
 
重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1Chris Huang
 
Refactoring - Mejorando el diseño del código existente
Refactoring - Mejorando el diseño del código existenteRefactoring - Mejorando el diseño del código existente
Refactoring - Mejorando el diseño del código existenteMariano Sánchez
 
Combatendo code smells em Java
Combatendo code smells em Java Combatendo code smells em Java
Combatendo code smells em Java Emmanuel Neri
 
@author public class Person{   String sname, .pdf
  @author   public class Person{   String sname, .pdf  @author   public class Person{   String sname, .pdf
@author public class Person{   String sname, .pdfaplolomedicalstoremr
 
Creating a Facebook Clone - Part XX.pdf
Creating a Facebook Clone - Part XX.pdfCreating a Facebook Clone - Part XX.pdf
Creating a Facebook Clone - Part XX.pdfShaiAlmog1
 
Introduction to ECMAScript 2015
Introduction to ECMAScript 2015Introduction to ECMAScript 2015
Introduction to ECMAScript 2015Tomasz Dziuda
 
Understand Properties in Codename One
Understand Properties in Codename One Understand Properties in Codename One
Understand Properties in Codename One Shai Almog
 
Web2Day 2017 - Concilier DomainDriveDesign et API REST
Web2Day 2017 - Concilier DomainDriveDesign et API RESTWeb2Day 2017 - Concilier DomainDriveDesign et API REST
Web2Day 2017 - Concilier DomainDriveDesign et API RESTNicolas Faugout
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo Ali Parmaksiz
 

Semelhante a TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB (20)

Implementing CQRS and Event Sourcing with RavenDB
Implementing CQRS and Event Sourcing with RavenDBImplementing CQRS and Event Sourcing with RavenDB
Implementing CQRS and Event Sourcing with RavenDB
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
How to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeHow to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy Code
 
VRaptor 4 - JavaOne
VRaptor 4 - JavaOneVRaptor 4 - JavaOne
VRaptor 4 - JavaOne
 
OOP Lab Report.docx
OOP Lab Report.docxOOP Lab Report.docx
OOP Lab Report.docx
 
Manual tecnic sergi_subirats
Manual tecnic sergi_subiratsManual tecnic sergi_subirats
Manual tecnic sergi_subirats
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
 
properties-how-do-i.pdf
properties-how-do-i.pdfproperties-how-do-i.pdf
properties-how-do-i.pdf
 
重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1
 
Refactoring - Mejorando el diseño del código existente
Refactoring - Mejorando el diseño del código existenteRefactoring - Mejorando el diseño del código existente
Refactoring - Mejorando el diseño del código existente
 
Combatendo code smells em Java
Combatendo code smells em Java Combatendo code smells em Java
Combatendo code smells em Java
 
@author public class Person{   String sname, .pdf
  @author   public class Person{   String sname, .pdf  @author   public class Person{   String sname, .pdf
@author public class Person{   String sname, .pdf
 
DotNet Conference: code smells
DotNet Conference: code smellsDotNet Conference: code smells
DotNet Conference: code smells
 
Creating a Facebook Clone - Part XX.pdf
Creating a Facebook Clone - Part XX.pdfCreating a Facebook Clone - Part XX.pdf
Creating a Facebook Clone - Part XX.pdf
 
Introduction to ECMAScript 2015
Introduction to ECMAScript 2015Introduction to ECMAScript 2015
Introduction to ECMAScript 2015
 
Understand Properties in Codename One
Understand Properties in Codename One Understand Properties in Codename One
Understand Properties in Codename One
 
Web2Day 2017 - Concilier DomainDriveDesign et API REST
Web2Day 2017 - Concilier DomainDriveDesign et API RESTWeb2Day 2017 - Concilier DomainDriveDesign et API REST
Web2Day 2017 - Concilier DomainDriveDesign et API REST
 
Writing Good Tests
Writing Good TestsWriting Good Tests
Writing Good Tests
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
 
CSharp v1.0.2
CSharp v1.0.2CSharp v1.0.2
CSharp v1.0.2
 

Mais de tdc-globalcode

TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidadeTDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidadetdc-globalcode
 
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...tdc-globalcode
 
TDC2019 Intel Software Day - ACATE - Cases de Sucesso
TDC2019 Intel Software Day - ACATE - Cases de SucessoTDC2019 Intel Software Day - ACATE - Cases de Sucesso
TDC2019 Intel Software Day - ACATE - Cases de Sucessotdc-globalcode
 
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPATDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPAtdc-globalcode
 
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVinoTDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVinotdc-globalcode
 
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...tdc-globalcode
 
TDC2019 Intel Software Day - Inferencia de IA em edge devices
TDC2019 Intel Software Day - Inferencia de IA em edge devicesTDC2019 Intel Software Day - Inferencia de IA em edge devices
TDC2019 Intel Software Day - Inferencia de IA em edge devicestdc-globalcode
 
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca PublicaTrilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publicatdc-globalcode
 
Trilha .Net - Programacao funcional usando f#
Trilha .Net - Programacao funcional usando f#Trilha .Net - Programacao funcional usando f#
Trilha .Net - Programacao funcional usando f#tdc-globalcode
 
TDC2018SP | Trilha Go - Case Easylocus
TDC2018SP | Trilha Go - Case EasylocusTDC2018SP | Trilha Go - Case Easylocus
TDC2018SP | Trilha Go - Case Easylocustdc-globalcode
 
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?tdc-globalcode
 
TDC2018SP | Trilha Go - Clean architecture em Golang
TDC2018SP | Trilha Go - Clean architecture em GolangTDC2018SP | Trilha Go - Clean architecture em Golang
TDC2018SP | Trilha Go - Clean architecture em Golangtdc-globalcode
 
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QATDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QAtdc-globalcode
 
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendenciaTDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendenciatdc-globalcode
 
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR ServiceTDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Servicetdc-globalcode
 
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NETTDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NETtdc-globalcode
 
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8tdc-globalcode
 
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...tdc-globalcode
 
TDC2018SP | Trilha .Net - .NET funcional com F#
TDC2018SP | Trilha .Net - .NET funcional com F#TDC2018SP | Trilha .Net - .NET funcional com F#
TDC2018SP | Trilha .Net - .NET funcional com F#tdc-globalcode
 
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Core
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor  em .Net CoreTDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor  em .Net Core
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Coretdc-globalcode
 

Mais de tdc-globalcode (20)

TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidadeTDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
 
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
 
TDC2019 Intel Software Day - ACATE - Cases de Sucesso
TDC2019 Intel Software Day - ACATE - Cases de SucessoTDC2019 Intel Software Day - ACATE - Cases de Sucesso
TDC2019 Intel Software Day - ACATE - Cases de Sucesso
 
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPATDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
 
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVinoTDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
 
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
 
TDC2019 Intel Software Day - Inferencia de IA em edge devices
TDC2019 Intel Software Day - Inferencia de IA em edge devicesTDC2019 Intel Software Day - Inferencia de IA em edge devices
TDC2019 Intel Software Day - Inferencia de IA em edge devices
 
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca PublicaTrilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
 
Trilha .Net - Programacao funcional usando f#
Trilha .Net - Programacao funcional usando f#Trilha .Net - Programacao funcional usando f#
Trilha .Net - Programacao funcional usando f#
 
TDC2018SP | Trilha Go - Case Easylocus
TDC2018SP | Trilha Go - Case EasylocusTDC2018SP | Trilha Go - Case Easylocus
TDC2018SP | Trilha Go - Case Easylocus
 
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
 
TDC2018SP | Trilha Go - Clean architecture em Golang
TDC2018SP | Trilha Go - Clean architecture em GolangTDC2018SP | Trilha Go - Clean architecture em Golang
TDC2018SP | Trilha Go - Clean architecture em Golang
 
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QATDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
 
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendenciaTDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
 
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR ServiceTDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
 
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NETTDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
 
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
 
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
 
TDC2018SP | Trilha .Net - .NET funcional com F#
TDC2018SP | Trilha .Net - .NET funcional com F#TDC2018SP | Trilha .Net - .NET funcional com F#
TDC2018SP | Trilha .Net - .NET funcional com F#
 
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Core
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor  em .Net CoreTDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor  em .Net Core
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Core
 

Último

AUDIENCE THEORY -CULTIVATION THEORY - GERBNER.pptx
AUDIENCE THEORY -CULTIVATION THEORY -  GERBNER.pptxAUDIENCE THEORY -CULTIVATION THEORY -  GERBNER.pptx
AUDIENCE THEORY -CULTIVATION THEORY - GERBNER.pptxiammrhaywood
 
Proudly South Africa powerpoint Thorisha.pptx
Proudly South Africa powerpoint Thorisha.pptxProudly South Africa powerpoint Thorisha.pptx
Proudly South Africa powerpoint Thorisha.pptxthorishapillay1
 
Transaction Management in Database Management System
Transaction Management in Database Management SystemTransaction Management in Database Management System
Transaction Management in Database Management SystemChristalin Nelson
 
Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Mark Reed
 
FILIPINO PSYCHology sikolohiyang pilipino
FILIPINO PSYCHology sikolohiyang pilipinoFILIPINO PSYCHology sikolohiyang pilipino
FILIPINO PSYCHology sikolohiyang pilipinojohnmickonozaleda
 
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17Celine George
 
How to Add Barcode on PDF Report in Odoo 17
How to Add Barcode on PDF Report in Odoo 17How to Add Barcode on PDF Report in Odoo 17
How to Add Barcode on PDF Report in Odoo 17Celine George
 
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdf
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdfAMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdf
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdfphamnguyenenglishnb
 
How to do quick user assign in kanban in Odoo 17 ERP
How to do quick user assign in kanban in Odoo 17 ERPHow to do quick user assign in kanban in Odoo 17 ERP
How to do quick user assign in kanban in Odoo 17 ERPCeline George
 
Karra SKD Conference Presentation Revised.pptx
Karra SKD Conference Presentation Revised.pptxKarra SKD Conference Presentation Revised.pptx
Karra SKD Conference Presentation Revised.pptxAshokKarra1
 
ISYU TUNGKOL SA SEKSWLADIDA (ISSUE ABOUT SEXUALITY
ISYU TUNGKOL SA SEKSWLADIDA (ISSUE ABOUT SEXUALITYISYU TUNGKOL SA SEKSWLADIDA (ISSUE ABOUT SEXUALITY
ISYU TUNGKOL SA SEKSWLADIDA (ISSUE ABOUT SEXUALITYKayeClaireEstoconing
 
Field Attribute Index Feature in Odoo 17
Field Attribute Index Feature in Odoo 17Field Attribute Index Feature in Odoo 17
Field Attribute Index Feature in Odoo 17Celine George
 
ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4MiaBumagat1
 
Science 7 Quarter 4 Module 2: Natural Resources.pptx
Science 7 Quarter 4 Module 2: Natural Resources.pptxScience 7 Quarter 4 Module 2: Natural Resources.pptx
Science 7 Quarter 4 Module 2: Natural Resources.pptxMaryGraceBautista27
 
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxMULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxAnupkumar Sharma
 
Culture Uniformity or Diversity IN SOCIOLOGY.pptx
Culture Uniformity or Diversity IN SOCIOLOGY.pptxCulture Uniformity or Diversity IN SOCIOLOGY.pptx
Culture Uniformity or Diversity IN SOCIOLOGY.pptxPoojaSen20
 
Concurrency Control in Database Management system
Concurrency Control in Database Management systemConcurrency Control in Database Management system
Concurrency Control in Database Management systemChristalin Nelson
 

Último (20)

AUDIENCE THEORY -CULTIVATION THEORY - GERBNER.pptx
AUDIENCE THEORY -CULTIVATION THEORY -  GERBNER.pptxAUDIENCE THEORY -CULTIVATION THEORY -  GERBNER.pptx
AUDIENCE THEORY -CULTIVATION THEORY - GERBNER.pptx
 
Proudly South Africa powerpoint Thorisha.pptx
Proudly South Africa powerpoint Thorisha.pptxProudly South Africa powerpoint Thorisha.pptx
Proudly South Africa powerpoint Thorisha.pptx
 
Transaction Management in Database Management System
Transaction Management in Database Management SystemTransaction Management in Database Management System
Transaction Management in Database Management System
 
Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)
 
FILIPINO PSYCHology sikolohiyang pilipino
FILIPINO PSYCHology sikolohiyang pilipinoFILIPINO PSYCHology sikolohiyang pilipino
FILIPINO PSYCHology sikolohiyang pilipino
 
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17
Incoming and Outgoing Shipments in 3 STEPS Using Odoo 17
 
Model Call Girl in Tilak Nagar Delhi reach out to us at 🔝9953056974🔝
Model Call Girl in Tilak Nagar Delhi reach out to us at 🔝9953056974🔝Model Call Girl in Tilak Nagar Delhi reach out to us at 🔝9953056974🔝
Model Call Girl in Tilak Nagar Delhi reach out to us at 🔝9953056974🔝
 
How to Add Barcode on PDF Report in Odoo 17
How to Add Barcode on PDF Report in Odoo 17How to Add Barcode on PDF Report in Odoo 17
How to Add Barcode on PDF Report in Odoo 17
 
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdf
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdfAMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdf
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdf
 
How to do quick user assign in kanban in Odoo 17 ERP
How to do quick user assign in kanban in Odoo 17 ERPHow to do quick user assign in kanban in Odoo 17 ERP
How to do quick user assign in kanban in Odoo 17 ERP
 
FINALS_OF_LEFT_ON_C'N_EL_DORADO_2024.pptx
FINALS_OF_LEFT_ON_C'N_EL_DORADO_2024.pptxFINALS_OF_LEFT_ON_C'N_EL_DORADO_2024.pptx
FINALS_OF_LEFT_ON_C'N_EL_DORADO_2024.pptx
 
Karra SKD Conference Presentation Revised.pptx
Karra SKD Conference Presentation Revised.pptxKarra SKD Conference Presentation Revised.pptx
Karra SKD Conference Presentation Revised.pptx
 
ISYU TUNGKOL SA SEKSWLADIDA (ISSUE ABOUT SEXUALITY
ISYU TUNGKOL SA SEKSWLADIDA (ISSUE ABOUT SEXUALITYISYU TUNGKOL SA SEKSWLADIDA (ISSUE ABOUT SEXUALITY
ISYU TUNGKOL SA SEKSWLADIDA (ISSUE ABOUT SEXUALITY
 
Field Attribute Index Feature in Odoo 17
Field Attribute Index Feature in Odoo 17Field Attribute Index Feature in Odoo 17
Field Attribute Index Feature in Odoo 17
 
ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4
 
Science 7 Quarter 4 Module 2: Natural Resources.pptx
Science 7 Quarter 4 Module 2: Natural Resources.pptxScience 7 Quarter 4 Module 2: Natural Resources.pptx
Science 7 Quarter 4 Module 2: Natural Resources.pptx
 
LEFT_ON_C'N_ PRELIMS_EL_DORADO_2024.pptx
LEFT_ON_C'N_ PRELIMS_EL_DORADO_2024.pptxLEFT_ON_C'N_ PRELIMS_EL_DORADO_2024.pptx
LEFT_ON_C'N_ PRELIMS_EL_DORADO_2024.pptx
 
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxMULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
 
Culture Uniformity or Diversity IN SOCIOLOGY.pptx
Culture Uniformity or Diversity IN SOCIOLOGY.pptxCulture Uniformity or Diversity IN SOCIOLOGY.pptx
Culture Uniformity or Diversity IN SOCIOLOGY.pptx
 
Concurrency Control in Database Management system
Concurrency Control in Database Management systemConcurrency Control in Database Management system
Concurrency Control in Database Management system
 

TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB

  • 1. CQRS e Event Sourcing na prática com RavenDB Elemar Júnior @elemarjr elemarjr@ravendb.net elemarjr@gmail.com elemarjr.com
  • 2. Olá, eu sou Elemar Jr
  • 4. CQRS e Event Sourcing na prática com RavenDB Mas, vamos falar de
  • 5. Vamos pensar em um cenário...
  • 6. Precisamos criar um um cadastro de funcionários...
  • 7. Coisa simples... Nome, Endereço Residencial e Salário
  • 8. Começamos com um protótipo
  • 9. [Route("api/[controller]")] public class EmployeesController : Controller { [HttpGet] public IEnumerable<Employee> Get() { /* .. */ } [HttpGet("{id}")] public Employee Get(string id) { /* .. */ } [HttpPost] public void Post([FromBody]Employee value) { /* .. */ } [HttpPut("{id}")] public void Put(string id, [FromBody]Employee value) { /* .. */ } [HttpDelete("{id}")] public void Delete(string id) { /* .. */} } Podemos modelar uma API...
  • 10. public class Employee { public string Id { get; set; } public string Name { get; set; } public Address HomeAddress { get; set; } public decimal Salary { get; set; } } Definir o Modelo [Route("api/[controller]")] public class EmployeesController : Controller { [HttpGet] public IEnumerable<Employee> Get() { /* .. */ } [HttpGet("{id}")] public Employee Get(string id) { /* .. */ } [HttpPost] public void Post([FromBody]Employee value) { /* .. */ } [HttpPut("{id}")] public void Put(string id, [FromBody]Employee value) { /* .. */ } [HttpDelete("{id}")] public void Delete(string id) { /* .. */} }
  • 11. public class EmployeesRepository { public Employee Load(string id) { using (var session = DocumentStoreHolder.Instance.OpenSession()) { return session.Load<Employee>(id); } } public void Save(Employee newEmployee) { using (var session = DocumentStoreHolder.Instance.OpenSession()) { session.Store(newEmployee); session.SaveChanges(); } } } Implementar persistência....
  • 15. UI (HTML + Angular) WebAPI RavenDB Presentation Business Persistence
  • 16. Esse modelo não está anêmico? public class Employee { public string Id { get; set; } public string Name { get; set; } public Address HomeAddress { get; set; } public decimal Salary { get; set; } }
  • 17. Cadê a linguagem ubíqua? [Route("api/[controller]")] public class EmployeesController : Controller { [HttpGet] public IEnumerable<Employee> Get() { /* .. */ } [HttpGet("{id}")] public Employee Get(string id) { /* .. */ } [HttpPost] public void Post([FromBody]Employee value) { /* .. */ } [HttpPut("{id}")] public void Put(string id, [FromBody]Employee value) { /* .. */ } [HttpDelete("{id}")] public void Delete(string id) { /* .. */} }
  • 19. Será que é fácil de alterar?
  • 20. Vamos tentar resgatar conceitos...
  • 21.
  • 22.
  • 23.
  • 25.
  • 26. Modelo expressa o domínio public sealed class Employee { public Guid Id { get; private set; } public FullName Name { get; private set; } public decimal Salary { get; private set; } public Address HomeAddress { get; private set; } public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ } public void RaiseSalary(decimal amount) { /* .. */ } public void ChangeHomeAddress(Address address) { /* .. */ } }
  • 27. Modelo expressa o domínio public sealed class Employee { public Guid Id { get; private set; } public FullName Name { get; private set; } public decimal Salary { get; private set; } public Address HomeAddress { get; private set; } public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ } public void RaiseSalary(decimal amount) { /* .. */ } public void ChangeHomeAddress(Address address) { /* .. */ } }
  • 28. Modelo expressa o domínio public sealed class Employee { public Guid Id { get; private set; } public FullName Name { get; private set; } public decimal Salary { get; private set; } public Address HomeAddress { get; private set; } public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ } public void RaiseSalary(decimal amount) { /* .. */ } public void ChangeHomeAddress(Address address) { /* .. */ } }
  • 29. Consolidação da Linguagem Ubíqua public sealed class Employee { public Guid Id { get; private set; } public FullName Name { get; private set; } public decimal Salary { get; private set; } public Address HomeAddress { get; private set; } public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ } public void RaiseSalary(decimal amount) { /* .. */ } public void ChangeHomeAddress(Address address) { /* .. */ } }
  • 30. Voltando ao protótipo... public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ }
  • 31. public sealed class Employee { public Guid Id { get; private set; } public FullName Name { get; private set; } public decimal Salary { get; private set; } public Address HomeAddress { get; private set; } public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ } public void RaiseSalary(decimal amount) { /* .. */ } public void ChangeHomeAddress(Address address) { /* .. */ } } Consolidação da Linguagem Ubíqua
  • 32. Cadê o protótipo? public void RaiseSalary(decimal amount) { /* .. */ }
  • 34. Anatomia de um Comando public sealed class UpdateEmployeeHomeAddressCommand : EmployeeCommand { public Address HomeAddress { get; } public UpdateEmployeeHomeAddressCommand( EmployeeId id, Address address) : base(id) { HomeAddress = address; } }
  • 36. public class EmployeeCommandsHandler : IMessageHandler<RegisterEmployeeCommand>, IMessageHandler<RaiseSalaryCommand>, IMessageHandler<ChangeHomeAddressCommand> { private readonly IEmployeeRepository _repository; public EmployeeCommandsHandler(IEmployeeRepository repository) { _repository = repository; } public void Handle(RegisterEmployeeCommand command) { var newEmployee = new Employee(command.Id, command.Name, command.InitialSalary); _repository.Save(newEmployee); } public void Handle(RaiseSalaryCommand command) { var employee = _repository.Load(command.EmployeeId); employee.RaiseSalary(command.Amount); _repository.Save(employee); } public void Handle(ChangeHomeAddressCommand command) { var employee = _repository.Load(command.EmployeeId); employee.ChangeHomeAddress(command.NewAddress); _repository.Save(employee); } }
  • 37.
  • 38.
  • 41. Resolvemos comandos! O que fazemos com consultas
  • 45.
  • 46.
  • 47. E isso é CQRS
  • 48. ... mas e Event Sourcing?
  • 51. Anatomia de um Evento public class EmployeeHomeAddressChangedEvent : VersionedEvent<Guid> { public Address NewAddress { get; } public EmployeeHomeAddressChangedEvent(Address newAddress) { NewAddress = newAddress; } } public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId> { public TSourceId SourceId { get; internal set; } public DateTime When { get; private set; } public int Version { get; internal set; } public VersionedEvent() { When = DateTime.Now; } }
  • 52. Anatomia de um Evento public class EmployeeHomeAddressChangedEvent : VersionedEvent<Guid> { public Address NewAddress { get; } public EmployeeHomeAddressChangedEvent(Address newAddress) { NewAddress = newAddress; } } public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId> { public TSourceId SourceId { get; internal set; } public DateTime When { get; private set; } public int Version { get; internal set; } public VersionedEvent() { When = DateTime.Now; } }
  • 53. Anatomia de um Evento public class EmployeeHomeAddressChangedEvent : VersionedEvent<Guid> { public Address NewAddress { get; } public EmployeeHomeAddressChangedEvent(Address newAddress) { NewAddress = newAddress; } } public class VersionedEvent<TSourceId> : IVersionedEvent<TSourceId> { public TSourceId SourceId { get; internal set; } public DateTime When { get; private set; } public int Version { get; internal set; } public VersionedEvent() { When = DateTime.Now; } }
  • 56. Stream de Eventos No RavenDB é fácil!
  • 57. Stream de Eventos No RavenDB é fácil!
  • 58. ... mas antes é preciso Gerar os Eventos
  • 59. Entidade/Agregado gera Eventos public Employee(Guid id, FullName name, decimal initialSalary) : this(id) { Throw.IfArgumentIsNull(name, nameof(name)); Throw.IfArgumentIsNegative(initialSalary, nameof(initialSalary)); Update(new EmployeeRegisteredEvent(name, initialSalary)); }
  • 60. Entidade/Agregado gera Eventos public void RaiseSalary(decimal amount) { Throw.IfArgumentIsNegative(amount, nameof(amount)); Update(new EmployeeSalaryRaisedEvent(amount)); }
  • 61. Entidade/Agregado gera Eventos public void ChangeHomeAddress(Address address) { Throw.IfArgumentIsNull(address, nameof(address)); Update(new EmployeeHomeAddressChangedEvent(address)); }
  • 62. Atualiza estado a partir dos Eventos protected void Update(VersionedEvent<TId> e) { e.SourceId = Id; e.Version = Version + 1; _handlers[e.GetType()].Invoke(e); Version = e.Version; _pendingEvents.Add(e); }
  • 63. Atualiza estado a partir dos Eventos protected void Update(VersionedEvent<TId> e) { e.SourceId = Id; e.Version = Version + 1; _handlers[e.GetType()].Invoke(e); Version = e.Version; _pendingEvents.Add(e); } private Employee(Guid id) : base(id) { Handles<EmployeeRegisteredEvent>(OnEmployeeRegistered); Handles<EmployeeSalaryRaisedEvent>(OnEmployeeSalaryRaised); Handles<EmployeeHomeAddressChangedEvent>(OnEmployeeHomeAddressChanged); }
  • 64. Atualiza estado a partir dos Eventos protected void Update(VersionedEvent<TId> e) { e.SourceId = Id; e.Version = Version + 1; _handlers[e.GetType()].Invoke(e); Version = e.Version; _pendingEvents.Add(e); } private void OnEmployeeRegistered(EmployeeRegisteredEvent @event) { Name = @event.Name; Salary = @event.InitialSalary; } private void OnEmployeeSalaryRaised(EmployeeSalaryRaisedEvent @event) { Salary += @event.Amount; }
  • 65. Atualiza estado a partir dos Eventos protected void Update(VersionedEvent<TId> e) { e.SourceId = Id; e.Version = Version + 1; _handlers[e.GetType()].Invoke(e); Version = e.Version; _pendingEvents.Add(e); }
  • 70. Salvar um documento com eventospublic void Save(Employee employee) { var head = GetHead(employee.Id); var storedVersion = GetStoredVersionOf(head); if (storedVersion != (employee.Version - employee.PendingEvents.Count())) throw new InvalidOperationException("Invalid object state."); if (head == null) { SaveNewEmployee(employee); } else { SaveEmployeeEvents(employee); } foreach (var evt in employee.PendingEvents) Bus.RaiseEvent(evt); }
  • 71. Salvar um documento com eventos public JsonDocumentMetadata GetHead(Guid id) { string localId = $"employees/{id}"; return _store.DatabaseCommands.Head(localId); } public int GetStoredVersionOf(JsonDocumentMetadata head) { return head ?.Metadata[EmployeeEntityVersion] .Value<int>() ?? 0; }
  • 72. Salvar um documento com eventospublic void Save(Employee employee) { var head = GetHead(employee.Id); var storedVersion = GetStoredVersionOf(head); if (storedVersion != (employee.Version - employee.PendingEvents.Count())) throw new InvalidOperationException("Invalid object state."); if (head == null) { SaveNewEmployee(employee); } else { SaveEmployeeEvents(employee); } foreach (var evt in employee.PendingEvents) Bus.RaiseEvent(evt); }
  • 73. Salvar um documento com eventos private void SaveNewEmployee(Employee employee) { using (var session = _store.OpenSession()) { var document = new EmployeeEvents( employee.Id, employee.PendingEvents ); session.Store(document); session.Advanced.GetMetadataFor(document) .Add(EmployeeEntityVersion, employee.Version); session.SaveChanges(); } }
  • 74. private void SaveEmployeeEvents( Employee employee ) { var patches = new List<PatchRequest>(); foreach (var evt in employee.PendingEvents) { patches.Add(new PatchRequest { Type = PatchCommandType.Add, Name = "Events", Value = RavenJObject.FromObject(evt, _serializer) }); } var localId = $"employees/{employee.Id}"; var addEmployeeEvents = new PatchCommandData() { Key = localId, Patches = patches.ToArray() }; var updateMetadata = new ScriptedPatchCommandData() { Key = localId, Patch = new ScriptedPatchRequest { Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; " } }; _store.DatabaseCommands.Batch(new ICommandData[] { addEmployeeEvents, updateMetadata }); }
  • 75. private void SaveEmployeeEvents( Employee employee ) { var patches = new List<PatchRequest>(); foreach (var evt in employee.PendingEvents) { patches.Add(new PatchRequest { Type = PatchCommandType.Add, Name = "Events", Value = RavenJObject.FromObject(evt, _serializer) }); } var localId = $"employees/{employee.Id}"; var addEmployeeEvents = new PatchCommandData() { Key = localId, Patches = patches.ToArray() }; var updateMetadata = new ScriptedPatchCommandData() { Key = localId, Patch = new ScriptedPatchRequest { Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; " } }; _store.DatabaseCommands.Batch(new ICommandData[] { addEmployeeEvents, updateMetadata }); }
  • 76. private void SaveEmployeeEvents( Employee employee ) { var patches = new List<PatchRequest>(); foreach (var evt in employee.PendingEvents) { patches.Add(new PatchRequest { Type = PatchCommandType.Add, Name = "Events", Value = RavenJObject.FromObject(evt, _serializer) }); } var localId = $"employees/{employee.Id}"; var addEmployeeEvents = new PatchCommandData() { Key = localId, Patches = patches.ToArray() }; var updateMetadata = new ScriptedPatchCommandData() { Key = localId, Patch = new ScriptedPatchRequest { Script = $"this['@metadata']['{EmployeeEntityVersion}'] = {employee.Version}; " } }; _store.DatabaseCommands.Batch(new ICommandData[] { addEmployeeEvents, updateMetadata }); }
  • 77. Salvar um documento com eventospublic void Save(Employee employee) { var head = GetHead(employee.Id); var storedVersion = GetStoredVersionOf(head); if (storedVersion != (employee.Version - employee.PendingEvents.Count())) throw new InvalidOperationException("Invalid object state."); if (head == null) { SaveNewEmployee(employee); } else { SaveEmployeeEvents(employee); } foreach (var evt in employee.PendingEvents) Bus.RaiseEvent(evt); }
  • 78. Carregar um documento com eventos public Employee Load(Guid id) { EmployeeEvents data; using (var session = _store.OpenSession()) { data = session.Load<EmployeeEvents>(id); } return new Employee(id, data.Events); } public Employee(Guid id, IEnumerable<IVersionedEvent<Guid>> history) : this(id) { LoadFrom(history); }
  • 79. Carregar um documento com eventos protected void LoadFrom(IEnumerable<IVersionedEvent<TId>> pastEvents) { foreach (var e in pastEvents) { _handlers[e.GetType()].Invoke(e); Version = e.Version; } }
  • 80.
  • 82. CQRS e Event Sourcing na prática com RavenDB Elemar Júnior @elemarjr elemarjr@ravendb.net elemarjr@gmail.com elemarjr.com