This is a tech test for a bank account. It is a command line application that allows a user to make deposits, withdrawals and print a statement of their transactions.
- JavaScript
- Jest
- Node
- ESLint
- Prettier
- Git
- GitHub
- excalidraw
- Clone this repository
- Run
npm install
to install dependencies - Run
jest
to run tests - Run
jest --coverage
to run tests with coverage - Run
npm run lint
to run ESLint
- Run
node
to open the node REPL - Run
const Account = require('./account.js')
to require the Account class - Run
const account = new Account(0)
to create a new account with a balance of 0 - Run
account.deposit(1000)
to deposit £1000 - Run
account.deposit(2000)
to deposit £2000 - Run
account.withdraw(500)
to withdraw £500 - Run
account.printStatement()
to print a statement of the transactions
Copy this code as a block and paste it into the node REPL node
to run all the commands at once:
const Account = require('./account.js')
const account = new Account(0)
account.deposit(1000)
account.deposit(2000)
account.withdraw(500)
account.printStatement()
NOTE: output in Node will show \n for new lines, and \b for backspaces to create the proper formatting required by the acceptance criteria when printed to the console.
- You should be able to interact with your code via a REPL like IRB or Node. (You don't need to implement a command line interface that takes input from STDIN.)
- Deposits, withdrawal.
- Account statement (date, amount, balance) printing.
- Data can be kept in memory (it doesn't need to be stored to a database or anything).
Given a client makes a deposit of 1000 on 10-01-2023
And a deposit of 2000 on 13-01-2023
And a withdrawal of 500 on 14-01-2023
When she prints her bank statement
Then she would see
date || credit || debit || balance
14/01/2023 || || 500.00 || 2500.00
13/01/2023 || 2000.00 || || 3000.00
10/01/2023 || 1000.00 || || 1000.00
As a user, So that I can store my money safely, I would like to be able to [deposit] money into my [account].
As a user, So that I can access my money, I would like to be able to [withdraw] money from my [account].
As a user, So that I can monitor my money and spending, I would like to be able to [print] a [statement] of my [transactions].
User interaction with the application:
A relatively small change in design, the removal of the balance method from the Transaction class, resulted in large changes throughout the codebase, and a major changes in the test suites where many tests had previously used the balance method in the Transaction class.
I derived user stories from the provide requirements and acceptance criteria. I then used these user stories in conjunction with the requirements and acceptance criteria to create a visualisation of the user interaction with the application which informed the design of the classes and methods disucssed below after the classes and methods section. The visualisation and diagramming process led me through several iterations of the design before starting to code, gave me a clear idea of the classes and methods I would need and helped me to identify edge cases.
After a code review, I was advised to remove the balance method from the Transaction class to avoid duplication of the balance in the Account class and the Transaction class. Having a single instance of the balance in the Account class results in a greater level of encapsulation and reduces the risk of the balance in the Transaction class becoming out of sync with the balance in the Account class. It did however mean that I had to refactor the code considerably to calculate the balance in the Account class printStatement method and resulted in a more complex printStatement method with an additional, formatValue method to format the values in the statement. It did also force me to change where in my program, the outputs were being formatted, which I think is a good thing as it means that the formatting is not tied to the Transaction class, could be changed easily if required and the values remain 'clean' until the point where they are outputted to the user.
I came very close to implementing the third class, Statement, but decided against it as I felt comfortable with the printStatement method in the Account class that I ended up with and felt that the Statement class would be unnecessary given the scale of the project.
- Account(balance - float) - manages transactions and balance
- Transaction(credit - float, debit - float, balance - float) - stores transaction details with a date
- constructor(balance - float)
- deposit(amount - float)
- withdraw(amount - float)
- printStatement()
- constructor(credit - float, debit - float, (constructor adds:) date - date)
I decided that the Account class would control the transactions and balance, while a separate Transaction class would store the details of each transaction. I considered the possibility of a third Statment class, but decided against this as the statement is simply a list of transactions and I felt that the Account class could easily handle this given the scale of the project.
- User cannot withdraw or deposit a negative amount
- User cannot withdraw or deposit a non-number
- User cannot withdraw or deposit a number with more than 2 decimal places
- User cannot withdraw or deposit a number with more than 500,000
I took the decision to set a transaction limit of 500,000 as an arbitrary number in consideration that above a certain amount, a bank would likely require some form of authorisation or security check. The limit could be changed by changing the value set in the validateAmount
method in the Account
class.
I also considered restricting withdrawals where there were insufficient funds in the account, but decided against this as it is not a requirement of the tech test and users may also have an overdraft facility.
I asked about a possible requirement to have a user account number or name, but was told that this was not a requirement of the tech test.
> account = new Account(0)
> account.deposit(1000)
> account.deposit(2000)
> account.withdraw(500)
> account.printStatement()
date || credit || debit || balance
14/01/2023 || || 500.00 || 2500.00
13/01/2023 || 2000.00 || || 3000.00
10/01/2023 || 1000.00 || || 1000.00
> account = new Account(0)
> account.deposit(1000)
> account.deposit(2000)
> account.withdraw(500)
> account.balance
2500
I used Jest to test the application.
- There are unit tests for the
Account
andTransaction
classes and integration tests for the user stories. - The
Transaction
class is tested using a mock date to ensure that the date is correct when the transaction is created. - The integration tests also use the same mock date to ensure that the date is correct when the transaction is created.
- The
Account
class is tested using a mock of theTransaction
class to ensure that its methods are called correctly in isolation. - All tests are passing with 100% coverage.
All tests pass with 100% coverage:
With input matching the acceptance criteria input but with the current date: 23rd May 2023, the output is: