Contact Us

If you still have questions or prefer to get help directly from an agent, please submit a request.
We’ll get back to you as soon as possible.

Please fill out the contact form below and we will reply as soon as possible.

  • Contact Us
  • Home
  • System Architecture

Active Record to Domain Model

Written by Oleksandr Sydorenko

Updated at May 5th, 2025

Contact Us

If you still have questions or prefer to get help directly from an agent, please submit a request.
We’ll get back to you as soon as possible.

Please fill out the contact form below and we will reply as soon as possible.

  • System Architecture
+ More

If the business logic that manipulates active records becomes complex and you notice more and more cases of inconsistencies and duplications, refactor the implementa‐ tion to the domain model pattern.

Start by identifying value objects. What data structures can be modeled as immutable objects? Look for the related business logic, and make it a part of the value objects as well.

Next, analyze the data structures and look for transactional boundaries. To ensure that all state-modifying logic is explicit, make all of the active records’ setters private so that they can only be modified from inside the active record itself. Obviously, expect the compilation to fail; however, the compilation errors will make it clear where the state-modifying logic resides. Refactor it into the active record’s bound‐ aries. For example:

public class Player

{

public Guid Id { get; set; }

public int Points { get; set; }

}

public class ApplyBonus

{

...

public void Execute(Guid playerId, byte percentage)

{

var player = _repository.Load(playerId); player.Points *= 1 + percentage/100.0;

_repository.Save(player);

}

}

In the following code, you can see the first steps toward the transformation. The code won’t compile yet, but the errors will make it explicit where external components are controlling the object’s state:

public class Player

{

public Guid Id { get; private set; }

public int Points { get; private set; }

}

public class ApplyBonus

{

...

public void Execute(Guid playerId, byte percentage)

{

var player = _repository.Load(playerId); player.Points *= 1 + percentage/100.0;

_repository.Save(player);

}

}

In the next iteration, we can move that logic inside the active record’s boundary:

public class Player

{

public Guid Id { get; private set; }

public int Points { get; private set; }

public void ApplyBonus(int percentage)

{

this.Points *= 1 + percentage/100.0;

}

}

When all the state-modifying business logic is moved inside the boundaries of the corresponding objects, examine what hierarchies are needed to ensure strongly con‐ sistent checking of business rules and invariants. Those are good candidates for aggregates. Keeping in mind the aggregate design principles we discussed in Chap‐ ter 6, look for the smallest transaction boundaries, that is, the smallest amount of data that you need to keep strongly consistent. Decompose the hierarchies along those boundaries. Make sure the external aggregates are only referenced by their IDs.

Finally, for each aggregate, identify its root, or the entry point for its public interface. Make the methods of all the other internal objects in the aggregate private and only callable from within the aggregate.

Was this article helpful?

Yes
No
Give feedback about this article

Related Articles

  • Discovering Domain Knowledge
  • Business Problems
  • Knowledge Discovery
  • Communication
  • What Is a Ubiquitous Language?

info@smartphonekey.com

  • Home
  • How It Works
  • Features
  • Residents and Tenants
  • Property Managers
  • Airbnb Hosts
  • Products
  • Blog
  • Guide for Usage and Installation
  • Our Team
  • Contact Us
  • Privacy Policy
  • Terms of Service
  • Facebook
  • Instagram
  • LinkedIn
© 2025, Smartphonekey.com Powered by Shopify
Expand