Skip to content

This repository reflects Makers Academy Week 10 project Bank Tech Test. The general overview of this challenge is to create a bank account manager.

License

Notifications You must be signed in to change notification settings

JoshSinyor/bank-tech-test

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

92 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ruby Version License Code Size Ruby Style Guide Deployment CI Badge

Bank Tech Test

This repository reflects Makers Academy Week 10 project Bank Tech Test. The general overview of this challenge is to create a bank account manager.


Table of Contents


Features of Note

  1. Full-blown feature test, using Ruby's poorly documented PTY package. The feature test (integrated in RSpec) opens the program from scratch in a pseudoterminal and executes the acceptance criteria tests specified in exactly the same way a user would.
  2. Automatic test runs using GitHub Actions. No third-party (Marketplace) code is used to achieve this.
  3. True deep copy (using Marshal.load(Marshal.dump(array))) to create a clone of the @transactions array. This is required because the array's elements individual transactions have DateTime objects. Ruby's dup, deep_dup and clone methods are all shallow copies.
  4. The date of transactions is stored as a DateTime object, rather than as a string. It seems best practice to store dates in an appropriate object, especially because this compartmentalisation allows easy reformatting (using strftime) and greater precision (e.g. hours and minutes) should that be desirable in the future.
  5. Transactions are stored as hashes, rather than strings. This makes it easier to reference the characteristics (:date, and :sum) of each transaction.

Specification

The specification of this tech test is as follows:

Requirements

  1. You should be able to interact with your code via a REPL like IRB or the JavaScript console. (You don't need to implement a command line interface that takes input from STDIN.)
  2. Deposits, withdrawal.
  3. Account statement (date, amount, balance) printing.
  4. Data can be kept in memory (it doesn't need to be stored to a database or anything).

Acceptance Criteria

Given a client makes a deposit of 1000 on 10-01-2012, and
A deposit of 2000 on 13-01-2012, and
A withdrawal of 500 on 14-01-2012;
When she prints her bank statement,
Then she would see:

date || credit || debit || balance
14/01/2012 || || 500.00 || 2500.00
13/01/2012 || 2000.00 || || 3000.00
10/01/2012 || 1000.00 || || 1000.00

Getting Started

Prerequisite(s)

This project requires Ruby 3.0.0. If you do not have Ruby 3.0.0, install it using these instructions.

Installation

  1. Clone or fork this repository.
  2. Install the necessary Gems from the Gemfile by executing bundle install.

Running the Program

  1. Move your working directory to the project directory (/bank_tech_test).
  2. Start the program by opening account.rb in your REPL of choice.
  3. Create a new account by executing account = Account.new.

Making a Deposit

Deposit funds to the account by executing account.deposit(sum, "date"), where the sum parameter is a non-optional positive integer, and the date parameter is a non-optional argument. To supply a date argument, use integers for day, month and year in the format dd-mm-yyyy.

Making a Withdrawal

Withdraw funds from the account by executing account.withdraw(sum, "date"), where the sum parameter is a non-optional positive integer, and the date parameter is a non-optional argument. To supply a date argument, use integers for day, month and year in the format dd-mm-yyyy.

Printing a Statement

Print an account statement to console by executing account.print_statement. Account statements are prefixed with a header, and transactions are printed in reverse order of input.


Development Process

Modelling

My approach to this problem relied on TDD, BDD, encapsulation and the SRP in order to create modular code that could be tested in independent units as well as collectively in features. The problem itself is simple; with no GUI it was not necessary to structure an MVC/MVP model. I split responsibilities into several classes so as to improve readability and modularity. I tried to balance the SRP against oversimplification leading to an excessive number of component classes.

To keep the code readable, I prioritised thoughtful naming of objects to reduce the need to explain in comments the purpose of each object and method.

User Stories

The requirements can be parsed in several simple user stories.

Actions are italic. Nouns are bold. Attributes of nouns are bold italics.

User Story 01

   As a user,
   So that I can add money to my account,
   I’d like to be able to deposit a sum in my account.

User Story 02

   As a user,
   So that I can remove money from my account,
   I’d like to be able to withdraw a sum from my account.

User Story 03

   As a user,
   So that I know when I added or removed money from my account,
   I’d like to be able to add a date to each transaction.

User Story 04

   As a user,
   So that I know how much money is in my account,
   I’d like to be able to print my account's balance.

User Story 05

   As a user,
   So that I can see my account's transactions,
   I’d like to be able to print in reverse chronological order my account's transactions.

Domain Modelling

As per Class Responsibility Collaborator modelling, there are three obvious areas of responsibility, and therefore three classes - Account, Transaction and Printer.

Class: Account

Responsibility Collaborators
Knows own transactions Transactions

Class: Transactions

Responsibility Collaborators
Knows own transaction dates
Knows own transaction sums
Knows own balance

Class: Printer

Responsibility Collaborators
Knows transactions Account

The relationship between these classes can be summarised in this Domain Model Diagram:

basic_classes_diagram

Test-Driven Design

TDD was used to structure Unit Tests. These were employed to test individual classes and their methods to ensure that they interacted as expected. RSpec was instructed (using the --format documentation and --color arguments to provide verbose feedback on passing and failing tests.

Behaviour-Driven Design

BDD was used to structure Feature Tests. After unit tests were created to test methods and classes in isolation, feature tests were employed to test the entire program.

Continuous Development

The code was continuously tested throughout development to ensure development was proceeding as expected, and that changes during development did not impact previously tested units and features. This was overseen in part by a CI/CD workflow built on GitHub Actions.

GitHub Actions workflow

The code is tested using RSpec, with coverage checked using SimpleCov. The addition of a GitHub Actions Workflow (as specified in deployment_ci.yml) assists with determining that checks are passed. Every time a commit is pushed to GitHub, the workflow runs creates an environment, installs the relevant gems, and runs the full suite of Rubocop and RSpec tests.

Refactoring

Refactoring was performed after the completion of any individual unit, and periodically throughout development, in order to simplify the code. The aim was to keep the code simple and readable, rather than as compact as possible. To check that the resulting code conformed to the Ruby style guide, it was parsed before each commit through Rubocop (integrating Rubocop-rspec), a linter.


Project Conclusions

Final Appearance

As per the instructions, this program runs exclusively in a REPL. It is pictured below executing the instructions in the Acceptance Criteria.

basic_classes_diagram

Additional Development

I suggest implementing some additional features:

  1. Suppressing the output of the terminal to reduce clutter.
  2. Making the date argument optional by setting a default parameter (DateTime.now).
  3. Sorting the transaction array elements into reversed chronological order - compensating for input of transactions out of chronological order - before printing. This would require a shift to dynamic calculation of the balance value.
  4. Rejection of withdrawals when funds would be insufficient to cover them (returning error Insufficient funds available!).
  5. Code hardening to improve resilience against erroneous input, and provide more helpful error messages.
  6. Justification of tables to align columns to the widest content.

Built With

This program's dependencies are minimal and relate solely to testing. They were chosen for their ubiquity and self-contained nature, so that they could be specified as require: false and required only in the test environment to reduce their impact on the program's speed. For clarity, all dependencies are explicitly invoked by the Gemfile.


Author(s)

Authored by Joshua Sinyor.


License(s)

This project is licensed under the MIT License.


Acknowledgements

About

This repository reflects Makers Academy Week 10 project Bank Tech Test. The general overview of this challenge is to create a bank account manager.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages