intermediate

Active Record vs Data Mapper

Contrast models that own persistence methods with mappers that keep domain objects separate from storage concerns.

Active Record puts persistence methods on the domain object: `user.save()`, `order.delete()`. Data Mapper keeps entities plain and routes persistence through a separate mapper or repository layer.

| Pattern | Persistence lives on | Best when | |---------|---------------------|-----------| | Active Record | The model class | CRUD services, rapid prototypes, simple aggregates | | Data Mapper | Mapper / repository | Rich domain rules, test seams, complex transactions |

					// Active Record style (conceptual)
class Order {
  async save() { /* INSERT or UPDATE */ }
}

// Data Mapper style (conceptual)
class Order { /* domain behavior only */ }
class OrderMapper {
  async insert(order: Order) { /* SQL */ }
}
				

On interviews: explain coupling, testability, and transaction boundaries. Rich domain behavior often pushes teams away from models that know how to save themselves.

Common pitfalls: claiming one pattern is always cleaner; Data Mapper ceremony on pure CRUD; Active Record that hides side effects in `save()` hooks.

The trade-off is delivery speed and familiarity versus explicit boundaries when business rules and tests matter.

Checklist:

  • Name where persistence code lives.
  • Connect pattern choice to domain complexity.
  • Discuss test seams and transaction scope.
  • Admit when CRUD pragmatism beats purity.