Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DDD with OrigoDB

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
Tweet

More Decks by Robert Friberg

Other Decks in Programming

Transcript

  1. 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
  2. One simple idea... Keep state in memory Persist operations, not

    system state s0 s1 s2 op1 op2 Sn = apply(opn , Sn-1 )
  3. ... 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
  4. 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
  5. 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>(); } }
  6. 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); } }
  7. 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]); } }
  8. 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(); }
  9. DDD < - > OrigoDb Aggregates Entity Objects Value Objects

    Domain Events Services Bounded Context Model POCO NET Events Commands Repository
  10. Thank you! • Questions? • Try it, you’ll like it!

    • Feedback – tell me what you think • Contribute! • http://origodb.com • @robertfriberg, [email protected]
  11. The model is an object graph TaskList Task Task Task

    TaskList Task Task Task Task Category Category Category Category TaskModel
  12. 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
  13. 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
  14. 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
  15. 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); } }