How do I extend my Python cash machine program to handle multiple accounts?

Summary

The provided Python code simulates a basic cash machine program with a single account, verifying the PIN and ensuring sufficient balance before processing a withdrawal. However, the code lacks the ability to handle multiple accounts, PIN changes, transaction logging, daily withdrawal limits, and comprehensive error handling. To extend this program, we need to redesign the architecture to accommodate these features.

Root Cause

The root cause of the limitations in the current code is the use of global variables and a simplified account representation. The code does not utilize a data structure to store multiple accounts, making it difficult to manage and extend. Additionally, the lack of modular design and error handling mechanisms hinders the implementation of advanced features.

Why This Happens in Real Systems

This issue occurs in real systems when:

  • Inadequate design: The initial design does not consider future requirements or scalability.
  • Insufficient testing: The system is not thoroughly tested for edge cases and potential security breaches.
  • Lack of maintainability: The code is not modular or well-structured, making it difficult to modify or extend.

Real-World Impact

The limitations of the current code can lead to:

  • Security vulnerabilities: Repeated incorrect PIN entries can lead to account compromise.
  • Inconvenience to users: Insufficient funds or incorrect PINs can result in frustrated users.
  • System crashes: Unhandled errors can cause the system to crash or become unresponsive.

Example or Code

class Account:
    def __init__(self, account_number, pin, balance):
        self.account_number = account_number
        self.pin = pin
        self.balance = balance
        self.transaction_log = []
        self.daily_withdrawal_limit = 1000
        self.attempts = 0

    def verify_pin(self, input_pin):
        if input_pin == self.pin:
            return True
        else:
            self.attempts += 1
            return False

    def withdraw(self, amount):
        if amount <= self.balance and amount <= self.daily_withdrawal_limit:
            self.balance -= amount
            self.transaction_log.append(f"Withdrawal: {amount}")
            self.daily_withdrawal_limit -= amount
            return True
        else:
            return False

class CashMachine:
    def __init__(self):
        self.accounts = {}

    def add_account(self, account_number, pin, balance):
        self.accounts[account_number] = Account(account_number, pin, balance)

    def get_account(self, account_number):
        return self.accounts.get(account_number)

# Create a cash machine and add an account
cash_machine = CashMachine()
cash_machine.add_account("12345", "4352", 10000)

# Get the account and perform a withdrawal
account = cash_machine.get_account("12345")
if account.verify_pin("4352"):
    if account.withdraw(500):
        print("Withdrawal successful")
    else:
        print("Insufficient funds or daily limit exceeded")
else:
    print("Incorrect PIN")

How Senior Engineers Fix It

Senior engineers address these issues by:

  • Redesigning the architecture: Utilizing a modular design with classes and objects to represent accounts and the cash machine.
  • Implementing comprehensive error handling: Catching and handling potential errors, such as incorrect PINs or insufficient funds.
  • Adding security features: Implementing daily withdrawal limits and tracking transaction logs to prevent security breaches.
  • Conducting thorough testing: Testing the system for edge cases and potential security vulnerabilities.

Why Juniors Miss It

Junior engineers may miss these issues due to:

  • Lack of experience: Inadequate experience with designing and implementing complex systems.
  • Insufficient knowledge: Limited understanding of security best practices and error handling mechanisms.
  • Overemphasis on simplicity: Focusing too much on simplicity and not considering future requirements or scalability.

Leave a Comment