Habit-tracking apps (Streaks, Productive, Habitify, Atomic Habits-inspired apps) are simple-looking but reveal interesting system design questions: streak calculation, time-zone sensitivity, smart reminders, and offline-first sync. The interview tests whether you understand the surprising depth of “just check off a box.”
Functional requirements
- Define habits with frequency (daily, weekly, custom) — store the frequency as a structured rule (“3x per week” versus “Mon/Wed/Fri”), not free text, because streak math and reminder scheduling both read from it.
- Mark complete with one tap — the completion write has to succeed instantly and locally; treat the tap as the primary action and make it work offline with no spinner.
- Streak tracking — compute the streak from the completion history rather than storing a running counter, so back-filled or edited entries recompute correctly.
- Reminders at user-chosen times — schedule these on-device as local notifications; a simple time-based reminder rarely needs a server round-trip.
- Visualization (calendar, charts) — interviewers expect a “don’t break the chain” calendar and a completion-rate chart; keep a denormalized read model so these render without scanning the raw log.
- Sync across devices — state the consistency target up front: habits and completions sync eventually, and the UI stays usable while a sync is still pending.
The streak calculation
Surprisingly subtle:
- What counts as “today” — the user’s local time, not server UTC
- What if the user travels across time zones? Did Tuesday repeat?
- What if the user marks a habit complete at 2am? Is it for today or yesterday?
- What about Daylight Saving Time?
Standard solution: track completions as date-time-zone tuples. Compute streaks based on local “day” boundaries. Handle DST as a 23 or 25-hour day.
Custom frequencies
Habits beyond daily:
- Three times a week (no specific days) — the streak unit is the week, not the day, so a miss happens only when the week ends below three completions; don’t reset just because Tuesday was skipped.
- Mondays only — every non-Monday is irrelevant, and a miss is a Monday with no completion; interviewers check whether you correctly ignore the other six days.
- Every other day — track the last completion date and test whether the gap exceeds two days; a fixed weekday grid breaks the moment the user shifts by one day.
- Once a month — the window is the calendar month, so a single completion anywhere in July satisfies July; decide up front whether “month” means the calendar month or a rolling 30 days.
Streak math gets complex. Define “miss” precisely for each frequency type.
Reminders
Local notifications via UNUserNotificationCenter (iOS) or AlarmManager (Android). Constraints:
- iOS limits to 64 pending notifications — you can’t pre-schedule a year of reminders per habit, so schedule a rolling window (the next few occurrences) and refill it each time the app runs.
- Android allows more but exact alarms need permission — on Android 12+ exact alarms require the SCHEDULE_EXACT_ALARM permission, so have an inexact-alarm fallback for users who deny it.
- Handle time-zone changes — re-schedule when device time zone changes: listen for the system time-zone-change broadcast and reschedule, or an 8am reminder fires at the wrong local time after the user flies across zones.
Smart reminders
Beyond “remind me at 8am”:
- Reminder fires only if not yet completed — check completion state at fire time (or cancel on completion) so the user isn’t nagged about something already done.
- Reminder cancels if user opens the app and marks complete — cancel the pending notification the moment the completion is written locally.
- Snooze 15/30/60 minutes — implement snooze as scheduling a fresh local notification, since there is no built-in OS snooze to lean on.
- Adaptive: learn when the user typically completes — shift the reminder toward the user’s historical completion time; a rolling average of past completion times is enough, and it’s more defensible in an interview than promising an ML model you can’t scope.
Offline-first sync
Common case: user marks complete on phone offline. Sync later. Strategies:
- Local SQLite as source of truth
- Operations log (mark complete, undo, edit) synced to server
- Server merges via last-write-wins per (habit, date) pair
- Conflict resolution: client tracks timestamps with HLC for clock-skew tolerance
Multi-device sync
If the user has phone + tablet, both should reflect the same data:
- Server is source of truth for cross-device state
- Push notifications signal “data changed; refresh”
- Pull on app foreground
Apple Watch / Wear OS companion
Glanceable habits, one-tap completion. Sync via WatchConnectivity or Wearable Data Layer.
Gamification
Common features:
- Streak counters — surface both current and longest streak, and derive them from history so a corrected past entry immediately updates the numbers.
- “Don’t break the chain” calendar visualization — the Seinfeld-style grid of filled days is the single most motivating view, so it usually belongs on the home screen.
- Achievements / badges — milestone rewards like 7-day and 30-day marks; keep them cheap by computing them from stats you already track.
- Stats: longest streak, completion rate, total completions — precompute these per habit on each write so the stats screen never has to scan the full completion log.
Be careful — gamification can backfire (users obsess over streaks at expense of habit’s real benefit).
Battery and data
Minimal. Habit apps are check-and-leave; no always-on processing. Data: tiny.
Frequently Asked Questions
How do I handle a user who legitimately could not do a habit (sick, traveling)?
Many apps offer “skip days.” The streak is preserved. Without this, perfectionism kills habits.
What if the user wants to track “did not do this” (e.g., quitting smoking)?
Same data model, opposite framing. Some apps support both kinds explicitly.
How accurate are streaks across time zones?
Most apps store date-tagged completions. Streak math is local-time dependent. Edge cases (international travel during a Tuesday) confuse most apps; well-engineered ones use UTC + zone snapshots.
Keep sharpening your system design:
