Ok, so this is less of a "how to" lesson and more of a "how do I?" conversation. I'm sure we've all run into this kind of problem before. You need to show some info-box or some widget to a user; and, when the user closes it, you (and your web application) need to remember that "this" user closed "that" info-box such that you don't show the same info to the same user again. Often times, once the user closes the info-box, that [flag] data has no real future value; and that makes me angry because I have to store it. It makes me wish that I had a better strategy for storing that data. So, I wanted to brainstorm some possible approaches.
Context: You need to store some "hasSeenIntroVideo" flag for each user.
Storing Additional Data In A Non-Expiring Cookie
This is probably the first kind of approach that I ever went with. Need to store a conditional user flag? Throw it in a cookie and forget about it. This is actually a really nice approach, to some degree, because it requires very little change in your application logic. No database changes; no data access changes; just a simple cookie check.
The problem with using cookies is that they cannot be relied upon. The user can clear them. The user can jump on a different machine. The user can enter "Incognito" mode in the browser. The user can run out of cookie space (theoretically). When you rely on cookies, it's actually quite easy to show a user some information that they've already seen.
Adding Additional Columns To Your User Table
Once I realized that the cookie approach doesn't work well enough, the next lowest-hanging fruit option is to simply tack on the needed Boolean column in the user database table. The first time you do this in your application, it feels relatively painless. Sure, you have to update the database schema and the data-access layer; but, it's not that much code to touch.
The pain starts to set in when you add more columns over a longer period of time. At some point, it may not even be a simple ALTER statement - at some point, you may not be able to "lock" the table up while adding the new column. When this happens, you have to start building "shadow" tables with the new schema. This is a lot of work.
And, as the work of adding a new column increases, the emotional strain of storing "useless" data starts to set in. You mean it's gonna take me five hours to implement a stupid flag so that the Product team can show a Happy Holidays modal to the user? Come on!
Adding A Hash Column To Your User Table
While this approach worked, it never sat right with me, philosophically; I feel like it corrupted the concept of "relational" database schemas. Philosophy aside, this approach also requires more code because you now have to serialize and deserialize the hash as it moves into and out of the database. Also, you can't [easily] query the database table based on various flags stored within the hash.
Treating Transient Data As First-Class Citizens
The next thing I want to try, though I haven't actually done this yet, is to promote these transient bits of data into actual first-class citizens. By that, I mean that I want to think of them as holistic units of information rather than as "attributes" of something else. So, instead of tacking on a "hasSeenIntroVideo" column onto the "user" table, I'd like to create a separate "intro_video_viewing" table that has a schema like:
- userID (PKey)
- durationInSeconds (tinyint)
- viewedAt (date/time)
Now, instead of setting a column value in the "user" table, I'll actually insert a new record into the "intro_video_viewing" table. Do I really need the last two columns? Probably not. But, adding them helps me transcend the "column" mental model and start seeing this transient data as something more full-bodied and robust.
Of course, this probably requires more code than any of the other approaches as this new model needs to be pulled through every layer of the application. That said, the emotional payoff is that I can now keep my "user" table in a much more clean, more consistent state. And, in time, as this information becomes irrelevant, I can simply DROP the table (and remove the corresponding code).
What About "Useless" Data That Can Never Be Forgotten?
The problem with all of these approaches, is that some data can never be forgotten. And yet, at the same time, it feels like it holds no value. "Intro" and "tour" data is a perfect example of this. Even after a user has been in your system for months or years, you still have to remember to NOT show them the intro video. This means that the "has seen" data need to be persisted. This is super lame and makes me sad.
Perhaps the best approach, and likely the most complicated, is to use the transient data in conjunction with the user data to conditionally query the database. For example, only worry about showing the "intro video" if the user signed up in the last 7 days. And, if the user has been around for more than 7 days, don't bother even checking. This way, the transient data table can be pruned without providing the user with a redundant experience.
Anyway, just some thoughts on the matter. If anyone has any thoughts or advice on the topic, I would love to hear it.