Order pickup number system

Order pickup number system

I've always enjoyed coding challenges; obviously at work but also every so often just for fun, usually from a coding-exercise site such as CodingBat or CodinGame. So I thought that I'd try my hand at imagining, writing and finally solving a coding challenge myself:

The challenge

You're tasked with implementing a module of an ordering system for a self-service restaurant. When a customer places an order, they shall receive a pickup number which is called when their order is ready for pickup at the counter. To avoid confusion, the order numbers shall have a configurable cooldown period after the food was picked up in which they may not be assigned again. The numbers of the orders which are currently prepared and the ones of the orders that are ready for pickup shall also be displayed to both the customers and the staff. The first number shall be configurable (at any time).

In coding terms, implement this interface:

public interface IOrderPickupNumberSystem
{
    /// <summary>
    /// Configures the (inclusive) lower minimum order number.
    /// </summary>
    int MinOrderNumber { get; set; }

    TimeSpan OrderNumberCooldown { get; set; }

    /// <summary>
    /// Gets the next free order number and marks it as "in preparation"
    /// </summary>
    int GetNextIdleOrderNumber();

    /// <returns>
    /// All order number which are currently being prepared.
    /// </returns>
    int[] GetOrderNumbersInPreparation();

    /// <returns>
    /// All order number which are waiting for customer pickup.
    /// </returns>    
    int[] GetOrderNumbersReadyForPickup();

    /// <summary>
    /// Marks the order with the specified number as "ready for pickup".
    /// </summary>
    void SetOrderReady(int orderNumber);

    /// <summary>
    /// Gets the total number of order numbers, regardless of status.
    /// </summary>
    int GetOrderNumberPoolSize();

    /// <summary>
    /// Marks the order with the specified number as picked up and initiates the
    /// cooldown.
    /// </summary>
    void SetOrderPickedUp(int orderNumber);
}

Implement yourself

If you want to take the challenge and implement this yourself, clone the repo at the end of this post, delete the contents of the OrderPickupNumberSystem class and have Visual Studio add the method stubs of the interface. When you're finished run the unit tests in the separate testing project to verify your work.

Solution

The data structure

Firstly, this system of unique numbers that have data attached to them screams database. This is a classic primary key scenario and in any productive environment, it would be implemented as such. But for the purposes of this challenge, I decided to use next best thing: a dictionary. I always think of a dictionary as a mini in-memory database. Often, key and value are value data types, such as int and string, but they can really be anything. In this case, the key will represent the order number as an int and the value will be the status of the order number.

At first, one may think that an enum for the states of the order numbers is enough, but there is also the requirement for a configurable cooldown which an enum can definitely not satisfy. Usually, I like to use a strictly implicit approach with something like this, but this time I decided to include the Cooldown state in the enum and an extra DateTime? property for tracking the cooldown time. In the strictly implicit solution, there would be no extra state in the enum and the number would be considered in cooldown if the DateTime? property is set to a non-null value, taking precedence over the actual state denoted by the enum. But this also complicates working with the class.

Getting the next order number

I will describe the implementation of int GetNextIdleOrderNumber() in an iterative fashion:

  1. At the core, the next order number is the minimum order number or the maximum existing order number + 1.
  2. Before that, all existing order numbers must be checked for the first number in the Idle state that is greater than or equal to the minimum order number.
  3. And at first, all existing order numbers must be refreshed in terms of the cooldown.

The info functions

For the int GetOrderNumberPoolSize(), int[] GetOrderNumbersInPreparation() and int[] GetOrderNumbersReadyForPickup() functions, we can simply use the Count property of the Dictionary and the Linq extensions respectively.

The setter functions

The setter functions, void SetOrderReady(int orderNumber) and void SetOrderPickedUp(int orderNumber), get the existing info of the specified order number, checks if a transition is possible to the desired state, sets the new state and, if the order has been picked up, sets the CooldownStart property to DateTime.Now.

GitHub - cronoxyd/OrderPickupNumberSystem
Contribute to cronoxyd/OrderPickupNumberSystem development by creating an account on GitHub.
Marcel Diskowski

Marcel Diskowski