2

I am designing a few different systems that revolve around a core system used to manage users, groups, associations between users, group memberships, user profiles and some other things.

System A is a task management system with tasks, assignments, attachments, etc...

System B us the user system.

System C is associated with some business workflow type of things (still figuring this one out)

Essentially I’m trying to determine how best to handle the fact that a table in database A will need to reference a a table in database B.

For example: in the task system, a task can be assigned to a user, or a group defined in the user system.

One idea I read about was to have some processes replicate the required data to tables in each system. So, a table in the task system that holds the group ID and it’s description would be updated when necessary from the user system.

Is this approach viable? Has anyone had success with something similar or different?

0

The most basic relation that must exist is using only Aggregate IDs. That is, the Task Aggregate has only the UserID or GroupID as a property. This has the advantage that is simple but the disadvantage that when displaying data in the UI you would need to join multiple tables from multiple Bounded Contexts. The join can be made using database technology (using the JOIN feature) or in code, by fetching the needed information as a separate query to the remote BC.

In any way the system is not resilient, if any of the services in the other BC fails (or is slow) then a cascade failure occurs. One BC depends on the other BC.

A more complex solution is to use an Anti-corruption layer that imports remote Aggregates as local Value Objects (VOs). That is, the Task Aggregate would have a User Value object as property. This VO is immutable and although it can contain the UserID it is not an entity.

This has the disadvantage that the VOs must be kept in sync with their corresponding Aggregates. There are at least two ways of doing this:

  • using a background process that runs periodically
  • using domain events - the preferred way

It has the huge advantage that the services in the two BCs are independent of each other in regards to resilience. If one service fails then the downstream services would be unaffected.

One other big advantage is that the services would be faster because no joins are happening, all the data is available locally.

You may want to read about CQRS if not done already.

  • @DDrmmr thanks for the feedback! what obfuscating terminology? – Constantin Galbenu Jan 28 at 7:53
  • 1
    @DDrmmr But these are basic terms from the domain-driven-design and this question is tagged so. – Constantin Galbenu Jan 28 at 8:06
  • @DDrmmr I've added links to those terms in case reader needs clarification – Constantin Galbenu Jan 28 at 9:43
  • Putting the answer in a DDD context is helpful for me, so thank you for that :). When you say import the remote aggregate as a value object, what would an implementation of that look like? Do you mean at runtime, or would that value object be persisted to a table? – MavisBeacon Jan 28 at 10:43
  • @MavisBeacon you should persist it to a local database table, just as any property/attribute of the Aggregate; so, instead of persisting just the ID of the remote Aggregate you persist an instance of a class like this: class User { private readonly $id, private readonly $name} (in pseudo code) – Constantin Galbenu Jan 28 at 10:53
3

The fact that tasks and users are stored in database tables is an implementation detail. You don't really want the tables to reference each other or to replicate databases, you just need a logical association between a task and a user.

Each of the three systems you described can be implemented as its own web service, with relations crossing service boundaries only stored in the form of IDs. For example, the task service might store tasks with a group ID, and if you wanted group details (such as list of users), you would call the user service to get that information.

  • One implementation detail in particular that worries me is a scenario where I need to display a list of tasks (hundreds, potentially thousands) that includes details about users or group, such as their name. I definitely want to avoid an N+1 scenario where I’m iterating over a list of tasks and populating the details one by one. – MavisBeacon Jan 28 at 10:34
  • @MavisBeacon There are several strategies (caching, batching, lazy loading etc.) you can employ to solve the presentation issue without undermining the domain model. I can't imagine you'd need to display thousands of items on a single screen. Maybe it's a scrollable list and you can lazy-load user details as tasks come into view? Or maybe there's a small set of hot users that you can cache ahead of time and load the others on demand? – casablanca Jan 30 at 2:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.