As I was building SmashVODs.tv, I thought it would be a great idea to add commenting to clips and tournament VODs. What’s a great commenting system? I really enjoy Reddit’s nested comments. So I set out to build it for SmashVODs.
Here are the requirements for a Reddit-style commenting system:
- Recursive parent-child comment relationship and terminal condition for scalability
- Comment upvotes
- Efficient comment fetching
- UI to upvote a comment / post a root comment / post a nested comment
- UI to show a single comment thread (i.e. render a comment as if it’s the root comment) / navigate up the comment tree
I set out to implement this system with these requirements without knowing how long it’d take. With a lot of thinking, mashing at the keyboard, and anti-social juice, I managed to build out a fully functioning system in one weekend. You can play around with it here.
1. Recursive parent-child comment relationship and terminal condition for scalability
It was easy to use a relational database (I used Postgres) and Ruby on Rails’s ORM to implement the recursive parent-child comment relationship. Every user had comments, a comment had a reference id to a parent comment. This reference id was nil if it’s a root comment.
I spent some time thinking about the terminal condition for the recursion. Should it be infinitely nestable? Should I stop the recursion after a set number of nests? Infinite nestability is cool but there are difficult comment fetching and UI edge cases when the nesting gets extreme that I didn’t want to design and implement.
I ended up settling with a maximum of 5 nested comments per root comment thread. This felt like a sufficient amount of allowance for nesting that it wouldn’t be a bad user experience, while minimizing the technical effort to implement.
2. Comment upvotes
This was straightforward to implement. Upvotes belonged to a user and a comment. The rest is setting up APIs, data plumbing, and UI design and implementation.
3. Efficient comment fetching
I spent the most time thinking about how to implement efficient comment fetching. Ideally, you’d want to show the most popular comments first, not return too many comments, and allow the user to show more comments if there are more.
With linear data sets, pagination works really well to make sure you don’t return too many comments. With nested comments, this becomes super tricky. I tried to figure out how Reddit handled this. With large comment threads, some nested comments would be truncated with a link like “6 more replies” and this truncation happened across multiple levels. I couldn’t figure out what heuristic Reddit used to determine when to truncate.
I also spent a long time thinking about how to fetch a comment tree efficiently without recursion.
After much deliberation, I realized that I was spending too much time designing the comment fetching logic when it should start off simple. The system was guaranteed to have low usage to start and if I needed to solve scaling when more people are using it, that’s a good problem to have!
I ended up implementing a naive recursive algorithm to fetch all comments for a comment thread. I returned the entire set of comments on page load. This was straightforward to implement and worked really well. To reduce potentially long pageloads, I fetched a page’s comments only after the rest of the page has loaded. The comment section was mostly below the fold and this had minimal effects on user experience.
4. UI to upvote a comment / post a root comment / post a nested comment
Two difficult problems to solve with implementing a UI.
The first is designing the UI. I’m bad at design and mediocre with CSS (I worship on the altar of
display: flex). To fast track design, I took heavy inspiration from the design of Reddit’s comment threads.
The second problem is architecting the frontend such that users can upvote comments, post root comments, and post nested comments without the code resembling an Italian pasta shop. There were many components to reuse, states to handle, and data pathways to set up and this required careful planning.
In the end, I was able to architect something that I was comfortable with, and implement it with minimal debugging.
5. UI to show a single comment thread (i.e. render a comment as if it’s the root comment) / navigate up the comment tree
This could be considered a nice-to-have feature but my completionist drive took a hold of me and I wanted to make it possible to expand into comment threads and show nested comments as root comments, similar to how Reddit does it. It turns out, this was mostly a matter of UI design as it only involved a minor tweak to the comment fetching logic in the backend.
Bonus points: SoundCloud-style comments for videos
I spent the first weekend building requirements 1-5 and tackled this afterwards. The trickiest aspect of this feature is rendering comment markers in a timeline under the video in a manageable way.
Here are the requirements for timestamped commments and a video comment timeline:
- Users can choose to attach a timestamp to a comment based on the video’s current time
- Readers can see that a comment has an attached timestamp, and quickly navigate to that point in the video
- Comment markers on the video comment timeline cannot overlap, even if there are many markers in a small location. This constraint should dynamically hold even as users change the size of the browser
- Users can quickly display all comments at a particular point in time
Requirement 3 proved to be the hardest to design and implement. I spent hours thinking about the best way to do this such that the edge cases are handled, e.g. if a user increases or decreases the browser’s width.
I ended up deciding to batch comments and partitioning the video timeline into 20 fixed increments. Each batch of comments would thus be part of 4% of the video’s length. If a 4% video segment had more than one comment, I rendered a marker with the comment count on it. A user could view comments in this video segment by clicking on this marker, which causes a special comment view to be displayed such that only root comments within this 4% video segment are shown.
This solution elegantly solves two key problems. Because the comment markers are batched and shown at predictable non-overlapping points in the timeline, the overlapping comment marker issue is solved. By choosing a 4% increment, I can simply use a 4% CSS width for each comment marker which ensures that comment markers elegantly adjust spacing between each other, even as users change the size of the browser.
The commenting system initially felt daunting to build given all the complex pieces that needed to be combined together. Breaking the problem down into component parts and articulating clear requirements made it easy to manage. The best part about building this is that I can reuse the system across many different side projects which widens the type of website I can build and increases my efficiency in experimentation.