Define the APIs expected from the system. This is your chance to analyze and define the read and write paths so that you can come up with the high-level design...
POST /activities
body: {
dateTime: string;
weight: number;
hoursOfSleep: number;
heartRate: number;
// ... any other numeric health metric
}
response: 204 no content status
GET /activities?minDate={minDate}&maxDate={maxDate}&page={pageNum}&pageSize={pageSize}
response: {
dateTime: string;
weight: number;
hoursOfSleep: number;
heartRate: number;
// ... any other numeric health metric
}[]
GET /stats-summary?minDate={minDate}&maxDate={maxDate}
response: {
overallSummary: string;
weightHistory: number[];
hoursOfSleepHistory: number[];
heartRateHistory: number[];
// ... any other collections of other numeric health metrics
}[]
POST /sync
body: {
deviceId?: string;
accountId?: string;
}
response: 204 no content status
Describe the overall system architecture. Identify the main components needed to solve the problem end-to-end. Use the diagramming tool to create a block diagram.
Services needed:
Deep dive into 2-3 key components. Explain how they work, how they scale, discuss tradeoffs, capacity, and any relevant algorithms or data structures.
A good portion of users may typically exercise in locations where there is no internet access (ex: gym basements, forests, mountains, etc.). Because of this, we need a mechanism to track an offline workout and sync it back to the backend once the user comes back online.
First, we need a mechanism to detect whether the client device is online or not. This can easily done using a client-side API or library that allows the front end to subscribe to network changes.
When the FE detects an offline network, the app will first write to a local database (e.g. SQLite), writing to the device local storage. When the app detects online connectivity again, it can initiate the online syncing process.
To ensure a reliable process, we need to ensure that the sync writes do not create duplicates so that all data is accurate in the user's account. To do this, we need to ensure idempotency. One way to do this whilst offline is to create a unique SQL constraint on the local DB on the timestamp of the logged activity to ensure no misfires from the client device are registered within a timeframe. We can also create an idempotency key in a similar way when we sync back online using only unique segments of time that pass.
To handle offline syncing data spikes, we can utilize the rate limiter to only allow each client's account to upload data at a certain maximum allowable rate (e.g. 50 MB per minute), ensuring our services don't get overwhelmed.
Instead of sending a contiguous stream of coordinate points to log routes from GPS tracking capabilities, we can utilize polyline encoding to efficiently transmit and store data.
Polyline encoding can be done by a series of mathematical operations that are inexpensive to do by the client. We can do operations such as removing decimal points, finding the differences between each points (smaller numbers), and encoding those numbers into a string representation and using bit manipulation to decode the route information.
This way, polyline encoding can speed up the syncing process, reduce storage dramatically to allow us to save on DB costs when scaling our user base, and reduce network bandwidth consumed by our endpoints and client devices, which is essentially important to consider if our app is to support hundreds of millions of DAUs.