SHIRA ABRAMOVICH

Skip to blurb Skip to contact

Designing infrastructure for following and blocking

Linoleum cut print depicting a laptop with several open, overlapping windows

Introduction

After I wrote up a Trust and Safety plan for Studio, our first project was implementing a new social feature and a safety feature at the same time.

I was tasked with writing the RFC for the data model for user following relationships, as well as user blocking relationships!

The spec

Users should be able to follow any other user, as long as these requirements are met:

  • The target (followee) hasn’t blocked the source user;
  • The source (follower) hasn’t blocked the target user.

In other words, blocks and follows are relationships that are directional, but mutually exclusive. In other words, it’s perfectly possible for two users to follow each other, or for two users to block each other, but follows and blocks between two users cannot coexist. Here’s a demo of the final feature.

Demo of final following and blocking feature.

The tradeoffs

Database technology

We’ve been using both SQL and NoSQL solutions in our code recently, with a consensus among engineers to use SQL wherever possible.

I considered storing blocks and follows in each technology. Here’s how that could play out, using best practices for each technology:

  1. NoSQL: store follow/block relationships within the same document as other user info, since NoSQL databases are not optimized for JOINs.
  1. SQL: store follow/block relationships as individual rows within a database, then cross-reference that with other tables in order to enrich with user information.

Given the relational nature of the data, I decided that a SQL-based solution would be best, since it allows us to store the relationships separately, rather than querying a larger, potentially unstructured user table (since many noSQL technologies don’t provide automatic validation).

How many tables?

Now that I’d decided to store these new relationships in SQL, the question came up: should these relationships be stored in one database or two?

Here’s the technical dilemma:

  • in one database of user relationships, we can enforce follow/block uniqueness at the database level, by implementing a uniqueness constraint on source and target users. This is very attractive, since SQL promises us uniqueness and is very well-tested on this front, and we’d eliminate the need for one-to-one JOINs (which are not terribly efficient).
  • in two databases, we enforce follow/block uniqueness at the data access level, by checking both tables on follow and block creation attempts. This includes calls to two different databases.

Framed this way, one database seems quite attractive. However, there’s another, product-based dilemma here: which is more futureproof?

The answer is, most likely, two databases. We’re not sure this is exactly the structure of user relationships that will extend into the future. What if we change “follows” to “friends”? Or what if we add another kind of relationship? Our one-database solution doesn’t seem as futureproof anymore.

As a result, I decided to implement the feature using two tables, two direct DAOs, and one SDK, which in turn is called by the server API. This way, we always check both databases before doing any follow or block manipulation, but we are free to add or remove user relationships in the future.

Conclusion

Writing up this RFC was a lot of fun, complete with classic Alice-and-Bob examples. Now that the feature is complete and has its frontend components set up, I’m so excited to see how users interact in a more social (following-inclusive)—and more protected (blocking-inclusive)—environment.

Contact:

Resume available upon request.