Skip to content

Instantly share code, notes, and snippets.

@tingwei628
Last active April 1, 2025 06:09
Show Gist options
  • Save tingwei628/fb3161ba91ea8bbbeedafb4e572ccd69 to your computer and use it in GitHub Desktop.
Save tingwei628/fb3161ba91ea8bbbeedafb4e572ccd69 to your computer and use it in GitHub Desktop.
system design - Twitter
/*
System Design - Twitter
1. User Registration
- Users can register with a unique username.
- Duplicate usernames are not allowed.
2. Follow & Unfollow
- Users can follow/unfollow others to control their feed.
3. Posting Tweets
- Tweets must be at least 200 characters.
- Each tweet has a unique ID, timestamp, and content.
4. Fetching Feeds
- Shows tweets from followed users, sorted by time (latest first).
- Only past tweets are displayed (no future timestamps).
- Limited to the 20 most recent tweets.
5. Testing
- Verify registration, follow/unfollow, and tweet validation.
- Ensure correct feed behavior and tweet filtering.
*/
//====================== Test Cases ==========================================
using System;
using System.Collections.Generic;
using System.Linq;
// Test 1: User Registration
Console.WriteLine("Test 1: User Registration");
User user1 = new("Alice");
User user2 = new("Bob");
DB.users.Add(user1);
DB.users.Add(user2);
Console.WriteLine(DB.users.Count == 2 ? "PASS" : "FAIL");
// Test 2: Duplicate Registration
Console.WriteLine("Test 2: Duplicate Registration");
Console.WriteLine(user1.Register("Alice") == false ? "PASS" : "FAIL");
// Test 3: Follow & Unfollow
Console.WriteLine("Test 3: Follow & Unfollow");
user1.Follow("Bob");
Console.WriteLine(user1.Followings.Contains("Bob") ? "PASS" : "FAIL");
user1.UnFollow("Bob");
Console.WriteLine(user1.Followings.Contains("Bob") == false ? "PASS" : "FAIL");
// Test 4: Post Tweet
Console.WriteLine("Test 4: Post Tweet");
bool success = user1.Post("This is a short tweet."); // Should fail (length < 200)
Console.WriteLine(success == false ? "PASS" : "FAIL");
success = user1.Post(new string('A', 201)); // Should succeed (length > 200)
Console.WriteLine(success == true ? "PASS" : "FAIL");
// Test 5: Get Feeds (No Following)
Console.WriteLine("Test 5: Get Feeds (No Following)");
var feeds = user1.GetFeeds();
Console.WriteLine(!feeds.Any() ? "PASS" : "FAIL");
// Test 6: Get Feeds (With Following)
Console.WriteLine("Test 6: Get Feeds (With Following)");
user1.Follow("Bob");
user2.Post(new string('B', 201)); // Bob posts a tweet
var feeds2 = user1.GetFeeds();
Console.WriteLine(feeds2.Any() ? "PASS" : "FAIL");
// Test 7: Unfollow and check feeds
Console.WriteLine("Test 7: Unfollow and check feeds");
user1.UnFollow("Bob");
var feeds3 = user1.GetFeeds();
Console.WriteLine(!feeds3.Any() ? "PASS" : "FAIL");
// Test 8: Multiple users posting and fetching feeds
Console.WriteLine("Test 8: Multiple users posting and fetching feeds");
User user3 = new("Charlie");
DB.users.Add(user3);
user1.Follow("Bob");
user1.Follow("Charlie");
user3.Post(new string('C', 201));
var feeds4 = user1.GetFeeds();
Console.WriteLine(feeds4.Count() == 2 ? "PASS" : "FAIL");
// Test 9: Posting multiple tweets and retrieving latest 20
Console.WriteLine("Test 9: Posting multiple tweets and retrieving latest 20");
for (int i = 0; i < 25; i++)
{
user2.Post(new string('D', 201));
}
var feeds5 = user1.GetFeeds();
Console.WriteLine(feeds5.Count() == 20 ? "PASS" : "FAIL");
// Test 10: Ensure only past tweets are shown
Console.WriteLine("Test 10: Ensure only past tweets are shown");
user3.tweets.Add(Guid.NewGuid().ToString(), (DateTime.Now.AddMinutes(10), "Future tweet"));
var feeds6 = user1.GetFeeds();
Console.WriteLine(!feeds6.Contains("Future tweet") ? "PASS" : "FAIL");
Console.WriteLine("All tests completed.");
//====================== Code ==========================================
static class DB
{
public static List<User> users = [];
}
public class User
{
public string UserName { get; set; }
public User(string userName)
{
UserName = userName;
}
public HashSet<string> Followings = [];
public Dictionary<string, (DateTime, string)> tweets = [];
public bool Register(string userName)
{
if (DB.users.Any(x => x.UserName == userName)) return false;
DB.users.Add(new User(userName));
return true;
}
public void Follow(string userName)
{
Followings.Add(userName);
}
public void UnFollow(string userName)
{
Followings.Remove(userName);
}
public bool Post(string tweet)
{
if (string.IsNullOrWhiteSpace(tweet) || tweet.Length < 200) return false;
string tweetId = Guid.NewGuid().ToString();
DateTime tweetDate = new();
tweets.Add(tweetId, (tweetDate, tweet));
return true;
}
public IEnumerable<string> GetFeeds()
{
if (Followings.Any() == false) return [];
var followings = DB.users.Where(x => Followings.Any(y => y == x.UserName));
var latestTweets = followings.SelectMany(x => x.tweets)
.Where(x => x.Value.Item1 <= DateTime.Now)
.OrderByDescending(x => x.Value.Item1)
.Take(20)
.Select(x => x.Value.Item2);
return latestTweets;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment