The task
The piece of software I'm writing operates on the following object types:
- Agents
- Calls
- CallQueues
These objects can be linked together, and each of them contains some additional information. For example, a Call contains the caller number, an Agent contains it's name, and so on.
This model should react to external events delivered through a message queue. Most of the events are like the following:
- an Agent has joined a CallQueue;
- an Agent has left a CallQueue;
- a Call was added to a CallQueue;
- a Call has left a CallQueue;
- an Agent has answered a Call;
- an Agent has completed a Call;
- etc.
And so on. Basically, most of the events trigger creation and removal of links between the objects - and also contain additional information. Some events trigger additional business logic, which is outside of the scope of this question.
Updates of Agents, Calls and CallQueues should be observed from outside for scenarios like these:
- delivering application state updates to clients through event streams (e.g. over WebSockets);
- persisting updates to a database;
- etc.
Un update is an event which is raised when either the object's data has changed, or a link to another object was created or removed.
The question
What are the best practices to organize business logic? Options that I have:
Make a separate component for handling each type of object, e. g.
AgentsRegistry
,CallsRegistry
andCallQueuesRegistry
. When, for example, an agent-linked-to-call-queue event happens, catch it in theCallQueuesRegistry
, create a link and notify theAgentsRegistry
, so that both of them execute their business logic. Expose update event streams from each component to the outside world, so that persistance and WebSockets handlers can bind to it and react.Make a single
ApplicationState
component for handling all kinds of events. Process links updates internally. Try to separate business logic into private methods. Expose a single update event stream from the component to the outside world.A mix of the two above: hide separate components behind an
ApplicationState
object, which should react to the events and act as a conductor for type-specific business logic.Put business logic into Agents, Calls and CallQueues - I can hardly envision this kind of approach when Dependency Injection comes into play, and additional components should be used. Also, it is unclear to me which object should react to an agent-has-answered-a-call event: the Agent or the Call.
Which option is preffered and why? What other options exist?
EDIT: split the question in two, renamed Queues to CallQueues.
EDIT 2: Clarification: a CallQueue
is generally a list of calls waiting to be processed by an Agent
who is bound to that particular CallQueue
. It is a virtual representation of a real queue
in an external application, and it has nothing to do with a queue
data structure, because the FIFO logic is managed in that external app. My app only gets notifications about a certain call entering the queue, leaving it (which can happen randomly) or making all the way to a free Agent
and getting connected with it. Multiple CallQueues
exist.
There is no such thing as a queue of Agents
waiting for a Call
, at least in the scope of this app. As far as we're concerned, a pseudo-random free Agent
connects to a pseudo-random Call
form the CallQueue
.
Queues
is a bit confusing. Logically queues of waiting customers and queues of waiting agents would be two different things, and there would probably also be a list of "running" calls. I'd also expect a distinction between an incoming, waiting call (which would e.g. have the the customers number) and a running call, which would have the agent who answered it and could just have a reference to an incoming call for that data.fun getState(): SomeEnum
. The Queues are queues of calls. I have renamed the entity in the post, made it CallsQueue. Thank you for suggestions!