In a productivity app I’m currently working on I wanted to incorporate the idea of a streak feature.
Streaks are nothing new in the world of productivity. Famously popularized by Jerry Seinfeld’s productivity secret.
In Mr. Seinfeld’s case, he used a calendar to mark each day he sat down to write. Eventually the marks create a chain and keeping the chain going (or not breaking the chain) was pressure enough for him to sit down and write every day.
I’ve iterated a few times on my solution for streaks in my app. And before I share where I landed I wanted to work a little backwards.
What I mean by this is there are multiple ways to implementing a streak. The most common one as seen in apps like Snapchat, is to award users with an unbroken streak as long as they interact with the application in some way every 24 hours.
And so before sharing my solution, I’d like to challenge you. If you’re reading this and also implementing a streak, first think about what you would like the people using your application to do on a regular basis in order to keep the streak going.
Once you’ve determined that, I also challenge you to think about both the positive and negative effects of the streak. While a streak is motivating is it your intention to have them show up to your application for the sake of keeping the streak going?
My first iteration of the streak in the system was pretty straightforward, determine whether the person had completed a task within the past 24 hours. If they did, then keep their streak going.
But then as I was participating in the streak function—while motivating—I noticed something that didn’t fit my life style. My weekends are less regimented. I enjoy spending time with my wife and kids and often times that means time away from my computer.
While this fits my use case, I think it will also have benefits for others as well that aren’t like me. While I’m definitely for productivity, I’m also strongly for a healthy mental well-being. For this reason my next iteration will likely have the ability to set up a schedule to not count against the streak. Like a pause button. To allow for more mindful productivity.
Implementing a pause is still aspirational at the time of writing this article, but I thought I’d share my solution.
The models
In my application there are two models which work together to achieve the streak.
The user
model which is used to represent a person using the application and then a task
model used to represent tasks.
The user
model contains three specific fields that are used for the streak function. Those fields are streak
, last_streak
, streak_updated_at
.
The streak
field is a numerical field that is used to keep track of the active streak.
The last_streak
is used to keep track of the last streak. If there is only a single streak, then the streak
and last_streak
are the same. The reason I have two fields is that if for some reason a user had lost their streak, I want a way to recover their hard earned streak for them.
The streak_updated_at
field is a timestamp field which gets updated when the streak gets updated. This is then used to determine whether the person has completed a task within the past 24 hours.
The task
model contains two fields which are used for the streak function. Those fields are completed_at
and streaked
.
The completed_at
is a timestamp which updates the moment a person marks a task as completed.
While the streaked
field is a boolean which also gets updated the moment a person marks a task as completed but only the first time. By default this field is set to false
. But when completed, it gets marked as true
. I did this because sometimes you mark a task as completed but it might not be true. I also didn’t want a person to game the app, so streaked
acts as a way to determine if a task has already been accounted for towards a streak.
The logic
When a person marks a task as complete for the first time, the application will determine if the last task was completed within 24 hours by checking the streak_updated_at
task of the user
model. If it is within the 24 hours, then the streak
and last_streak
increases.
The task also then gets marked as streaked
by having this field marked as true
. With the completed_at
set to the current timestamp.
When a person marks a task that has been marked streaked
to true
then the application will just update the task
’s completed_at
with the current timestamp but the streak won’t be updated.
How is 24 hours determined?
The last piece to the streak is that every person using the application has a common time to complete a task. That time is coordinated universal time (UTC) a time is commonly known amongst computer servers.
When a task is completed, the application checks to make sure that it is completed in the current UTC day. Then it checks to make sure the streak_updated_at
time was completed within the last UTC day. If both criteria are met, then the streak is incremented.
Conclusion
The purpose of this article wasn’t to provide a streak solution in a particular programming language but it was more as a strategy based around rules for what the streak should enforce.
I hope with what I’ve shared it’ll give you ideas on how you can implement your own streak feature in an application you might be involved in.