Introduction: a rainy night as a system problem
Picture this: it is late at night at a busy airport, it is raining, and the taxi line is long. You have no idea how long you will wait or how much the ride will cost. Now think of opening a ride sharing app like Uber instead: you see nearby cars, a time estimate, a price, and a driver coming just for you.​
This first article turns that simple story into explicit system requirements for an Uber‑like platform. These requirements will guide all architecture, algorithms, and database choices in the rest of the Uber system design series.​
Two main characters: Alice and Bob
To keep the series concrete, use two recurring characters: Alice the rider and Bob the driver. Everything in the system exists to give them a smooth experience.​
Alice’s journey as a rider
From Alice’s point of view, one ride usually looks like this:
- Open the app and see nearby cars with ETAs.
- Enter pickup and destination; see an estimated price.
- Confirm the ride and see which driver accepted.
- Watch the driver move on the map until he arrives.
- Ride to the destination while tracking the route and ETA.
- Get dropped off, pay automatically, and rate the driver.​
These steps translate directly into features: real‑time cars on a map, price estimation, driver assignment, tracking, payments, and ratings.​
Bob’s journey as a driver
For Bob, the same ride looks like this:
- Go online in the app to show he is available.
- Receive trip offers with pickup point, rider rating, and expected earnings.
- Accept or decline within a few seconds.
- Drive to the rider and then to the destination using navigation.
- Finish the trip and see updated daily earnings.
- Maintain a good rating to keep receiving trips.​
Bob’s experience drives requirements around driver state, earnings visibility, and fair, timely matching between riders and drivers.​
Functional requirements: what the system must do
Now turn these stories into clear, testable functional requirements. These will later map to APIs, services, and database tables in the Uber architecture.​
Rider-facing functional requirements
The system must let a rider:
- Discover and planSee nearby drivers with ETAs for different vehicle types.Get an upfront fare estimate before confirming a ride.​
- Book ridesChoose pickup and destination (map or address).Confirm a ride request with a selected product (e.g., normal, SUV).Select a payment method (card, wallet, or cash where supported).​
- Track and complete ridesSee driver’s name, photo, car model, plate, and rating.Track the driver on the map before pickup and during the trip.View live ETA updates and route information.​
- After the ridePay automatically when the trip ends.See a receipt and full fare breakdown.Rate and review the driver and see trip history.​
Driver-facing functional requirements
The system must let a driver:
- Manage availabilityGo online/offline and broadcast whether he is ready to accept trips.Set basic preferences like vehicle type or service area if needed.​
- Receive and respond to trip offersGet trip offers in real time, including pickup position, expected route length, and payout estimate.Accept or decline offers within a strict time window (for example 15–30 seconds).​
- Run and finish tripsStart a trip when the rider enters the car.End a trip when arriving at the destination.View current and historical earnings and ratings.​
These requirements later drive design decisions such as which microservices exist (Trip, Dispatch, Driver, Rider, Payment) and what endpoints and state transitions they support.​
Non‑functional requirements: why Uber is hard to build
Even if you can meet the functional needs with a simple backend, the non‑functional requirements make an Uber‑scale system challenging.​
Scale and performance requirements
The platform must:
- Handle large traffic: millions of trips per day, hundreds of thousands of concurrent users in big cities and at peak times.​
- Keep core actions fast: trip creation, matching, and status updates should complete in under about 100ms on the server side when possible, so the app feels responsive.​
- Support frequent location updates: driver apps may send GPS data every 1–2 seconds while a trip is in progress, which the backend must process efficiently.​
These constraints lead to architecture choices like horizontal scaling, heavy caching, asynchronous processing, and efficient geospatial queries.​
Availability, reliability, and consistency
The platform is used in critical moments (late night, bad weather, events), so it needs to be very reliable:
- Aim for high availability (for example around 99.99% uptime) so riders and drivers can rely on the service almost all the time.
- Design to avoid single points of failure: one region or service failing should not crash the entire system.​
- Accept different consistency levels:Strong consistency for core actions like trip state and payments.Eventual consistency for analytics, dashboards, and some counters.​
These requirements point to multi‑region deployment, replication, retries, and patterns like circuit breakers and graceful degradation.​
Security and trust
The system deals with people, money, and sensitive data:
- Protect personal data (names, phone numbers, emails, locations) in transit and at rest.
- Follow payment security standards (like PCI‑DSS) and integrate with trusted payment providers.​
- Detect and respond to fraud and abuse (for example, stolen cards, fake users, repeated cancellations).​
These needs drive authentication design, encryption choices, logging/auditing, and fraud detection models in later parts of the system design.​
Trip lifecycle as a state machine
Before drawing architecture diagrams, it helps to define a simple trip state machine. Almost every service will either read or influence these states.​
Trip state

Diagram explained in words
- REQUESTED: Alice has asked for a ride, but no driver has accepted yet.
- DRIVER_ASSIGNED: Dispatch has found a driver (Bob) and he has accepted the trip.
- DRIVER_ARRIVING: Bob is driving to the pickup location.
- IN_PROGRESS: Alice is in the car and the trip has started.
- COMPLETED: The trip has finished at the destination; fare calculation can be finalized.
- PAID: Payment has been successfully processed.
- RATED: Alice (and optionally Bob) has submitted ratings, so the lifecycle is fully finished.​
- CANCELLED: The trip was cancelled either by the rider, driver, or system (for example, no driver was found in time).
The arrows show allowed transitions. For example, you cannot go directly from REQUESTED to COMPLETED without passing through an assigned driver and an in‑progress trip. These rules shape validation in APIs and logic in core services.​
Logical capability map (what we will build later)
From these requirements and states, the system naturally breaks into capabilities. Later articles will turn these into specific services, APIs, schemas, and algorithms.​

Diagram explained in words
- The Trips capability sits in the center: it is responsible for the lifecycle of a ride, from REQUESTED to RATED.​
- Riders and Drivers capabilities manage user accounts, profiles, and preferences on each side of the marketplace.​
- Matching is responsible for finding which driver should serve which rider at any moment, based on location, ETA, and rules or ML models.​
- Pricing decides how much a trip will cost (both estimated and final), including surge or discounts.​
- Payments handles charging riders and paying drivers.
- Support capabilities like Auth, Location, Notifications, Ratings, and Analytics cut across these central features and will show up as shared services and libraries in later architecture diagrams.​
This logical map is not yet a microservice diagram, but it tells us what pieces the system needs. Future articles will map each capability to specific services, endpoints, data models, and algorithms.
Conclusion
This first article in the Uber system design series took a simple rainy‑night story and turned it into concrete functional and non‑functional requirements for a ride sharing backend. By walking through Alice and Bob’s journeys, it identified what the system must do for riders and drivers, what kinds of scale and reliability it must handle, and how a trip’s life can be modeled as a clear state machine. The logical capability map sketched out the main areas—trips, matching, pricing, payments, location, notifications—that will become separate components in the architecture. In the next article, these requirements and capabilities will be turned into a high‑level system architecture for a single Uber ride, with layers, services, and data flows that show how everything works together in an uber system design



