Design article voting and flip-tracking system
Company: Rippling
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Technical Screen
Design an object-oriented "Article System" that supports voting and query operations.
You need to design the data model and core APIs (including method signatures and internal logic, but not full code) for an in-memory service that manages articles and user votes.
The system should provide **at least** the following methods:
```python
def add_article(article_name) -> article_id
```
- Create a new article with the given name.
- Return a unique `article_id` for the newly created article.
```python
def up_vote_article(article_id, user_id) -> None
```
- Register an **upvote** from `user_id` on `article_id`.
- A user can vote on the same article multiple times, but at any moment their effective vote on that article should be one of: upvote, downvote, or no vote.
- If the user previously **downvoted** this article and now upvotes it, this should count as a **flip** (change of opinion) for that article by this user.
```python
def down_vote_article(article_id, user_id) -> None
```
- Register a **downvote** from `user_id` on `article_id`.
- Similar rules as `up_vote_article`: a user's effective vote on an article is unique at any time.
- If the user previously **upvoted** this article and now downvotes it, this should count as a **flip**.
```python
def get_most_recent_3_flip_article(user_id) -> List[article_id]
```
- For the given `user_id`, return the **3 most recent articles** on which this user has **changed their mind** (flipped from upvote to downvote or from downvote to upvote).
- "Recent" is defined by the time when the flip happened.
- You may clarify and assume one of the following (state your choice):
- Either return the 3 most recent **flip events** (allowing the same article to appear multiple times if the user flipped multiple times), or
- Return up to 3 **distinct article IDs**, ordered by the most recent flip time per article.
```python
def get_top_k(k: int) -> List[article_id]
```
- Each article has a **score** defined as: `score = (#upvotes) - (#downvotes)`.
- Return the `k` articles with the highest scores, ordered from highest score to lower.
- If scores tie, you may pick any consistent tie-breaker (e.g., article ID).
### Requirements & Assumptions
1. **Correctness semantics**
- A user can at most have one effective vote per article at a time: up (+1), down (-1), or no vote (0).
- Multiple calls from the same user on the same article should update the effective vote and, where applicable, create flip events.
- You should track the time at which flips happen so you can answer `get_most_recent_3_flip_article` accurately.
2. **Design focus**
- Focus on **class design**, key data structures, and how each method operates.
- Describe how you would store:
- Articles and their current scores.
- Each user's current vote per article.
- Flip history used for the recent-3-flips query.
- Consider reasonable time and space complexity for each API.
3. **Constraints**
- You may assume a single-process in-memory implementation (no need for distributed systems) but should mention any concurrency or thread-safety concerns.
- You do **not** need to persist data across restarts.
Describe:
- The main classes and their responsibilities (e.g., `Article`, `User`, `Vote`, `ArticleService`).
- The key fields and data structures used (e.g., hash maps, lists, heaps/trees) and how they support the required operations.
- The algorithm used inside each of the above methods.
- Time complexity (big-O) for each API, and trade-offs if you choose one data structure over another.
Do **not** provide full implementation code; instead, focus on a clear OOD and how the methods behave internally.
Quick Answer: This question evaluates object-oriented design, stateful data modeling, vote aggregation, and time-ordered event history tracking competencies in the Software Engineering Fundamentals domain.