Successfully reported this slideshow.
Your SlideShare is downloading. ×

TechDay: Functional DDD - Alessandro Melchiori

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
El Numero Primo
El Numero Primo
Loading in …3
×

Check these out next

1 of 55 Ad

More Related Content

More from Codemotion (20)

Recently uploaded (20)

Advertisement

TechDay: Functional DDD - Alessandro Melchiori

  1. 1. Functional Domain Driven Design disclaimer: is still a “work in progress”
  2. 2. Focus on the domain and domain logic rather than technology (Eric Evans)
  3. 3. Why not with a functional approach?
  4. 4. A monad is a triple (T,  η,  μ) where T is an endofunctor T:  X-­‐>X and η:  I-­‐>T and μ:  T  x  T-­‐>T are 2 natural transformations satisfying these laws: •  Identity law: μ(η(T))  =  T  =  μ(T(η))     •  Associative law: μ(μ(T  ×  T)  ×  T))  =  μ(T  ×  μ(T   ×  T)) A monad in X is just a monoid in the category of endofunctors of X, with product × replaced by composition of endofunctors and unit set by the identity endofunctor What is a monad?
  5. 5. software developer @ codiceplastico @amelchiori alessandro@codiceplastico.com About me
  6. 6. F#: a gentle introduction
  7. 7. let  myString  =  "original  value"   let  myString  =  "new  value”         Immutability: values, not variables! Duplicate definition of value ‘myString’
  8. 8. let  add  x  y  =  x  +  y   add  2  2     x:int  -­‐>  y:int  -­‐>  int     Type inference
  9. 9. void  ProcessItems(Item[]  items,  Action<Item>  action)   {          for(int  i  =  0;  i  <  items.Length;  i++)          {                  var  item  =  items[i];                  action(item);        }   }   Recursion
  10. 10. let  rec  processItems  action  =  function      |  []              -­‐>  ()        |  head  ::  tail  -­‐>              action  head;              processItems  tail   Recursion
  11. 11. let  add  x  y  =  x  +  y   x:int  -­‐>  y:int  -­‐>  int     Partial function application let  add5  x  =  add  5   x:int  -­‐>  int     let  value  =  add5  10   (value  =  15)    
  12. 12. let  f  x  =  x  *  x   x:int  -­‐>  int     let  g  x  =  -­‐x/2  +  5   x:int  -­‐>  int         Functions composition let  (<<)  f  g  x  =  f  (g  x)   ('b  -­‐>  'c)  -­‐>  ('a  -­‐>  'b)  -­‐>  'a  -­‐>  ’c   let  h  x  =  f  <<  g   x:int  -­‐>  int    
  13. 13. let  square  x  =  x  *  x   let  add  x  y  =  x  +  y   let  toString  x  =  x.ToString()     let  complexFunction  x  =  toString  (add  5  (square  x))   Pipeline operator let  (|>)  x  f  =  f  x   let  complexFunction  x  =  x  |>  square  |>  add  5  |>  toString  
  14. 14. let  div  x  y  =  x  /  y   x:int  -­‐>  y:int  -­‐>  int     div  10  5      //  2   div  10  0      //  System.DivideByZeroException     Option type let  safeDiv  x  y  =          if  y  =  0  then  None          else  Some(x/y)   x:int  -­‐>  y:int  -­‐>  int  option    
  15. 15. let  safeDiv  x  y  =          match  y  with                  |  0  -­‐>  None                  |  _  -­‐>  Some(x/y)     Pattern matching let  safeDiv  x  y  =          match  y  with                  |  0  -­‐>  None                  |  1  -­‐>  Some(x/y)     Incomplete pattern matches on this expression. For example, the value '2' may indicate a case not covered by the pattern(s)  
  16. 16. type  State  =          |  On          |  Off     let  x  =  On   let  y  =  Off     Discriminated unions
  17. 17. let  div  (x,  y)  =  …     (int  *  int)  -­‐  >  int       Tuples let  div  (x,  y)  =    match  (x,  y)  with      |  (_,  0)  -­‐>  None      |  (_,  _)  -­‐>  Some(x/  y)      
  18. 18. type  site  =  {  Title  :  string;  Url  :  string  }       Records let  homepage  =      {  Title  =  "Google";  Url  =  "http://www.google.com"  }     let  next  =  {  homepage  with  Title  =  "NextPage"  }      
  19. 19. OK! Let’s go…
  20. 20. public  class  Company   {    public  String  BusinessName  {  get;  set;  }    public  String  TaxCode  {  get;  set;  }    public  String  VatNumber  {  get;  set;  }      public  String  AssignedBank  {  get;  set;  }    public  Boolean  IsBankAuthorized  {  get;  set;  }   }  
  21. 21. Value object An immutable object, like money or a date range, whose equality isn't based on identity (in general equality is based on all fields equality) Martin Fowler
  22. 22. Value object An immutable object, like money or a date range, whose equality isn't based on identity (in general equality is based on all fields equality) Martin Fowler
  23. 23. public  class  CompanyProfile   {    public  String  BusinessName  {  get;  private  set;  }    public  String  TaxCode  {  get;  private  set;  }    public  String  VatNumber  {  get;  private  set;  }      public  CompanyProfile(String  businessName,  String  taxCode,                String  vatNumber=null)    {      //  check  if  parameters  are  valid      BusinessName  =  businessName;      TaxCode  =  taxCode;      VatNumber  =  vatNumber;    }   }   Value object
  24. 24. public  class  CompanyProfile   {    //  same  as  before…    public  override  Boolean  Equals(Object  other)    {      var  target  =  other  as  CompanyProfile;      return  target  ==  null  ?  false  :          target.BusinessName  ==  this.BusinessName          &&  target.TaxCode  ==  this.TaxCode          &&  target.VatCode  ==  this.VatCode;    }      public  override  Int32  GetHashCode()    {      //  ...    }   }   Value object’s equality
  25. 25. type  CompanyProfile  =  {    BusinessName  :  string;    TaxCode  :  string;    VatNumber  :  string   }   Value object in F# option;   let  profile  =  {      BusinessName  =  “CodicePlastico”;    TaxNumber  =  “1234567890”;   }  
  26. 26. Ubiquitous Language is the concept of defining a language (spoken and written) that is equally used across developers and domain experts Ubiquitous language
  27. 27. public  class  Company   {    ...      public  String  AssignedBank  {  get;  set;  }    public  Boolean  IsBankAuthorized  {  get;  set;  }   }   Ubiquitous language
  28. 28. Rule 1: A company must have a bank to work with Rule 2: A company can be authorized to work with its assigned bank Rule 3: A company can be not authorized to work with its assigned bank Business logic
  29. 29. Make illegal states unrepresentable Ubiquitous language
  30. 30. type  Bank  =  Bank  of  string   type  UnauthorizedBank  =  UnauthorizedBank  of  Bank   type  AuthorizedBank  =  AuthorizedBank  of  Bank     type  AssignedBank  =    |  Unauthorized  of  UnauthorizedBank    |  Authorized  of  AuthorizedBank     Business logic in F#
  31. 31. type  CompanyProfile  =  {    BusinessName:  string,    TaxCode:  string,    VatCode:  string  option     }         type  Bank  =  Bank  of  string   type  UnauthorizedBank  =        UnauthorizedBank  of  Bank   type  AuthorizedBank  =        AuthorizedBank  of  Bank   type  AssignedBank  =    |  Unauthorized  of  UnauthorizedBank    |  Authorized  of  AuthorizedBank       type  Company  =  {    Profile:  CompanyProfile,    Bank:  AssignedBank     }     Ubiquitous language to the rescue
  32. 32. The central idea of specification is to separate the statement of how to match a candidate, from the candidate object that it is matched against Specification
  33. 33. type  SpecificationResult  =            |  Success          |  Failure  of  string     type  Spec<'a>  =  'a  -­‐>  SpecificationResult   Specification
  34. 34. type  Category  =            |  Default          |  Premium          |  Gold     type  Customer  =  {          Name:  string;          Category:  Category;   }     Specification: our (simple) domain type  Item  =  {          Code:  string;          Quantity:  int;   }     type  Order  =  {    Number:  string;    Customer:  Customer;    Items:  Item  list;   }  
  35. 35. let  isOrderFullFilled  :  Spec<Order>  =          let  p  order  =                  match  Seq.isEmpty  order.Items  with                  |  true  -­‐>  Failure("Items'  list  empty")                  |  false  -­‐>  Success          in  p     let  isGoldCustomer  :  Spec<Customer>  =          let  p  customer  =                  match  customer.Category  with                  |  Gold  -­‐>  Success                  |  _  -­‐>  Failure("No-­‐gold  customer")          in  p   Specification
  36. 36. let  And  (left:  Spec<'a>)  (right:  Spec<'a>)  :  Spec<'a>  =    let  p  entity  =      match  left  entity  with      |  Success  -­‐>  right  entity      |  _  -­‐>  Failure("And  specification  is  not  satisfied")    in  p   Specification
  37. 37. let  order  =  {          Number  =  "1234";    Customer  =  {  Name  =  "Alessandro";  Category  =  Gold};          Items  =  [                  {  Code  =  "Code1";  Quantity  =  1};                  {  Code  =  "Code2";  Quantity  =  2};    ];   }     let  isOrderValid  =  And      isOrderFullFilled      (adapt  isGoldCustomer  (fun  order  -­‐>  order.Customer))     let  isValid  =  isOrderValid  order   Specification
  38. 38. CQRS & Event Sourcing
  39. 39. A single model cannot be appropriate for reporting, searching and transactional behavior Greg Young CQRS
  40. 40. State transition are an important part of our problem space and should be modeled within our domain Greg Young Event Sourcing
  41. 41. public  void  AddItemToCart(Item  item)   {    //  validation    if  (item  ==  null)      throw  new  ArgumentNullException();      //  execution    _items.Add(item.Id);   }   Commands, events and…fold (step 1)
  42. 42. public  void  AddItemToCart(Item  item)   {    if  (item  ==  null)      throw  new  ArgumentNullException();      var  domainEvent  =  new  ItemAddedToCart        {  CartId  =  this.Id,  ItemId  =  item.Id  };    Apply(domainEvent)   }     private  void  Apply(ItemAddedToCart  domainEvent)   {    _items.Add(domainEvent.ItemId);   }   Commands, events and…fold (step 2)
  43. 43. public  void  AddItemToCart(Item  item)   {    if  (item  ==  null)      throw  new  ArgumentNullException();      var  domainEvent  =  new  ItemAddedToCart        {  CartId  =  this.Id,  ItemId  =  item.Id  };    Apply(this,  domainEvent)   }     private  void  Apply(Cart  target,  ItemAddedToCart  domainEvent)   {    target._items.Add(domainEvent.ItemId);   }   Commands, events and…fold (step 3)
  44. 44. public  static  Cart  Apply(Cart  target,  CartCreated  domainEvent)   {    return  new  Cart  {  Id  =  domainEvent.CartId,  _items  =  new  String[0]  };   }     public  static  Cart  Apply(Cart  target,  ItemAddedToCart  domainEvent)   {    var  items  =  target._items.ToList();    items.Add(domainEvent.ItemId);      return  new  Cart  {  Id  =  domainEvent.CartId,  _items  =  items  };   }     public  static  Cart  Apply(Cart  target,  ItemRemovedFromCart  domainEvent)   {    var  items  =  target._items.ToList();    items.Remove(domainEvent.ItemId);        return  new  Cart  {  Id  =  domainEvent.CartId,  _items  =  items  };   }   Commands, events and…fold (step 4)
  45. 45.            Cart.Apply(null,  new  CartCreated  {  CartId=1  })   Commands, events and…fold (step 5)
  46. 46.        Cart.Apply(        Cart.Apply(null,  new  CartCreated  {  CartId=1}),        new  ItemAddedToCart  {  CartId  =  1,  ItemId  =  "A"  }      )   Commands, events and…fold (step 5)
  47. 47.    Cart.Apply(      Cart.Apply(        Cart.Apply(null,  new  CartCreated  {  CartId=1}),        new  ItemAddedToCart  {  CartId  =  1,  ItemId  =  "A"  }      ),      new  ItemAddedToCart  {  CartId  =  1,  ItemId  =  "B"  }    )   Commands, events and…fold (step 5)
  48. 48. Cart.Apply(    Cart.Apply(      Cart.Apply(        Cart.Apply(null,  new  CartCreated  {  CartId=1}),        new  ItemAddedToCart  {  CartId  =  1,  ItemId  =  "A"  }      ),      new  ItemAddedToCart  {  CartId  =  1,  ItemId  =  "B"  }    ),    new  ItemRemovedFromCart  {  CartId  =  1,  ItemId  =  "A"  }   )   Commands, events and…fold (step 5)
  49. 49. Executing a command: type  Exec  =      (  CartState  *  Command  )  -­‐>  DomainEvent   Applying an event: type  Apply  =      (  CartState  *  DomainEvent  )  -­‐>  CartState     Commands, events and…fold (step 6)
  50. 50. type  Command  =      |  Create  of  string    |  AddItem  of  int    |  RemoveItem  of  int    |  RemoveAllItems    |  Checkout   type  Event  =      |  Created  of  string    |  ItemAdded  of  int    |  ItemRemoved  of  int    |  AllItemsRemoved    |  Checkedout   Commands, events and…fold (step 7)
  51. 51. type  CartState  =  {          Name:  string;          Items:  List<int>;          Active:  bool;   }     let  apply  state  =  function          |  Created  x  -­‐>  {  Cart.empty  with  Name  =  x  }          |  ItemAdded  x  -­‐>  {  state  with  Items  =  List.append  state.Items  [x]  }          |  ItemRemoved  x  -­‐>          {  state  with  Items  =  List.filter  (fun  i  -­‐>  i  <>  x  )  state.Items  }          |  Removed  _  -­‐>  {  state  with  Items  =  List.empty  }          |  Checkedout  _  -­‐>  {  state  with  Active  =  false  }     Commands, events and…fold (step 8)
  52. 52. let  domainEvents  =  [          Created("cart1");          ItemAdded(1);          ItemAdded(2);          Removed;          ItemAdded(3);          Checkedout;   ]     let  state  =  List.fold  apply  Cart.empty  domainEvents   Commands, events and…fold (step 9)
  53. 53. Tackling Complexity in the Heart of Software Eric Evans …but, when DDD?

×