I am modeling an application following some DDD and Clean Architecture good practices. I'm at the beginning, trying to define the subdomains, actors and create the user cases for my application using this article as a reference: Better Software Design with Application Layer Use Cases | Enterprise Node.js + TypeScript.
But, I got stuck in a scenario where I could have the same actor for different subdomains. In this case, should I create a shared folder and share domain logic? Duplicating the code among the domains doesn't seem right to me. Or maybe I didn't know how to separate the subdomains correctly.
Let me explain it better:
Let's take a stock management app as an example, with a CRUD for users (staff), products, and with some notifications. This app has just two roles manager and employee. A manager can manage users and products (all CRUD operations), and an employee can just see their own profile, see the products and update the quantity of a product. This app also sends notifications after some actions such as an update of a product. Pretty simple.
I know that I must name actors based on their roles. So, for this system, I know that there are 3 actors: Manager, Employee, and the System itself (for sending notifications). And, I divided this system into 3 subdomains: Stock, Users, and Notifications.
So far so good. However, I got stuck when I tried to draw the use case diagram for this system. I had to duplicate those actors among the subdomains.
Since I have different use cases for each of them in the users subdomain (an employee has limited access). And, I also have different use cases for manager and employee roles in the stock subdomain, I don't think it's appropriate to put the logic to restrict the access to the product creation for the employee role in the users subdomains for example.
So, what I did was just duplicate those roles, and I put the classes and interfaces related to the 2 roles in a shared folder, like src/modules/shared/domain:
|-- src
|-- modules
|-- users
|-- app
|-- domain
|-- infra
|-- stock
|-- app
|-- domain
|-- infra
|-- notifications
|-- app
|-- domain
|-- infra
|-- shared
|-- domain
But, It sounds dirty to me, sharing domain logic across subdomains. What do you guys think? What would you do in this scenario? Maybe I didn't know how to separate the subdomains correctly. The following is the use case diagram I created for this scenario.
Thanks!
The problem that you face here, is that R.C.Martin in his Clean Architecture reused the term "use-case" to define a basic (domain) functionality and make functional decomposition. This creates confusion and leads to such a very detailed, difficult-to-read diagram.
In a use-case analysis, you'd probably have actors goals such as Manage users
, Manage own user account
, Manage products
, Alert/notify users
. Login
/Logout
would not be use-cases, but constraints that are required in the context of most of the use-cases (use-cases would have their own value and be unsequenced with the others, which is clearly not the case for a login)(there are endless debates on this topic, see my other founder answer here).
But don't despair. If you want to deal with this level of detail, the simplest would be to make separate diagrams: one per domain (a model can show the same items under different perspectives in different diagrams). This would keep each diagram simpler, and avoid the confusion of the same actors appearing several times.
Moreover an actor is always external to the system. So the system is not an actor. If App
is shown as an actor, it would mean that this App
is a separate autonomous system, independent from stock management. If it's not the case in your design, and App
is only the front-end to your back-end, don't show it, but show the user/actor who's using the app.
Last but not least, the code structure should be independent of the internals of the system. Maybe R.C.Martin sees this otherwise, but this is written black on white in the UML standard. This is good news for you: this means that reagardless of your diagram(s), you don't have to repeat yourself and adopt bad practices of redundant code. So do as usual, factor out the commonalities between the subdomains. By the way, access management, like login/logout should not be domain logic either. This is some code in outer application services, probably the presenter or gateway layer and the UI.