SlideShare ist ein Scribd-Unternehmen logo
1 von 89
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 sou Microsoft MVP
Eu gosto de aprender coisas novas
Eu gosto de resolver problemas
Eu gosto de escrever compiladores
Eu gosto do
Roslyn (e do
CoddeCracker)
Eu gosto de
Computação Gráfica
Eu gosto de
Heurísticas
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

Weitere ähnliche Inhalte

Was ist angesagt?

Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Alina Vilk
 
MultiClient chatting berbasis gambar
MultiClient chatting berbasis gambarMultiClient chatting berbasis gambar
MultiClient chatting berbasis gambaryoyomay93
 
Multi client
Multi clientMulti client
Multi clientAisy Cuyy
 
TypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic LabsTypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic LabsAlfonso Peletier
 
Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2Technopark
 
Laporan multiclient chatting berbasis grafis (gambar)
Laporan multiclient chatting berbasis grafis (gambar)Laporan multiclient chatting berbasis grafis (gambar)
Laporan multiclient chatting berbasis grafis (gambar)Rara Ariesta
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScriptMichael Girouard
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
 
Multi client
Multi clientMulti client
Multi clientganteng8
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code DevelopmentPeter Gfader
 
What’s new in C# 6
What’s new in C# 6What’s new in C# 6
What’s new in C# 6Fiyaz Hasan
 
Promise: async programming hero
Promise: async programming heroPromise: async programming hero
Promise: async programming heroThe Software House
 
(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your GroovyAlonso Torres
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friendThe Software House
 
Building High Performance Web Applications and Sites
Building High Performance Web Applications and SitesBuilding High Performance Web Applications and Sites
Building High Performance Web Applications and Sitesgoodfriday
 
JNI - Java & C in the same project
JNI - Java & C in the same projectJNI - Java & C in the same project
JNI - Java & C in the same projectKarol Wrótniak
 
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)James Clause
 
Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! aleks-f
 
LINQ Internals - STLDODN
LINQ Internals - STLDODNLINQ Internals - STLDODN
LINQ Internals - STLDODNKeith Dahlby
 

Was ist angesagt? (19)

Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)
 
MultiClient chatting berbasis gambar
MultiClient chatting berbasis gambarMultiClient chatting berbasis gambar
MultiClient chatting berbasis gambar
 
Multi client
Multi clientMulti client
Multi client
 
TypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic LabsTypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic Labs
 
Java весна 2013 лекция 2
Java весна 2013 лекция 2Java весна 2013 лекция 2
Java весна 2013 лекция 2
 
Laporan multiclient chatting berbasis grafis (gambar)
Laporan multiclient chatting berbasis grafis (gambar)Laporan multiclient chatting berbasis grafis (gambar)
Laporan multiclient chatting berbasis grafis (gambar)
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScript
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
Multi client
Multi clientMulti client
Multi client
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
 
What’s new in C# 6
What’s new in C# 6What’s new in C# 6
What’s new in C# 6
 
Promise: async programming hero
Promise: async programming heroPromise: async programming hero
Promise: async programming hero
 
(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friend
 
Building High Performance Web Applications and Sites
Building High Performance Web Applications and SitesBuilding High Performance Web Applications and Sites
Building High Performance Web Applications and Sites
 
JNI - Java & C in the same project
JNI - Java & C in the same projectJNI - Java & C in the same project
JNI - Java & C in the same project
 
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)
Advanced Dynamic Analysis for Leak Detection (Apple Internship 2008)
 
Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! 
 
LINQ Internals - STLDODN
LINQ Internals - STLDODNLINQ Internals - STLDODN
LINQ Internals - STLDODN
 

Andere mochten auch

TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETtdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negóciostdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negóciostdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negóciostdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negóciostdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negóciostdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negóciostdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negóciostdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negóciostdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negóciostdc-globalcode
 
TDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura EmpresarialTDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura Empresarialtdc-globalcode
 
TDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura EmpresarialTDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura Empresarialtdc-globalcode
 
TDC2016SP - Por dentro do .Net Core
TDC2016SP - Por dentro do .Net CoreTDC2016SP - Por dentro do .Net Core
TDC2016SP - Por dentro do .Net Coretdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negóciostdc-globalcode
 
TDC2016SP - Fillas com php
TDC2016SP - Fillas com phpTDC2016SP - Fillas com php
TDC2016SP - Fillas com phptdc-globalcode
 
TDC2016SP - O que há de novo no Entity Framework Core 1.0
TDC2016SP - O que há de novo no Entity Framework Core 1.0TDC2016SP - O que há de novo no Entity Framework Core 1.0
TDC2016SP - O que há de novo no Entity Framework Core 1.0tdc-globalcode
 
TDC2016SP - Qual a melhor plataforma para se desenvolver?
TDC2016SP - Qual a melhor plataforma para se desenvolver?TDC2016SP - Qual a melhor plataforma para se desenvolver?
TDC2016SP - Qual a melhor plataforma para se desenvolver?tdc-globalcode
 
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hat
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red HatTDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hat
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hattdc-globalcode
 
TDC2016SP - Internet das Coisas
TDC2016SP - Internet das CoisasTDC2016SP - Internet das Coisas
TDC2016SP - Internet das Coisastdc-globalcode
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negóciostdc-globalcode
 

Andere mochten auch (20)

TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NET
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura EmpresarialTDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura Empresarial
 
TDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura EmpresarialTDC2016SP - Trilha Arquitetura Empresarial
TDC2016SP - Trilha Arquitetura Empresarial
 
TDC2016SP - Por dentro do .Net Core
TDC2016SP - Por dentro do .Net CoreTDC2016SP - Por dentro do .Net Core
TDC2016SP - Por dentro do .Net Core
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 
TDC2016SP - Fillas com php
TDC2016SP - Fillas com phpTDC2016SP - Fillas com php
TDC2016SP - Fillas com php
 
TDC2016SP - O que há de novo no Entity Framework Core 1.0
TDC2016SP - O que há de novo no Entity Framework Core 1.0TDC2016SP - O que há de novo no Entity Framework Core 1.0
TDC2016SP - O que há de novo no Entity Framework Core 1.0
 
TDC2016SP - Qual a melhor plataforma para se desenvolver?
TDC2016SP - Qual a melhor plataforma para se desenvolver?TDC2016SP - Qual a melhor plataforma para se desenvolver?
TDC2016SP - Qual a melhor plataforma para se desenvolver?
 
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hat
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red HatTDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hat
TDC2016SP - Novas Oportunidades para o .NET com a parceria Microsoft e Red Hat
 
TDC2016SP - Internet das Coisas
TDC2016SP - Internet das CoisasTDC2016SP - Internet das Coisas
TDC2016SP - Internet das Coisas
 
TDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de NegóciosTDC2016SP - Trilha Análise de Negócios
TDC2016SP - Trilha Análise de Negócios
 

Ähnlich wie TDC2016SP - Trilha .NET

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
 
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
 
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
 
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
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
Uncommon Design Patterns
Uncommon Design PatternsUncommon Design Patterns
Uncommon Design PatternsStefano Fago
 
Best of build 2021 - C# 10 & .NET 6
Best of build 2021 -  C# 10 & .NET 6Best of build 2021 -  C# 10 & .NET 6
Best of build 2021 - C# 10 & .NET 6Moaid Hathot
 
[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancjiJakub Marchwicki
 
Introduction to ECMAScript 2015
Introduction to ECMAScript 2015Introduction to ECMAScript 2015
Introduction to ECMAScript 2015Tomasz Dziuda
 
Building a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceBuilding a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceMaarten Balliauw
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8Dhaval Dalal
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokusHamletDRC
 
Better Software: introduction to good code
Better Software: introduction to good codeBetter Software: introduction to good code
Better Software: introduction to good codeGiordano Scalzo
 
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
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented NetworkingMostafa Amer
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 

Ähnlich wie TDC2016SP - Trilha .NET (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
 
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...
 
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
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
VRaptor 4 - JavaOne
VRaptor 4 - JavaOneVRaptor 4 - JavaOne
VRaptor 4 - JavaOne
 
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
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
OOP Lab Report.docx
OOP Lab Report.docxOOP Lab Report.docx
OOP Lab Report.docx
 
Uncommon Design Patterns
Uncommon Design PatternsUncommon Design Patterns
Uncommon Design Patterns
 
CSharp v1.0.2
CSharp v1.0.2CSharp v1.0.2
CSharp v1.0.2
 
Best of build 2021 - C# 10 & .NET 6
Best of build 2021 -  C# 10 & .NET 6Best of build 2021 -  C# 10 & .NET 6
Best of build 2021 - C# 10 & .NET 6
 
[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji
 
Introduction to ECMAScript 2015
Introduction to ECMAScript 2015Introduction to ECMAScript 2015
Introduction to ECMAScript 2015
 
Building a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceBuilding a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to Space
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 
Better Software: introduction to good code
Better Software: introduction to good codeBetter Software: introduction to good code
Better Software: introduction to good code
 
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
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented Networking
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 

Mehr von 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
 

Mehr von 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
 

Kürzlich hochgeladen

Salient Features of India constitution especially power and functions
Salient Features of India constitution especially power and functionsSalient Features of India constitution especially power and functions
Salient Features of India constitution especially power and functionsKarakKing
 
UGC NET Paper 1 Mathematical Reasoning & Aptitude.pdf
UGC NET Paper 1 Mathematical Reasoning & Aptitude.pdfUGC NET Paper 1 Mathematical Reasoning & Aptitude.pdf
UGC NET Paper 1 Mathematical Reasoning & Aptitude.pdfNirmal Dwivedi
 
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptx
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptxHMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptx
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptxmarlenawright1
 
Interdisciplinary_Insights_Data_Collection_Methods.pptx
Interdisciplinary_Insights_Data_Collection_Methods.pptxInterdisciplinary_Insights_Data_Collection_Methods.pptx
Interdisciplinary_Insights_Data_Collection_Methods.pptxPooja Bhuva
 
80 ĐỀ THI THỬ TUYỂN SINH TIẾNG ANH VÀO 10 SỞ GD – ĐT THÀNH PHỐ HỒ CHÍ MINH NĂ...
80 ĐỀ THI THỬ TUYỂN SINH TIẾNG ANH VÀO 10 SỞ GD – ĐT THÀNH PHỐ HỒ CHÍ MINH NĂ...80 ĐỀ THI THỬ TUYỂN SINH TIẾNG ANH VÀO 10 SỞ GD – ĐT THÀNH PHỐ HỒ CHÍ MINH NĂ...
80 ĐỀ THI THỬ TUYỂN SINH TIẾNG ANH VÀO 10 SỞ GD – ĐT THÀNH PHỐ HỒ CHÍ MINH NĂ...Nguyen Thanh Tu Collection
 
FSB Advising Checklist - Orientation 2024
FSB Advising Checklist - Orientation 2024FSB Advising Checklist - Orientation 2024
FSB Advising Checklist - Orientation 2024Elizabeth Walsh
 
Unit 3 Emotional Intelligence and Spiritual Intelligence.pdf
Unit 3 Emotional Intelligence and Spiritual Intelligence.pdfUnit 3 Emotional Intelligence and Spiritual Intelligence.pdf
Unit 3 Emotional Intelligence and Spiritual Intelligence.pdfDr Vijay Vishwakarma
 
Holdier Curriculum Vitae (April 2024).pdf
Holdier Curriculum Vitae (April 2024).pdfHoldier Curriculum Vitae (April 2024).pdf
Holdier Curriculum Vitae (April 2024).pdfagholdier
 
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...Pooja Bhuva
 
This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.christianmathematics
 
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...Nguyen Thanh Tu Collection
 
On National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan FellowsOn National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan FellowsMebane Rash
 
Plant propagation: Sexual and Asexual propapagation.pptx
Plant propagation: Sexual and Asexual propapagation.pptxPlant propagation: Sexual and Asexual propapagation.pptx
Plant propagation: Sexual and Asexual propapagation.pptxUmeshTimilsina1
 
Sociology 101 Demonstration of Learning Exhibit
Sociology 101 Demonstration of Learning ExhibitSociology 101 Demonstration of Learning Exhibit
Sociology 101 Demonstration of Learning Exhibitjbellavia9
 
How to Add New Custom Addons Path in Odoo 17
How to Add New Custom Addons Path in Odoo 17How to Add New Custom Addons Path in Odoo 17
How to Add New Custom Addons Path in Odoo 17Celine George
 
Understanding Accommodations and Modifications
Understanding  Accommodations and ModificationsUnderstanding  Accommodations and Modifications
Understanding Accommodations and ModificationsMJDuyan
 
SOC 101 Demonstration of Learning Presentation
SOC 101 Demonstration of Learning PresentationSOC 101 Demonstration of Learning Presentation
SOC 101 Demonstration of Learning Presentationcamerronhm
 
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptxMaritesTamaniVerdade
 
Jual Obat Aborsi Hongkong ( Asli No.1 ) 085657271886 Obat Penggugur Kandungan...
Jual Obat Aborsi Hongkong ( Asli No.1 ) 085657271886 Obat Penggugur Kandungan...Jual Obat Aborsi Hongkong ( Asli No.1 ) 085657271886 Obat Penggugur Kandungan...
Jual Obat Aborsi Hongkong ( Asli No.1 ) 085657271886 Obat Penggugur Kandungan...ZurliaSoop
 
How to Manage Global Discount in Odoo 17 POS
How to Manage Global Discount in Odoo 17 POSHow to Manage Global Discount in Odoo 17 POS
How to Manage Global Discount in Odoo 17 POSCeline George
 

Kürzlich hochgeladen (20)

Salient Features of India constitution especially power and functions
Salient Features of India constitution especially power and functionsSalient Features of India constitution especially power and functions
Salient Features of India constitution especially power and functions
 
UGC NET Paper 1 Mathematical Reasoning & Aptitude.pdf
UGC NET Paper 1 Mathematical Reasoning & Aptitude.pdfUGC NET Paper 1 Mathematical Reasoning & Aptitude.pdf
UGC NET Paper 1 Mathematical Reasoning & Aptitude.pdf
 
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptx
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptxHMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptx
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptx
 
Interdisciplinary_Insights_Data_Collection_Methods.pptx
Interdisciplinary_Insights_Data_Collection_Methods.pptxInterdisciplinary_Insights_Data_Collection_Methods.pptx
Interdisciplinary_Insights_Data_Collection_Methods.pptx
 
80 ĐỀ THI THỬ TUYỂN SINH TIẾNG ANH VÀO 10 SỞ GD – ĐT THÀNH PHỐ HỒ CHÍ MINH NĂ...
80 ĐỀ THI THỬ TUYỂN SINH TIẾNG ANH VÀO 10 SỞ GD – ĐT THÀNH PHỐ HỒ CHÍ MINH NĂ...80 ĐỀ THI THỬ TUYỂN SINH TIẾNG ANH VÀO 10 SỞ GD – ĐT THÀNH PHỐ HỒ CHÍ MINH NĂ...
80 ĐỀ THI THỬ TUYỂN SINH TIẾNG ANH VÀO 10 SỞ GD – ĐT THÀNH PHỐ HỒ CHÍ MINH NĂ...
 
FSB Advising Checklist - Orientation 2024
FSB Advising Checklist - Orientation 2024FSB Advising Checklist - Orientation 2024
FSB Advising Checklist - Orientation 2024
 
Unit 3 Emotional Intelligence and Spiritual Intelligence.pdf
Unit 3 Emotional Intelligence and Spiritual Intelligence.pdfUnit 3 Emotional Intelligence and Spiritual Intelligence.pdf
Unit 3 Emotional Intelligence and Spiritual Intelligence.pdf
 
Holdier Curriculum Vitae (April 2024).pdf
Holdier Curriculum Vitae (April 2024).pdfHoldier Curriculum Vitae (April 2024).pdf
Holdier Curriculum Vitae (April 2024).pdf
 
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...
 
This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.
 
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...
 
On National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan FellowsOn National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan Fellows
 
Plant propagation: Sexual and Asexual propapagation.pptx
Plant propagation: Sexual and Asexual propapagation.pptxPlant propagation: Sexual and Asexual propapagation.pptx
Plant propagation: Sexual and Asexual propapagation.pptx
 
Sociology 101 Demonstration of Learning Exhibit
Sociology 101 Demonstration of Learning ExhibitSociology 101 Demonstration of Learning Exhibit
Sociology 101 Demonstration of Learning Exhibit
 
How to Add New Custom Addons Path in Odoo 17
How to Add New Custom Addons Path in Odoo 17How to Add New Custom Addons Path in Odoo 17
How to Add New Custom Addons Path in Odoo 17
 
Understanding Accommodations and Modifications
Understanding  Accommodations and ModificationsUnderstanding  Accommodations and Modifications
Understanding Accommodations and Modifications
 
SOC 101 Demonstration of Learning Presentation
SOC 101 Demonstration of Learning PresentationSOC 101 Demonstration of Learning Presentation
SOC 101 Demonstration of Learning Presentation
 
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx
2024-NATIONAL-LEARNING-CAMP-AND-OTHER.pptx
 
Jual Obat Aborsi Hongkong ( Asli No.1 ) 085657271886 Obat Penggugur Kandungan...
Jual Obat Aborsi Hongkong ( Asli No.1 ) 085657271886 Obat Penggugur Kandungan...Jual Obat Aborsi Hongkong ( Asli No.1 ) 085657271886 Obat Penggugur Kandungan...
Jual Obat Aborsi Hongkong ( Asli No.1 ) 085657271886 Obat Penggugur Kandungan...
 
How to Manage Global Discount in Odoo 17 POS
How to Manage Global Discount in Odoo 17 POSHow to Manage Global Discount in Odoo 17 POS
How to Manage Global Discount in Odoo 17 POS
 

TDC2016SP - Trilha .NET

  • 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. Eu gosto de aprender coisas novas
  • 5. Eu gosto de resolver problemas
  • 6. Eu gosto de escrever compiladores
  • 7. Eu gosto do Roslyn (e do CoddeCracker)
  • 11. CQRS e Event Sourcing na prática com RavenDB Mas, vamos falar de
  • 12. Vamos pensar em um cenário...
  • 13. Precisamos criar um um cadastro de funcionários...
  • 14. Coisa simples... Nome, Endereço Residencial e Salário
  • 15. Começamos com um protótipo
  • 16. [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...
  • 17. 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) { /* .. */} }
  • 18. 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....
  • 22. UI (HTML + Angular) WebAPI RavenDB Presentation Business Persistence
  • 23. 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; } }
  • 24. 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) { /* .. */} }
  • 26. Será que é fácil de alterar?
  • 27. Vamos tentar resgatar conceitos...
  • 28.
  • 29.
  • 30.
  • 32.
  • 33. 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) { /* .. */ } }
  • 34. 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) { /* .. */ } }
  • 35. 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) { /* .. */ } }
  • 36. 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) { /* .. */ } }
  • 37. Voltando ao protótipo... public Employee(Guid id, FullName name, decimal initialSalary) { /* .. */ }
  • 38. 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
  • 39. Cadê o protótipo? public void RaiseSalary(decimal amount) { /* .. */ }
  • 41. Anatomia de um Comando public sealed class UpdateEmployeeHomeAddressCommand : EmployeeCommand { public Address HomeAddress { get; } public UpdateEmployeeHomeAddressCommand( EmployeeId id, Address address) : base(id) { HomeAddress = address; } }
  • 43. 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); } }
  • 44.
  • 45.
  • 48. Resolvemos comandos! O que fazemos com consultas
  • 52.
  • 53.
  • 54. E isso é CQRS
  • 55. ... mas e Event Sourcing?
  • 58. 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; } }
  • 59. 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; } }
  • 60. 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; } }
  • 63. Stream de Eventos No RavenDB é fácil!
  • 64. Stream de Eventos No RavenDB é fácil!
  • 65. ... mas antes é preciso Gerar os Eventos
  • 66. 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)); }
  • 67. Entidade/Agregado gera Eventos public void RaiseSalary(decimal amount) { Throw.IfArgumentIsNegative(amount, nameof(amount)); Update(new EmployeeSalaryRaisedEvent(amount)); }
  • 68. Entidade/Agregado gera Eventos public void ChangeHomeAddress(Address address) { Throw.IfArgumentIsNull(address, nameof(address)); Update(new EmployeeHomeAddressChangedEvent(address)); }
  • 69. 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. 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); }
  • 71. 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; }
  • 72. 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); }
  • 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. 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; }
  • 79. 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); }
  • 80. 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(); } }
  • 81. 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 }); }
  • 82. 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 }); }
  • 83. 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 }); }
  • 84. 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); }
  • 85. 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); }
  • 86. 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; } }
  • 87.
  • 89. CQRS e Event Sourcing na prática com RavenDB Elemar Júnior @elemarjr elemarjr@ravendb.net elemarjr@gmail.com elemarjr.com