4

Let's say we have three types of objects:

  • Agents
  • Calls
  • CallsQueues

They all can be linked with each other (1to1, 1toM, MtoM) or have no links, and these links change over time. Calls wait in CallsQueues for a free Agent, each Agent serve one Call at a time, and Agents wait for calls in zero, one or multiple CallQueues at the same time.

From different perspectives in the application, each type can be the root type. For example an AgentMonitoringController serves a list of Agents with their current Calls and the CallQueues that the Agent is in, and QueuesMonitoringController does the same with Queues as root objects.

Which options exist to represent links between the objects? The options that I have in mind:

  1. Make each object type a class. Also, create classes AgentToCallLink, CallToCallQueueLink and AgentToCallQueueLink which would hold references to concrete instances of the classes, as in many-to-many relationships in a relational database. Store lists of references to the link classes in both of the entity classes.
  2. Same as in 1, but instead of creating link classes, store only lists of references to concrete instances (which eliminates the possibility of putting additional information into links, like creation datetime).

ORM and any other kind of persistence is not considered.


Also, from which "collection" should these objects be fetched for manipulation? Is repository per type a good idea (e.g. AgentsRepository, CallsRepository, CallsQueuesRepository)?

4

IMHO you should start by getting the model right first. I would not expect a Call to occur in more than one CallQueue at a time, so this is just a 1:M relationship. Moreover, since an Agent can only server one call at a time (as you wrote), this is a 1:1 relationship. The only M:M relationship I see is the one between agents and queues.

You main question, however, stays the same (except in your option 1 there is only one link class required, not three). The answer to this boils down to which level of persistence ignorance you want or need to achieve.

For a fully persistence-ignorant model, you can try to model a Call without any dependencies to a CallQueue entity and without any dependencies to an Agent entity. This is mainly your option 2. For example, the queues will reference their calls by some internal lists, the Agents will have a reference to the Call they currently serve, and agents and queues can reference each other by lists as well. Of course, if you need additional attributes for the link between agents and queues, a class like AgentToCallQueueLink will be required.

One advantage of this is avoiding cyclic dependencies (for example, between Calls and CallQueues), which makes things like unit testing a little bit easier.

However, persistence ignorance does not come for free:

  • achieving persistence is somewhat harder

  • working with isolated subsets of the data (units of work) is harder, since this implicitly assumes that there is a persisting storage in the background holding the data outside the current unit of work

  • getting the transactions correct in a concurrent environment is somewhat harder (especially if you don't want to add CQRS to your system)

For example, by modeling a Call object with a primary key CallID and a foreign key attribute CallQueueID, knowing it will be stored that way in a database, it will become a little bit easier to pull a some Call objects of a queue from the database, manipulate the queue in isolation and update the original CallQueue content without the necessity to delete and rewrite all the calls of the queue. However, now you have introduced a cyclic dependendency between CallQueues and Calls in your domain model (which can be perfectly acceptable, since actually it is just a weak dependency by IDs, not more).

In the past, I have often used both: classes with all foreign key ids as attributes in a 1-to-1 correspondence to the columns in the database, and additionally lists of references, which allows to write more concise code. This is redundant information, of course, but this redundancy is fine as long as the keys are immutable and changing a reference to another instance is either forbidden or properly encapsulated.

So in the end, it is a trade-off. If you need persistence, and don't need persistence ignorance, go with option 1. A repository per type will be then ok. Your mapping from the domain model to a database will be simpler. And if you consider to use an ORM, this will be a natural fit (if you model your classes directly in a way they fit to the restrictions the ORM imposes on them).

However, if you think you really need persistence ignorance, go with option 2, but don't be astonished if persistence, dealing with overlapping units of work and transactional handling will become harder. Option 2 is often a better fit for models where either no persistence is required, or the only way of required persistence is to load and save all the data of an aggregate at once, with no concurrent writers. For this usage, one repo for loading and saving everything might be ok.

1

I'ld almost allways go for the persistence ignorant model (Option 2) , because of the principle of separation of concerns, but it depends on the implementation many times. For example, if you are using a given Persistence Framework which, by default, comes with its own MVC pattern and in which Models are also query builders (typicaly persistence-aware entities) then it does make sense option 1 .BUT not exactly as you are presenting it,with a class for every link, that woudln't make sense.

Also, option 2 it's not an allways do it like that recipe really, you can't do it if you need to store some attributes to the relationship. BUT that doesn't imply that you coudln't mix the two in a persistence ignorant model, creating intermediate classes only when it's necessary to do so.

Finally, I would do the following (but is just a personal choice) :

  • Call knows the Agent with a reference to its instance, and also knows its current CallQueue.

  • CallQueue doesn't know any Call nor holds any list of references of any kind. I think that could lead to messy code. If you want to know, for example, the list of all Calls belonging to a given Queue, you would achieve that on your PersistenceFacade, querying your DB for all the Calls pointing to that CallQueue.

  • Strictly speaking , there is no need for the Agent to know any CallQueue instance. The Call instance knows both the Agent and the CallQueue, so tecnically you would be able to navigate that relationship. This will complicate things when you wanted to know , for example, in which queues a given Agent is. More queries to do, populating a list, etc . Keep in mind that it is a N to N relationship, so you couldn't actually have a single CallQueue reference on the Agent, you can either use a list of references or, even better, you do use an intermediate CallQueueAgent class just to save time and simplify querying. BUT ONLY in this case, because its an N to N, not in the others.

  • The concern of transforming a DB registry to the appropiate Model belongs to your PersistenceFacade class, which also holds the responsability to query your DB. Modern frameworks comes all with a DB Facade which can perfectly do the job. As it's a Facade, you have all the freedoom to modify your persitence logic as you want, and it won't affect your bussiness logic or modeling at all.

Thats all the strenght on the PersistenceFacade pattern and that's why I recommend you to use it, applying a non persistence aware modelling for your bussiness modelling and the principle of separation of concerns.

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.