Thodoris Kouleris
Software Engineer
Code Kata #1: Bank Account
The Problem
Write a class named BankAccount that implements the following public interface:
public interface BankAccount
{
void deposit(int amount)
void withdraw(int amount)
void printStatement()
}
(Note you can do this exercise in any programming language, translate the above code as appropriate)
Example statementWhen you call the ‘printStatement’ method, something like the following is printed on standard output:
Date || Amount || Balance
2012-01-14 || -500 || 2500
2012-01-13 || 2000 || 3000
2012-01-10 || 1000 || 1000
This example statement shows one withdrawal on 14th January 2012, and two deposits on 13th and 10th January respectively.
Notes
* You cannot change the public interface of the BankAccount
* We’re using ints to represent money, which in general may not be the best idea. In a real system, we would always use a datatype with guaranteed arbitrary precision, but doing so here would distract from the main purpose of the exercise.
* Don’t worry about matching the exact formatting of the bank statement, the important thing is to print a table that has column headings and which orders transactions by date.
The thinking....
Since we already have an interface we will start with that. We will use python to solve the problem.
class IBankAccount(ABC):
@abstractmethod
def deposit(self, amount: int):
pass
@abstractmethod
def withdraw(self, amount: int):
pass
@abstractmethod
def print_statement(self):
pass
To hold the data of each transaction, we can use a simple dataclass that will have a date and the amount. It is not necessary to have a dataclass but makes the whole thing more organized.
@dataclass
class Transaction:
date: str
amount: int
Now we can create the BankAccount class that will implement our interface. We have to make sure that the amount in withdraw and deposit methods won't be a negative number.
It is important to hold the history of the transactions. So, we will introduce a list with the name history that will hold all the transactions.
class BankAccount(IBankAccount):
def __init__(self):
self.history = []
def deposit(self, amount: int):
if amount <= 0:
raise ValueError("Deposit amount must be positive")
self.history.append(Transaction(datetime.today().strftime('%Y-%m-%d %H:%M'), amount))
def withdraw(self, amount: int):
if amount <= 0:
raise ValueError("Withdrawal amount must be positive")
self.history.append(Transaction(datetime.today().strftime('%Y-%m-%d %H:%M'), -amount ))
def print_statement(self):
pass
The last part of the problem is to write the method that will print the transaction history on screen.
def print_statement(self):
header = "Date || Amount || Balance ||"
separator = "-" * 57
print(header)
print(separator)
total_balance = 0
for transaction in self.history:
total_balance += transaction.amount
print(f"{transaction.date} || {transaction.amount:>15} || {total_balance:>15} ||")
The final file will look like this:
from abc import ABC, abstractmethod
from datetime import datetime
from dataclasses import dataclass
@dataclass
class Transaction:
date: str
amount: int
class IBankAccount(ABC):
@abstractmethod
def deposit(self, amount: int):
pass
@abstractmethod
def withdraw(self, amount: int):
pass
@abstractmethod
def print_statement(self):
pass
class BankAccount(IBankAccount):
def __init__(self):
self.history = []
def deposit(self, amount: int):
if amount <= 0:
raise ValueError("Deposit amount must be positive")
self.history.append(Transaction(datetime.today().strftime('%Y-%m-%d %H:%M'), amount))
def withdraw(self, amount: int):
if amount <= 0:
raise ValueError("Withdrawal amount must be positive")
self.history.append(Transaction(datetime.today().strftime('%Y-%m-%d %H:%M'), -amount ))
def print_statement(self):
header = "Date || Amount || Balance ||"
separator = "-" * 57
print(header)
print(separator)
total_balance = 0
for transaction in self.history:
total_balance += transaction.amount
print(f"{transaction.date} || {transaction.amount:>15} || {total_balance:>15} ||")
Improvements
The most obvious improvement that we could do, but we are restricted by the requisite of the problem (use the given interface) could be to separate the print statement from the bank account class for SOLID reasons.