Fork me on GitHub

DDD Aggregates in Rails with ActiveRecord

In Domain Driven Design there is a concept of an Aggregate.

A cluster of associated objects that are treated as a unit for the purpose of data changes. External references are restricted to one member of the Aggregate, designated as the root.

Simply put: an aggregate has one entity that is designated as the root and an object of the root's class is what you would manipulate in your code. The other entities in an aggregate could not stand on their own outside of the aggregate. It is possible to use the aggregate concept using just ActiveRecord in Rails.

Take this Order entity as an example:

Order entity example

In this example an OrderLineItem doesn't really make sense outside of the context of an Order. Having this in your appliation's global namespace doesn't really make sense and just clutters it.

You could namespace it with a module, but then you call Order::Order to use the Order model. However, if you put the model definition for the order line items in the Order class definition you get the benefit of namespacing the line items whilst defining Order as your aggregate root and being the entity that you interface with in your code.

Here's what that looks like:

class Order < ActiveRecord::Base
  belongs_to :customer
  belongs_to :payment
  has_many :line_items

  class LineItem < ActiveRecord::Base
    belongs_to :order
    belongs_to :item
  end
end

When Rails looks up the table name for LineItem it will look for order_line_items since the full class name is now Order::LineItem. Best of all the Order class is the interface to get an order's line items.

Nesting the classes in the same file may seem weird and admittedly you do not have to approach it that way. To me it seems like a better alternative to do that than create a folder and place a separate file for each class, but that seems to indicate more of a namespace to me.

If a aggregate class starts to become unmanageable, then I would try to move more of the functionality to a module that you can include in your class. Using a module will make testing easier anyway.

In the interest of full disclosure: I am by no means a domain driven design expert, or novice even. It was my co-worker Karthik who pointed out to me that what I was doing actually had a DDD term for it.

Comments

Post New Comment »

Loading....