List functional requirements for the system (Ask interviewer if stuck)...
List non-functional requirements for the system...
Estimate the scale of the system you are going to design...
Assume we have:
600 compact car parking spots, 300 standard parking spots and 100 oversized vehicle parking spots.
Peak hour entry rate: 30 vehicles per hour
Peak hour exit rate: 30 vehicles per hour
Peak hour length: 2 hours
Off-peak hours entry rate: 10 vehicles per hour
Off-peak hours exit rate: 10 vehicles per hour
The parking lot operates for 12 hours per day.
That means 30 * 2 + 10 * 10 = 160 vehicles a day.
Define what APIs are expected from the system...
enter(license: string, vehicle_size:enum) -> num_of_available_parking_spots, parking_record_id
vehicle_size could be COMPACT, STANDARD or OVERSIZED.
getParkingFee(parking_record_id: string)->fee:float
exit(parking_record_id: string)->leftFee:float
processPayment(parking_record_id: string, payment_id: string, payment_method: enum, card_info: object)
payment_method could be cash, debit or credit
Defining the system data model early on will clarify how data will flow among different components of the system. Also you could draw an ER diagram using the diagramming tool to enhance your design...
PARKING SPOTS TABLE:
VEHICLE PARKING RECORD TABLE:
PAYMENT RECORD TABLE:
You should identify enough components that are needed to solve the actual problem from end to end. Also remember to draw a block diagram using the diagramming tool to augment your design...
This system contains following components:
Client - user-facing UI machines at entrances and exits of the Parking lot.
Server - The main business logic lives here.
Database - Holds table to track current number of available parking spots. As well as recent parking record and payment record.
External Payment System - a third party payment system that takes payment (e.g. square)
Cron machine - Running a cron job to obtain old records (probably records older than 1 year and stores them in cold storage), the records could be cleared up in Database.
Cold Storage - Low cost storage to store old record, as they're seldom accessed.
Explain how the request flows from end to end in your high level design. Also you could draw a sequence diagram using the diagramming tool to enhance your explanation...
Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...
Cron machine & cold storage: The past parking records and payment records might be useful for future reference, audition, etc. However, it is not accessed very frequently, therefore, a cron job could be setup to run monthly and pull data that's over 1 year ago and store them in s3.
Server: we have very low traffic so 1 machine could handle all traffics. However, in order to ensure the availability of the service, we introdcue duplication in the server. We can have multiple (3 might be good enough) machines to serve the data. Whenever a client calls the service, it can use a round robin mechanism to choose a server to call.
Database: Similar to server, we are not expecting a huge number of data, and the data can fit in to one machine. However, in order to avoid downtime introduced by machine crashing or maintenence, we should introduce replica of the database. The database could run in master - slave mode, and the master is responsible to copy data over to slaves. In case the master machine is unavailable, a slave machine will then become the new master.
Explain any trade offs you have made and why you made certain tech choices...
The cold storage is chosen over storing historical data in database for the following reasons.
Try to discuss as many failure scenarios/bottlenecks as possible.
When a database machine is crashed, the service can make use of the replica machine.
When a server machine is crashed, we will have the following scenarios:
If a client is sending an enter request to a server but didn't get a response, it will send the request to a different server. The two servers might end up creating duplicate parking record and update the parking spots table twice. To avoid this, we can have the server update both tables in one transaction (will both succeed or fail). And in the same transaction, the server should first check if there is already a parking record for the same license number.
If a client is sending a getPayment request to a server and didn't get a response, it will just call a different one.
If a client is sending a processPayment request to a server and didn't get a response, it will call another server. As we have a unique payment id from third party payment system, this should not result in duplicate records.
If a client is sending an exit request to a server and didn't get a response, it will call another server. This might resulting in updating the database twice, therefore, the server should update the parking record and the parking spots table in a single transaction, under a condition where the parking record has no exit timestamp.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?
The system could potentially be updated to support multiple parking lots.