Design in-memory payment and friendship system
RobinhoodSoftware Engineer · Technical ScreenLast updated
This question evaluates object-oriented design skills, stateful in-memory data structures, request processing, and correctness constraints such as friend relationships, unique request IDs, and atomic balance transfers.
Design and implement an in-memory payment system with simple social features. The system processes a sequence of requests that can:
- Register a user
- Send a friend request from one user to another
- Accept a friend request (referencing a previous friend request by its request ID)
- Transfer money between two users
Rules and Requirements
- Users and balances
- Each user has:
- A unique
user_id(string) - A
balance(integer amount, e.g., cents) - A list or set of friends (other user IDs)
- Friend requests
- A friend request is initiated via a request that includes:
- A unique
req_idfor this friend request user1anduser2(both must be existing users)- An accept-friend request does not repeat the usernames; instead it contains:
- Its own
req_id(unique for the accept request) - The
req_idof the original friend request to accept - Only when an accept-friend request is processed successfully do
user1anduser2become friends.
- Transfers
- Money can only be transferred between users who are already friends.
- A transfer request specifies:
- A unique
req_id from_userto_useramount(> 0)- A transfer must fail if:
- Either user does not exist, or
- The users are not friends, or
from_userdoes not have enough balance.- On success:
- Subtract
amountfromfrom_user.balance. - Add
amounttoto_user.balance.
- Error handling
- If a request is invalid (e.g., refers to unknown user, refers to a non-existent friend request ID, tries to accept a friend request twice, etc.), the system should indicate failure for that request.
- You can define reasonable behavior for repeated or conflicting requests, but document it in comments.
Interface
Design classes and methods in an object-oriented way.
One possible interface (you can adjust names/signatures as long as behavior is clear):
class PaymentSystem:
def register_user(self, user_id: str, initial_balance: int) -> bool:
"""Register a new user with given balance. Return False if user_id already exists."""
def send_friend_request(self, req_id: str, user1: str, user2: str) -> bool:
"""Store a friend request identified by req_id. Return False on invalid input or duplicate req_id."""
def accept_friend_request(self, req_id: str, original_req_id: str) -> bool:
"""Accept the previously stored friend request with ID original_req_id. Return False if original_req_id doesn't exist, is already accepted, or users are invalid."""
def transfer(self, req_id: str, from_user: str, to_user: str, amount: int) -> bool:
"""Transfer amount from from_user to to_user if they are friends and balance is sufficient. Return True on success, False otherwise."""
Your implementation should:
- Maintain all necessary internal state in memory (no external database required).
- Enforce the friendship and balance constraints for transfers.
- Correctly handle the indirection where a friend-accept request refers to an earlier friend-request by
req_id.
You may ignore concurrency in the basic solution, but you can optionally comment on how you would make operations atomic under multiple threads.
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.