3

In our project we're trying to apply the Bounded Context ideology and we've faced kind of obvious problem of performance. E.g., we have different classes (in different contexts) for representing a user in the system: Person in our core domain's context and User in security context. So, we have two different repositories for each of the aggregate, but they are using the same table in DB and sometimes accessing the same data.

Is there common solution to minimize db roundtrips in this case? Are there ORM's which deals with it, or should we code some caching system by ourselves?

upd: the db is from legacy app, and we'll have to use it "as is"

vorou
  • 1,869
  • 3
  • 18
  • 35

2 Answers2

3

So, we have two different repositories for each of the aggregate, but they are using the same table in DB and sometimes accessing the same data.

The fact that you have two aggregates stored in the same table is an indication of a problem with the design. In this case, it seems you have two bounded contexts - a BC for the core domain (Person is here) and an identity/access BC (User is here). The BCs are related and the latter can be seen as upstream from the former. A Person in the core domain has a corresponding User in the identity BC, but they are not exactly the same thing.

Beyond this relationship between the BCs there are questions regarding ownership of behavior. For example, both a Person and a User may have a name and what is to be determined is who own's the behavior of changing a name. This can be implemented in several ways. Person may have its own name and changes should be propagated to the identity BC. Similarly, User may own changes to name, in which case they must be propagated to Person via a synchronization mechanism.

Overall, your problem could be addressed in two ways. First, you can store Person and User aggregates in different tables. Any given query should only use one of these tables and they can be synchronized in an eventually consistent matter. Another approach is to decouple the behavioral domain model from a model designed for queries (read-model). This way, you can create a read-model designed to serve a specific screen(s) and have a customized query, perhaps even outside of an ORM.

eulerfx
  • 36,769
  • 7
  • 61
  • 83
  • i forgot to mention that db is from legacy app, so we'll have to use it "as is". thanks for the reply, will check the article you provided. – vorou Mar 26 '13 at 06:35
  • 1
    *"The fact that you have two aggregates stored in the same table is an indication of a problem with the design."* In DDD the design is supposed to be *utterly ignorant* of the database schema, so it's difficult to see that the database could have such influence over the design. *"Another approach is to decouple the behavioral domain model from a model designed for queries (read-model).*" This is great advice though, +1! – MattDavey Mar 26 '13 at 08:39
  • If schema is as is, then I'd still have separate repositories. This way, at least your code will be organized. If you have to select twice from the same table, so be it. Overall, a negligible performance hit. – eulerfx Mar 26 '13 at 15:20
1

If all the Users are Person too (sometimes external services are modeled as special users too), the only data that User and Person should share on the database are their identifiers. Indeed each entity in a domain model should hold references only to the data that they need to ensure their invariants.

Moreover I guess that Users are identified by Username and Persons are identified by something else (VAT code or so..).

Thus, the simplest optimization technique is to avoid to encapsulate in an entity those informations that are not required to ensure its invariants.

Furthermore you simply need an effective context mapping technique to easily pass from User to Person when needed. I use shared identifiers for this.

As an example you can expose the Person's identifier in the User class, so that a simple query to the Person's repository can provide you the data you need.

Finally I suggest you the Vaughn Vernon series on Aggregate Root Design.

Giacomo Tesio
  • 7,144
  • 3
  • 31
  • 48