Share
Embed
DDD with OrigoDB
OrigoDB from a Domain Driven Design perspective, presented at the @dotnetfringe conference in Portland Oregon, April 2015
Robert Friberg
April 13, 2015
Transcript
22 slides
-
What is DDD? • Focus on the domain – model
driven design • Ubiquitous language – same lingo across disciplines • Patterns • Aggregates • Entity objects • Value objects • Domain Events • Services • Repository -
Why? Service Layer Domain Layer Data Access Layer Relational Model
Views/SP’s Build faster systems faster -
One simple idea... Keep state in memory Persist operations, not
system state s0 s1 s2 op1 op2 Sn = apply(opn , Sn-1 ) -
... with many names • ARIES – write ahead logging
(WAL) • System prevalance – Prevalyer, java • MongoDB op log • Redis AOF • Memory Image – Martin Fowler • VoltDB – command logging • Akka persistence – logging per actor • Event Sourcing – Greg Young et al -
OrigoDB Kernel Engine Model Storage App Code Server Command Query
File Sql Event Store Custom Consistency Isolation concurrency Sends commands and queries Journaling Snapshots BinaryFormatter ProtoBuf JSON tcp JSON/http In-process calls Domain specific object-graph Domain specific operations Replication Ad-hoc queries Web ui Console or win svc -
Example – the model [Serializable] public class CommerceModel : Model
{ internal SortedDictionary<Guid, Customer> Customers { get; set; } internal SortedDictionary<Guid, Order> Orders { get; set; } internal SortedDictionary<Guid, Product> Products { get; set; } public CommerceModel() { Customers = new SortedDictionary<Guid, Customer>(); Orders = new SortedDictionary<Guid, Order>(); Products = new SortedDictionary<Guid, Product>(); } } -
Command [Serializable] public class AddCustomer : Command<CommerceModel> { public readonly
Guid Id; public readonly string Name; public AddCustomer(Guid id, String name) { Id = id; Name = name; } public override void Execute(CommerceModel model) { if (model.Customers.ContainsKey(Id)) Abort("Duplicate customer id"); var customer = new Customer {Id = Id, Name = Name}; model.Customers.Add(Id, customer); } } -
Query [Serializable] public class CustomerById : Query<CommerceModel, CustomerView> { public
readonly Guid Id; public CustomerById(Guid id) { Id = id; } public override CustomerView Execute(CommerceModel model) { if (!model.Customers.ContainsKey(Id)) throw new Exception("no such customer"); return new CustomerView(model.Customers[Id]); } } -
Start your engines! static void Main(string[] args) { Guid id
= Guid.NewGuid(); var engine = Engine.For<CommerceModel>(); var customerCommand = new AddCustomer(id, "Homer"); engine.Execute(customerCommand); var customerView = engine.Execute(new CustomerById(id)); Console.WriteLine(customerView.Name); Console.WriteLine("{0} orders", customerView.OrderIds.Count); Console.ReadLine(); } -
DDD < - > OrigoDb Aggregates Entity Objects Value Objects
Domain Events Services Bounded Context Model POCO NET Events Commands Repository -
Thank you! • Questions? • Try it, you’ll like it!
• Feedback – tell me what you think • Contribute! • http://origodb.com • @robertfriberg, [email protected] -
The model is an object graph TaskList Task Task Task
TaskList Task Task Task Task Category Category Category Category TaskModel -
x64 vs. x32 • Core Library compiled with AnyCPU •
x32 = 32-bit pointers, max 4GB • x64 = 64-bit pointers • Server ships with x64 and x32 binaries -
IIS Hosting • Disable application pool recycling • Ensure single
process, no farming or LB • Litter controllers with Db.For<M>() / Engine.For<M>() • Or put a static ref somewhere, eg Global.asax -
Implicit operations • Proxy has same interface as the Model
• Method calls are intercepted • void methods interpreted as commands (and logged) • other methods interpreted as queries • Can be overriden with attributes • Local or remote, cluster -
Example static void ProxyExample(IEngine<CommerceModel> engine) { CommerceModel proxy = engine.GetProxy();
proxy.AddProduct(Guid.NewGuid(), "Duff beer", 40, 2.5M); var customers = proxy.Customers.Values .Where(c => c.Name.StartsWith("H")) .Select(c => new CustomerView(c)).ToList(); foreach (var customer in customers) { Console.WriteLine(customer.Name); } }