DDD-rail your Monorail

46a19926f5dff95126e78b7393019c9e?s=47 Andrew Hao
October 21, 2015

DDD-rail your Monorail

The scene cuts to the offices of Delorean - the hottest time-transport startup in town (“it’s like Uber for time travel!”). Beneath the glitzy face of the fast-growing company, we find a defeated engineering team struggling with a large Rails monolith, complete with the battle scars of anemic domain models, spaghetti code, and cut corners. The team is shipping fewer features while battling increasing rates of unexpected regressions. The team wants to break up the monolith to combat complexity, but where do they begin? Join the team as they turn to three Domain-Driven Design (DDD) techniques to discover key domain insights and attempt to design their way out of the monolith mess into a well-defined, cleanly segregated, and service-oriented future. Will they succeed, or will the inexorable tides of time and entropy forever trap this team in the past?

Presentation: https://www.youtube.com/watch?v=TljmIXW2fwM

Don't forget to check out the companion sample app: https://github.com/andrewhao/delorean

46a19926f5dff95126e78b7393019c9e?s=128

Andrew Hao

October 21, 2015
Tweet

Transcript

  1. 3.
  2. 6.

    %

  3. 10.
  4. 11.
  5. 12.
  6. 13.

    The business decides… • Drivers deliver passengers from year A

    to year B. ⌛ • Passengers choose the type of Delorean service they want.
  7. 14.
  8. 15.
  9. 16.
  10. 17.

    The business decides… • Drivers deliver passengers from year A

    to year B. ⌛ • Passengers choose the type of Delorean service they want. • Time travel carpools! 01
  11. 18.
  12. 19.
  13. 20.
  14. 21.

    The business decides… • Drivers deliver passengers from year A

    to year B. ⌛ • Passengers choose the type of Delorean service they want. • Time travel carpools! 01 • DeloreanEATS: Customers order food, drivers pick up from time period and deliver to customer time period!
  15. 22.
  16. 23.
  17. 24.
  18. 25.

    Hm.

  19. 26.
  20. 31.
  21. 38.

    A set of techniques to arrive at a flexible design

    that cleanly maps to the business model
  22. 47.
  23. 68.

    A Customer orders an item from a Menu, which is

    picked up and delivered by the Delivery Agent
  24. 70.

    Ridesharing • Passenger: “…” • Driver: “…” • Trip: “…”

    • Pickup: “…” • Vehicle: “…” • Vehicle Owner: “…”
  25. 71.

    Financial Transaction • Invoice: “…” • Order: “…” • Payment:

    “…” • Royalty: “…” • Salary: “…”
  26. 88.

    Context Map: A tool to visualize how your software systems

    relate to each other and the domain(s)
  27. 111.

    module Financial class ShoppingCart def order @order ||= FoodDelivery::Order.new end

    def amount @order.menu_items.sum(&:cost) + @order.menu_items.sum(&:tax_amount) end def add(item) order.menu_items << item end def remove(item) order.menu_items.delete(item); order.save end end end
  28. 112.
  29. 113.

    module FoodDelivery class Order < ActiveRecord::Base belongs_to :user has_many :order_menu_items

    has_many :menu_items, through: :order_menu_items def total_cost item_cost + tax_cost end def item_cost menu_items.sum(&:cost) end def tax_cost menu_items.sum(&:tax_amount) end def add_item!(menu_item) menu_items << menu_item end def remove_item!(menu_item) menu_items.delete(menu_item); save end end end
  30. 114.

    module Financial class ShoppingCart def order @order ||= FoodDelivery::Order.new end

    def amount @order.total_cost end def add(item) order.add_item!(item) end def remove(item) order.remove_item!(item) end end end Calculation logic kept in FoodDelivery domain Implementation- agnostic
  31. 115.
  32. 120.

    module Rideshare class Trip < ActiveRecord::Base belongs_to :service_tier has_many :trip_pool_trips

    has_one :trip_pool, through: :trip_pool_trips belongs_to :driver, foreign_key: :driver_id, class_name: I belongs_to :passenger, foreign_key: :passenger_id, class_n belongs_to :vehicle belongs_to :order, class_name: FoodDelivery::Order has_one :payment end
  33. 122.
  34. 123.

    module Rideshare class Trip < ActiveRecord::Base belongs_to :service_tier has_many :trip_pool_trips

    has_one :trip_pool, through: :trip_pool_trips belongs_to :driver, foreign_key: :driver_id, class_name: I belongs_to :passenger, foreign_key: :passenger_id, class_n belongs_to :vehicle belongs_to :order, class_name: FoodDelivery::Order has_one :payment end
  35. 124.

    module Rideshare class Trip < ActiveRecord::Base # belongs_to :order, class_name:

    FoodDelivery::Order def order FoodDeliveryAdapter.new.order_from_trip(self) end end end
  36. 133.
  37. 139.

    Big idea: Bounded contexts are separators for linguistic drivers. Keep

    your language consistent in one and only one system