DEV Community

Cover image for Design a Call Center.
Bernice Waweru
Bernice Waweru

Posted on

Design a Call Center.

Instructions

A call center has three levels of employees: respondent, manager,
and director. An incoming call must be first allocated to a respondent who is free. If the respondent can't handle the call, he or she must escalate the call to a manager. If the manager is not free or not able to handle it, then the call should be escalated to a director. Design the classes and
data structures for this problem. Implement a method dispatchCall() which assigns a call to the first available employee.

Approach

We will follow the approach suggested in Cracking the Coding Interview:

Step 1: Handle Ambiguity

Here we determine the constraints and assumptions we will use in the design.

  • We assume the responders always get the initial calls and they only escalate to manager if they cannot handle it. The call is escalated to the director if the manager cannot handle it and the director can handle all calls.
  • Calls are placed in queue awaiting to be handled.

Step 2: Define the Core Objects

The main objects are Employee, Call,and CallCenter.
The Respondent, Manager, and Director classes inherit from the Employee class.
We also include a Rank class to handle the employee's rank, CallState class to determine the state of each call.

Step 3: Analyze Relationships

An employee can only handle one call at a time.

Step 4: Investigate Actions

The Employee can receive and end a call.
The Responder and Manager can escalate calls.
The CallCenter dispatches calls to available employees.

Implementation

Create an enumeration to define the level of each employee.
We create an enumeration where the levels are functionally constant.
Learn more about enum here.

from enum import Enum

class Rank(Enum):
    RESPONDER = 0
    MANAGER = 1
    DIRECTOR = 2
Enter fullscreen mode Exit fullscreen mode

Create class Employee which is a super class of the Responder, Manager and Director classes.

We implement the Employee class as an abstract class with all the abstract methods common to all employees.

More about abstract classes in python here and here.

An abstract class inherits from the Abstract Base Class ABC. @abstractmethod is a decorator to define an abstract method.

from abc import ABCMeta, abstractmethod
class Employee(metaclass=ABCMeta):

    def __init__(self, employee_id, name, rank, call_center):
        self.employee_id = employee_id
        self.name = name
        self.rank = rank
        self.call = None
        self.call_center = call_center

    def take_call(self, call):
        """Assume the employee will always successfully take the call."""
        self.call = call
        self.call.employee = self
        self.call.state = CallState.IN_PROGRESS

    def complete_call(self):
        self.call.state = CallState.COMPLETE
        self.call_center.notify_call_completed(self.call)

    @abstractmethod
    def escalate_call(self):
        pass

    def _escalate_call(self):
        self.call.state = CallState.READY
        call = self.call
        self.call = None
        self.call_center.notify_call_escalated(call)
Enter fullscreen mode Exit fullscreen mode

Create Responder class inheriting from Employee.
Learn more about inheritance here.

RANK.RESPONDER returns the value of the responder's level

class Responder(Employee):

    def __init__(self, employee_id, name):
        super(Responder, self).__init__(employee_id, name, Rank.RESPONDER)

    def escalate_call(self):
        self.call.level = Rank.MANAGER
        self._escalate_call()
Enter fullscreen mode Exit fullscreen mode

Create the Manager Class inheriting from Employee.

class Manager(Employee):

    def __init__(self, employee_id, name):
        super(Responder, self).__init__(employee_id, name, Rank.MANAGER)

    def escalate_call(self):
        self.call.level = Rank.DIRECTOR
        self._escalate_call()

Enter fullscreen mode Exit fullscreen mode

Create class Director.
Director cannot escalate call; therefore, we throw an error.

class Director(Employee):

    def __init__(self, employee_id, name):
        super(Responder, self).__init__(employee_id, name, Rank.DIRECTOR)

    def escalate_call(self):
        raise NotImplementedError('Directors must be able to handle any call')
Enter fullscreen mode Exit fullscreen mode

Create an enumeration to define the state of a given call.

class CallState(Enum):

    READY = 0
    IN_PROGRESS = 1
    COMPLETE = 2
Enter fullscreen mode Exit fullscreen mode

Create Call class.

class Call(object):

    def __init__(self, rank):
        self.state = CallState.READY
        self.rank = rank
        self.employee = None
Enter fullscreen mode Exit fullscreen mode

Create the CallCenter class.

  • Attributes: responders, managers, directors and calls.
  • methods : dispatch_call, notify when call is escalated,completed,
from collections import deque
class CallCenter(object):

    def __init__(self, responders, managers, directors):
        self.responders = responders
        self.managers = managers
        self.directors = directors
        self.queued_calls = deque()

    def dispatch_call(self, call):
        if call.rank not in (Rank.RESPONDER, Rank.MANAGER, Rank.DIRECTOR):
            raise ValueError('Invalid call rank: {}'.format(call.rank))
        employee = None
        if call.rank == Rank.RESPONDER:
            employee = self._dispatch_call(call, self.responders)
        if call.rank == Rank.MANAGER or employee is None:
            employee = self._dispatch_call(call, self.managers)
        if call.rank == Rank.DIRECTOR or employee is None:
            employee = self._dispatch_call(call, self.directors)
        if employee is None:
            self.queued_calls.append(call)

    def _dispatch_call(self, call, employees):
        for employee in employees:
            if employee.call is None:
                employee.take_call(call)
                return employee
        return None

    def notify_call_escalated(self, call):
        print("Call escalated")

    def notify_call_completed(self, call):
        print("Call completed")

Enter fullscreen mode Exit fullscreen mode

You can find the entire code here.
Happy learning and designing !!!

References

  1. Cracking the Coding Interview
  2. System Design Primer

Top comments (0)