Social Network
Post something, and everyone who follows you should see it without refreshing into a full table scan. The whole design question is: who does the work of getting a post into a follower's feed, and when? Doing it at read time is simple and slow; doing it at write time is the interesting part.
Requirements
Functional
- A user follows or unfollows another user.
- A user publishes a text post, visible to their followers.
- Each user has a feed: posts from people they follow, newest first.
- A follower is notified the moment someone they follow publishes.
Non-functional
- Reading a feed must not require scanning every post ever made by every followed user - the fan-out work happens once, at publish time, not on every read.
- Adding a new way to be notified (push, email, in-app banner) must not require changing
UserorPost.
Design
Post doesn't know who its followers are and User doesn't loop over anyone else's data to
build a feed - publishing a post notifies a list of subscribed observers, and each observer
decides what to do with the news. That's Observer doing the one thing it's actually good
for: decoupling "something happened" from "here's what happens next."
- 1The author only ever talks to the network facade, never to a follower directly.
- 2A post is created once and handed its author’s current follower list.
- 3Publishing is the post’s own job - it owns the notify step, not the network.
- 4Every follower’s Feed is an observer; the post has no idea Feed exists beyond this interface.
- 5The feed prepends the post and trims itself to its cap - nobody outside Feed manages its size.
Feed is one such observer: it just prepends the post to a capped list. A push-notification
service could be a second observer on the exact same publish call, with zero changes to
SocialNetwork or Post.
Class diagram
Code
Design decisions
- Fan-out happens on write, not on read.
SocialNetwork.publishpushes the new post into every follower'sFeedimmediately. Building a feed at read time by merging every followed user's post history would be simpler to write and unusable at any real follower count - this is the classic push-vs-pull tradeoff, and this page takes the side that keeps reads cheap. - Notification is Observer, not a hardcoded call to
Feed.prepend.Post.publishnotifies a list ofFeedObservers;Feedhappens to be the only implementation here, but a second observer (an email digest, a push notification) plugs in at the same call site with no change toUser,Post, orSocialNetwork. Feedcaps its own size instead of trusting callers to trim it. A feed that grows forever turns "prepend a post" into a slow operation years into a user's life; keeping the cap insideFeed.receivemeans every caller gets the same guarantee for free.- Follow/unfollow is a set operation on
User, not aFriendshipjoin object. A follow here is one-directional and has no state of its own (no pending/accepted), so a plainSet<User>of followers is the whole model - introducing a relationship class would be structure with nothing to hold. - What's missing for a real system: ranking (chronological only here, no relevance
scoring), pagination past the in-memory cap, and de-duplicating a post that reaches a user
through more than one path (retweets/shares) are all real feed-system concerns that don't
change the observer wiring above - they'd sit inside
Feed.receive, not around it.