Hone logo
Hone
Problems

Event Sourcing for a Simple Bank Account

Event sourcing is a powerful architectural pattern where the state of an application is determined by replaying a sequence of events. This challenge asks you to implement a simplified version of event sourcing for a bank account, focusing on the core concepts of event generation, storage, and state reconstruction. This pattern is useful for auditing, debugging, and enabling time-travel capabilities within an application.

Problem Description

You are tasked with creating a system that manages a bank account using the event sourcing pattern. The system should allow for deposits, withdrawals, and potentially other account actions, but instead of directly updating the account balance, it records each action as an event. The current balance can then be derived by replaying all events related to that account.

Key Requirements:

  • Event Generation: Implement functions to generate events for deposits and withdrawals. Each event should contain information about the action, the amount, and a timestamp.
  • Event Storage: Design a simple mechanism to store events (e.g., a list or a dictionary). For simplicity, you don't need to persist to a database.
  • State Reconstruction: Implement a function that reconstructs the account balance by iterating through the stored events and applying them in chronological order.
  • Account Representation: Define a class to represent a bank account, including methods for generating events and reconstructing the balance.

Expected Behavior:

The system should accurately track account activity through events and be able to calculate the correct balance at any point in time by replaying those events. The order of events is crucial for accurate balance calculation.

Edge Cases to Consider:

  • Withdrawals exceeding balance: Handle cases where a withdrawal amount is greater than the current balance. You can either reject the withdrawal (and generate a "Withdrawal Rejected" event) or allow it (and generate a "Withdrawal" event that results in a negative balance). For this challenge, reject the withdrawal and generate a "Withdrawal Rejected" event.
  • Zero amount transactions: Consider how to handle events with a zero amount. Should they be allowed? For this challenge, ignore zero amount transactions.
  • Invalid Event Types: While not strictly required, consider how you might handle unexpected or invalid event types.

Examples

Example 1:

Input:
account = BankAccount("12345")
account.deposit(100)
account.deposit(50)
account.withdraw(25)
account.withdraw(150) # Attempt to withdraw more than available
account.get_balance()

Output:
125
Explanation:
1. Deposit 100: Balance = 100
2. Deposit 50: Balance = 150
3. Withdraw 25: Balance = 125
4. Withdrawal rejected (attempt to withdraw 150): Balance remains 125

Example 2:

Input:
account = BankAccount("67890")
account.withdraw(50) # Attempt to withdraw before deposit
account.deposit(200)
account.get_balance()

Output:
200
Explanation:
1. Withdrawal rejected (attempt to withdraw 50 before deposit): Balance = 0
2. Deposit 200: Balance = 200

Example 3: (Edge Case - Withdrawal exceeding balance)

Input:
account = BankAccount("11223")
account.deposit(50)
account.withdraw(100)
account.get_balance()

Output:
50
Explanation:
1. Deposit 50: Balance = 50
2. Withdrawal rejected (attempt to withdraw 100): Balance remains 50

Constraints

  • Event Storage: For simplicity, events can be stored in a Python list. No external database is required.
  • Event Types: The system should support "Deposit" and "Withdrawal" events. A "Withdrawal Rejected" event should also be generated.
  • Timestamp: Each event should include a timestamp (you can use datetime.datetime.now() for simplicity).
  • Account ID: Each account should be uniquely identified by an ID string.
  • Performance: While not a primary focus, avoid excessively inefficient data structures or algorithms. The reconstruction process should be reasonably fast for a moderate number of events (e.g., up to 1000).

Notes

  • Focus on the core concepts of event sourcing: event generation, storage, and state reconstruction.
  • Consider using classes to encapsulate the account and event logic.
  • Think about how to handle errors and invalid input.
  • The timestamp is primarily for demonstration and can be simplified if needed.
  • The "Withdrawal Rejected" event is crucial for handling edge cases and maintaining data integrity.
  • The order of events is paramount for accurate balance calculation. Ensure your reconstruction logic respects this order.
Loading editor...
python