This is a very common interview question for judging one’s system design skills. You may use apps like Uber every day, but have you ever wondered how you could design the backend for a similar problem statement?
We will use Java as the programming language. This project will try to cover the following requirements.
We will first try to define entities and then services.
We will also build a class diagram as we proceed
If you are new to Java, this post will be a good start.
Requirement
Register a rider
Register a driver
Book a ride within a given radius
Show the ride history
Update the location of the cab
Use In-memory database
Design Motivation
Rider Entity
Rider Entity will have the following fields:
Name
Phone Number
Country Code
List of booking Ids that this rider has completed
Driver Entity
Driver entity should have the following fields:
Name
Phone Number
Country Code
Possibility of abstract class Personal Info
If we notice the following fields are common in both entities:
Name
Phone Number
Country Code
That implies we can safely abstract out a PersonalInfo class, which will be extended by both the Driver and Rider classes. Rider class can have “The list of booking Ids that this consumer has completed”
At this point, our class diagram should look like the one below:
Vehicle Entity
Vehicle entity should have the following fields:
Car Number
Latitude
Longitude
Type – To store type of car, for example, SUV, Compact, Sedan etc.
IsAvailable – To store if the car is available to hire or not.
DriverId – We will not tightly couple the driver and the vehicle. So, whenever a driver logs in, he will pick up one of the vehicles. This field will store the id of the driver who is currently driving this vehicle.
Booking Entity
The booking entity should have the following fields:
Booking Id
Rider User Id
Car Number
Start Time
End Time
Status
Storage Service
The requirement says that we need to use in-memory database. But what if tomorrow, someone asks us to implement the storage in a database? Or in a cache, like Redis or Memcache?
We will make an IStorageService. This will be an interface which will initially have just one implementation that stores data in-memory using Maps and Lists.
This interface will be like the one shown in the gist below:
public interface IStorageService {
Boolean saveRider(Rider rider);
Boolean saveDriver(Driver driver);
Boolean saveVehicle(Vehicle vehicle);
Boolean updateLocation(Vehicle vehicle);
Boolean book(Booking booking);
Vehicle find(Double lat, Double lon, Double maxDistance);
List<Booking> rideHistory(String riderUserId);
Boolean endTrip(Long timeStamp, String bookingId);
}
Our new class diagram should look like the one below:
Rider Service, Driver Service, Vehicle Service and Booking Service
The first three services will again have interfaces to save the data of a new rider, driver and vehicle. In addition to that, vehicle service should also have a contract to find the vehicle near the given position within the given distance, as well as a contract to update the position of the vehicle.
These three different services will be injected with Storage Service at initialisation, in order to store the data.
Booking Service will have Vehicle Service injected in addition to the Storage Service since we need to find vehicles within the given radius during a booking.
If you don’t understand this statement right now, it’s okay. Please wait for the main class at the end. Things would be clearer then.
The class diagrams look like this now:
Download the project
Download the project using the following link.
https://github.com/rohitsingh20122992/cab
Main Class
import booking.models.Booking;
import booking.service.BookingServiceImpl;
import booking.service.IBookingService;
import driver.models.Driver;
import driver.services.DriverServiceImpl;
import driver.services.IDriverService;
import rider.models.Rider;
import rider.services.IRiderService;
import rider.services.RiderServiceImpl;
import storage.IStorageService;
import storage.StorageServiceImpl;
import vehicle.models.Vehicle;
import vehicle.services.IVehicleService;
import vehicle.services.VehicleServiceImpl;
import java.util.List;
public class CabMain {
private static IStorageService storageService = new StorageServiceImpl();
private static IRiderService riderService = new RiderServiceImpl(storageService);
private static IDriverService driverService = new DriverServiceImpl(storageService);
private static IVehicleService vehicleService = new VehicleServiceImpl(storageService);
private static IBookingService bookingService = new BookingServiceImpl(vehicleService, storageService);
public static void main(String args[]){
Rider rider = new Rider();
rider.setName("harsh");
rider.setCountryCode("+91");
rider.setPhoneNumber("910");
riderService.register(rider);
Driver driver = new Driver();
driver.setName("harsh Driver");
driver.setCountryCode("+91");
driver.setPhoneNumber("9431");
driverService.register(driver);
Vehicle vehicle = new Vehicle();
vehicle.setCarNumber("KA01HK");
vehicle.setLat(1D);
vehicle.setLon(1D);
vehicleService.registerVehicle(vehicle);
vehicle.setLat(2D);
vehicle.setLon(2D);
vehicleService.updateLocation(vehicle);
bookingService.book("+91910", 1D, 2D);
List<Booking> bookingHistory = bookingService.history("+91910");
System.out.println("bookingHistory"+bookingHistory);
}
}
And there you go. This is how you can design and code a cab-hailing service!
Join our discord server if you would like to connect and get access to industry experts for mentorship: Discord for SkillCaptain