Domain Driven Design

Domain Driven Design

Domain Driven Design advocates for organizing your code around how your business and its workflows are organized.

Wikipedia Page: https://en.wikipedia.org/wiki/Domain-driven_design

It's difficult to map domain driven design to a specific code implementation because it's a concept, not a software framework. However, important parts of the concept include:

Entities

An object with a unique identifier. Its attributes may change but the unique identifier lets us continue to acknowledge it as the same entity.

In Ruby on Rails, this could be an ActiveRecord model

create_table :pizzas do |t|
  t.uuid :uuid
  t.string :size
  t.expiration_date :datetime
end

class Pizza << ActiveRecord::Base
end

In this case, the size and expiration_date may change but the uuid tells us it is the same object.

Value Objects

An object without a unique identifier whose attributes determine its value.

In Ruby on Rails, this could be a Money object

value_object_one = Money.new("USD", 10.10) # Currency, Magnitude
value_object_two = Money.new("USD", 10.10) # Currency, Magnitude

value_object_one == value_object_two # would return true

In this case, the combination of currency and magnitude determines what the object represents. Any two instances of the money class with the same attributes are equal.

Aggregates

An abstraction that guarantees the consistency of changes to a collection of entities.

In Ruby on Rails, this could be a custom class that exacts as an interface for making changes to multiple ActiveRecord models which need to be updated together.

class Order
  def place(opts)
    ActiveRecord::Base.transaction do
      if opts[:pizza]
        Pizza.create!(opts[:pizza])
      end

      if opts[:soda]
        Soda.create!(opts[:soda])
      end
    end
  end
end

Services

A service handles the use of aggregates. It's an interface into the domain logic of your codebase.

In Ruby on Rials, this could look like the following:

class OrdersController
  def create
    ProcessPayment.call(params)
    PlaceOrder.call(params)
    SendConfirmation.call(params)
  end
end

class PlaceOrder
  def self.call(opts)
    order = Order.new(opts)
    order.place
  end
end

These are simple examples that cannot illustrate the full reasons why you would want to apply domain driven design to your codebase. In order to learn more, please see the following resources:

Books

  • Domain-Driven Design by Eric Evans
  • Domain-Driven Design Distilled by Vaughn Vernon
  • Implementing Domain-Driven Design by Vaughn Vernon

Sample Applications

  • https://github.com/kgrzybek/modular-monolith-with-ddd

Talks/Videos

  • RailsConf 2014 - Domain Driven Design and Hexagonal Architecture with Rails (https://www.youtube.com/watch?v=_rbF97T4480)