0

For multi-tenant systems, Vaughn Vernon suggests the tenant id should be on the domain entities. This doesn't seem right to me. The tenant id has no business meaning (with the exception of an aggregate in the context of identity/access control). To me, it seem like the tenant id is an application or infrastructure level detail. The repositories that give access to aggregates can be instantiated with the tenant information they need to provide access to the right data.

Consider, if we had a system that served only a single tenant and then we expanded that system to serve multiple tenants. If the tenant id lives on the domain entities, the domain model will have to be modified to accommodate this business rule independent change. If the tenant information is handled by the application layer or infrastructure layer, it will not. This indicates to me that tenant id does not belong in the aggregates or in the domain model, in general.

Is there any precedent for my perspective in the DDD literature? Is there something I'm missing that supports the notion of the tenant information being part of the domain model?

Update: After thinking about this and reviewing some of the responses, I have come to the conclusion that tenant must be part of the domain. The thing that finally clenched this for me is domain events and the fact that down stream recipients of those events must be aware of the tenant in order to take tenant specific actions in response to the reception of those events. If tenant id were treated as a infrastructure detail they would not be available for inclusion on domain events. Thanks for all the responses.

  • 2
    This doesn't seem right to me. No offence. When it comes to DDD, our (devs) opinion is not that relevant. We have to rely on what does the domain say about "tenants". Whether tenants belong to the domain or not is something that your domain expert must tell you. Perhaps you are wrong at calling them "tenant" instead of "customer". Perhaps the domain experts call them otherwise, you have to identify it and bring it to the domain model. DDD is tech-savvy. It's pure modelling and conceptualization. – Laiv Sep 9 at 14:22
  • I think you've missed my point. Perhaps I didn't express myself clearly. The scenario I'm describing is one in which I have expressly stated tenant is not part of the bounded context in question. But the tenant id is still relevant to implementation, but its only relevance is to tell the data access what bucket to point to. – Yuli Bonner Sep 9 at 14:43
  • 1
    In "bounded" context may be, hence the Id referencing the tenant. The question is -Is tenant a first-class citizen of the domain?-. As a bounded context itself of as another element. If the tenancy is (in all meanings) out of place in the domain, then you already answered your question, regardless of what Vaughn Vernon suggests. In any case, the answer remains the same "ask your domain experts". Note that the tenancy can be solved in the persistence layer which might or might not match the domain model. In such a case, tenancy is an implementation detail. But we cannot say if that's the case – Laiv Sep 9 at 14:48
  • Are we talking exclusively about cases where each tenant has their own database? Because if the database is shared between tenants (which is less ideal but does happen in reality), you may want the tenant ID in the tables so the queries can perform an additional check in order to prevent tenants accessing each other's data because of a bug (or malicious intent by a user, e.g. knowingly passing a random ID value). It's a fairly effective last line of defense. – Flater Sep 10 at 10:28
  • @Flater in the current case I am talking about database per tenant, but even if the the tenant id was part of the query, that query could be made using the tenant information from the repository instance. – Yuli Bonner Sep 10 at 12:32
2

If you are sure that Tenant is not a part of your domain, you should treat it as an implementation detail just like you would treat an auth token, a user's password, etc.

You need to persist the tenant_id along with your domain entities, but you could manage it centrally. For example, you can create a base class that has only a tenant_id field defined on it, and all other entities subclass from it. Then whenever you persist or query your entities, you can assign tenant_id as part of your infrastructure code, instead of handling it in domain code.

Personally, I think we all end up introducing Tenant into the domain at a later time. We may call it by different names, like Client, Account, Entity or Customer, but there will be well-defined rquirements associated with it like Enterprise-wide Configuration/Rules, Billing/Invoicing and User Permissions/ACLs.

  • If domain entities subclass from a base that has tenant information on it then, by extension, that tenant information part of the domain code. It's worth noting that I'm operating from the assumption of a ports and adapters architecture where the domain code has no outside references. Your suggestion of a base class, is the same as Vaughn Vernon's. My alternative suggestion is that the tenant information, for any bounded context not containing tenant oriented logic would be contained in the implementation (not part of the domain code) of repositories as a infrastructure detail. – Yuli Bonner Sep 10 at 12:43
  • Can you give an example of what you mean by implementation? You need to persist the tenant_id somehow and any mechanism which helps you achieve that would be fine. My base class suggestion is just one example mechanism. – Subhash Bhushan Sep 10 at 13:02
  • The domain defines the repository interface IMyEntityRepository, the application implements it, MyEntityRepository. Only this implementation knows about the tenant information. Thus, the tenant id is not part of the domain code, it's part of the application (or potentially infrastructure) code. – Yuli Bonner Sep 12 at 13:09
0

Let's imagine the problem our company is solving is scrum project management. And the expectation is this has to be a multi-tenant system.

Then product owner could be saying, "A sprint could be linked with one product from the same organization. But the sprint should not be linkable to a product from a different organization."

If the product owner's quote sounds natural, then the companyId (or the tenantId) is part of the domain.

Another way to look at it would be...

The domain we are working with is NOT scrum project management. It is actually enabling different companies to manage their scrum problem. If we solve this problem for few companies that is when we get money. When I look at it this way, tenantId clearly seems part of the domain.

0

After thinking about this and reviewing some of the responses, I have come to the conclusion that tenant must be part of the domain. The thing that finally clenched this for me is domain events and the fact that down stream recipients of those events must be aware of the tenant in order to take tenant specific actions in response to the reception of those events. If tenant id were treated as a infrastructure detail it would not be available for inclusion on domain events. Thanks for all the responses.

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.