Hello there Bill.
First I would like to thank you for this awesome video and repo you came with, it opened my mind in ways I can't even express and I'm learning a lot with it. Now to the question.
I'm building a more complex app using a very similar approach but using typescript.
Simplifying the whole thing, I have an entity User
which declares a dependency on a UserRepository
that will be used to check if the given email is unique across the database on creation (which is an enterprise business rule, therefore needs to be here). This UserRepository
interface has a findByEmail
method that returns a simple user data structure (name, email and password).
So far so good, but I have one use case ShowUser
which will be used to display the user information with some extra data. This use case should use the same UserRepository
(defined in the entity), but the return value of findByEmail
now should return a slightly different user data structure, because now I want it to include the user boards, which you can think of as a join of 2 tables.
Now comes the whole problem, with a lot of solutions which seem bad to me.
Solution 1: Easily fix the problem by going to the User
entity and altering the user data structure to include a boards
field. But now I modified the data structure with an application business rule in a place that should only be concerned with enterprise business rules.
Solution 2: Create another method in the interface called maybe findByEmailWithBoards
, which sounds horrible just by the name (what if I need more fields?) and also has the same problem as solution 1.
Solution 3: Make the repository simpler, returning a simple user data structure and creating a new BoardsRepository
to create a "manual join" of both data structures. This sounds a bit better but I completely lose the speed and convenience of joining multiple tables (or even having embedded documents in mongodb) that databases offer, leading me to have to make multiple queries (which can grow a lot) instead of 1, which will probably have a huge impact on performance in certain cases.
Solution 4: Having one UserRepository
interface in the User
entity and another for the use case, which then the implementation would implement both, satisfying both needs. But that sounds very weird for me, especially on how would I name them to differentiate between them.
There are probably more solutions that I came about but all of them seem to have a big drawback like these, so I'm not sure if this is gonna have to be a trade off or maybe I'm missing something.
This approach is a bit different than yours since you don't use the repository/database inside your entities, but there's definitely gonna be a point where you'll have to if you want to have more complex business rules.
So what to do when your application business rules conflict with your enterprise ones like here?
Thanks again and sorry for the long question! I hope you have the time to discuss this because I'm kinda out of ideas for now and I'm really hopping to get to something solid.