Lets assume we are building this application with a lifespan of 10 years and we have around 100 locations for this app
current weather info 7/times a week, with an update every hour
datetime: 8 bytes
weather type(sunny, rain, cloudy etc): 10 bytes
precipitation(mm): 3 bytes
pressure: 4 bytes
wind speed: 3 bytes
longitude: 10 bytes
latitude: 10 bytes
((8+10+3+4+3+10+10)*24)*365= 420480 bytes/yr
forecast info: 7 days rolling forecast, update daily
datetime: 8 bytes
weather type(sunny, rain, cloudy etc): 10 bytes
precipitation(mm): 3 bytes
pressure: 4 bytes
wind speed: 3 bytes
location: 20 bytes
temperature: 3 bytes
(8+10+3+4+3+20+3) * 7 * 52= 18564 bytes/yr
user settings: updated rarely, assume its only set once
city_id(s): 10-100 bytes (can set up to 10 cities)
longitude: 10 bytes
latitude: 10 bytes
notification type: 10 bytes
notification frequency: 10 bytes
temperature_id: 1 byte
(100+10+10+10+1) = 141 bytes total
historical data: updated weekly via analytics service
city_id: 10 bytes
longitude: 10 bytes
latitude: 10 bytes
avg_temp: 3 bytes
avg_pressure: 4 bytes
avg_wind_speed: 3 bytes
avg_weather_type: 10 bytes
avg_precipitation: 3 bytes
(10+10+10+3+4+3+10+3) * 52 = 2756 bytes
(141 + ((420480 + 18564 + 2756) * 10)) * 100 = 0.44 GB over 10 years and 100 locations
fetchWeatherData(longitude,latitude,city_id) -> Fetch weather data based on current location (or an input city) from a government or third party weather api
fetchClosestCity(longitude,latitude) -> find the closest city to a user's coordinate to display weather data for
updateSettings(temp_type,notification_type,notification_frequency,home_city, device_uuid)-> Allow a user to set preferences unique to their device by using their device uuid. A user can set temperature type (celcius or farenheit), cities they want to monitor (up to 10 cities for the time being) and notification settings
generateHistoricalData(longitude,latitude,city_id, date)-> generate analytical data (avg temp, pressure, etc) based on a user's current location or a city of their choosing. This will be generated once a month for all cities.
generateHistoricalVisuals(longitude,latitude,city_id) -> Output historical data as well as populate several visuals such as graphs based on all data collected up until the current month for a user's location or input city_id2
convertUnits(user_id) -> will save a user's settings to display units in imperial (Fahrenheit, in, etc) or metric
sendEmergencyNotification(region,city_id,notificationMessage) -> will send an emergency notification to all users in the affected region and will further pinpoint affected users by the affected cities
sendScheduledNotification(user_id,city_id)
currentWeatherInfo{
city_id: string
datetime: datetime
weather type(sunny, rain, cloudy etc): string
precipitation(mm): float,
pressure: float,
wind speed: float
}
forecastInfo{
datetime: datetime
weather type(sunny, rain, cloudy etc): 10 bytes
precipitation(mm): 3 bytes
pressure: 4 bytes
wind speed: 3 bytes
location: 20 bytes
temperature: 3 bytes
}
WeatherCount {
city_id: string,
dataCollectionStartDate: datetime,
lastUpdatedDate: datetime,
avg_weather_type: string
sunny: int,
overcast: int,
rainy: int,
snow: int,
cloudy: int,
}
We can denormalize weatherCount and historicalData since they have the same primary keys. This helps with speeding up get requests.
historicalData{
city_id: string,
dataCollectionStartDate: datetime,
lastUpdatedDate: datetime,
avg_temp: float,
avg_pressure: float,
avg_wind_speed: float,
avg_weather_type: WeatherType[]
avg_precipitation: 3 bytes,
}
City {
city_id: string,
users: User[]
}
User {
user_id: string,
device_id: string,
region:int,
home_city_id: string,
saved_cities: city_id[],
imperial: int,
last_known_longitude: float,
last_known_latitude: float,
notification_schedule: int,
notification_type:string,
}
Notification:{
user_id: string,
message: string,
city_id: string
}
Region{
users:User[],
region_id: int,
}
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...
generateHistoricalData -> This component can initially be pre loaded with data from some existing online api. This ensures the cost is limited to one time and from there on we can update it with our own data. Doing so allows us to collect data according to how we design the database and allows us to be consistent with the data structure for historical data.
Cache layer -> We can implement a cache layer which will save weather data for a certain number of cities that may be accessing data very frequently (large cities like Toronto, or new york etc). We can make use of a least recently used cache which is different for each geographical region in order to significantly cut down on get requests to the database.
I decided to trade off implementing a sign in system for this application since I don't foresee many settings a user would want unique to their app. Most changes can be made instantly such as changing the temperature units or saving multiple cities. The only way that their settings may be lost is if they lose their device or get a new device they want to also download the app on. We can utilized their device UUID or browser information to save their settings for them.
I chose to use a relational database like MySQL since this application deals with analytical data as well as prioritizing data consistency and availability