I am currently thinking about how I would implement a software I did write some years ago with a Clean-/Hexagonal-/Onion-Architecture. This shall not be a "Grand Redesign from Heaven", since I'm not involved in the project anymore, but rather I'd like to learn what I could have done better.
One thing that I have problems realizing for the specific use-cases is the "Tell, don't ask" principle (TDA). Without going in too much details of the problem domain, I'd like to give a short outline of the main use-cases
Basis premises:
- The data is organized in matches (we have been analyzing a team sport)
- Each match has a number of players each for the home and the visitor team
- There is a number of actions for each match (basically players touching the ball)
- Each action is associated with a player
- For sake of simplicity I left out sets within the match and player substitutions and the like
Use cases for the match
- Add home player
- Add visitor player
- Add action for home/visitor and roster number
(again, there is much more to it, but I think this will be sufficient to describe my problem)
Analyses of the data within the matches (also over multiple matches, but - simplicity) is central to the application. Within the architecture I'd place the analyses on the second ring, since they are not entities of the application, but still provide central use cases. Analyses rely heavily on the filtering and subsequent counting of actions within the match.
- Filtering by the player
- Filtering by other actions (e.g. only take action
A
if it occurs after actionR
, but not after actionD
; only take actionA
after a good or very good actionR
; ...) - Filtering by quality
- Calculations based on the qualities of the remaining actions
- and so forth
Anyway, just asking the match object for its contacts to operate on them would be a violation of TDA. And since the match contains business logic, I feel that I should comply with TDA. On the other hand I don't see a way to add analyses to a match and still keep the analyses definitions on the second ring.
How can I perform analyses of the actions within the match, but still adhere to the TDA? Or shouldn't I operate on a match for the analyses anyway, but directly get the actions from a repository?
var contacts = contactsRepository.GetContactsForMatch(match);
While this would solve the issue for analyses, it would not for saving the contacts for a match - and directly saving from the respective class would certainly violate the SRP and is not in the sense of the architecture paradigms.