Skip to content

MattTravis/GL_Affordability_Kata

Repository files navigation

GL_Affordability_Kata

A Kata for a service that determines tenant/property affordability given tenant income, expenses, and property rental value.

Task 1

Translate the given pseudocode into a unit test (plus models and functionality) the determines which properties the tenant can afford.

//Given 

//Transactions - date, type description, money out, money in, balance
"1st January 2020", "Direct Debit", "Gas & Electricity", "£95.06", "", "£1200.04"
"2nd January 2020", "ATM", "HSBC Holborn", "£20.00", "", "£1180.04"
"3rd January 2020", "Standing Order", "London Room", "£500.00", "", "£680.04"
"4th January 2020", "Bank Credit", "Awesome Job Ltd", "", "£1254.23", "£1934.27"
"1st February 2020", "Direct Debit", "Gas & Electricity", "£95.06", "", "£1839.21"
"2nd February 2020", "ATM", "@Random", "£50.00", "", "£1789.21"
"3rd February 2020", "Standing Order", "London Room", "£500.00", "", "£1289.21"
"4th February 2020", "Bank Credit", "Awesome Job Ltd", "", "£1254.23", "£2543.44"

// Properties - id, address, rent per month
1, "1, Oxford Street", 300
2, "12, St John Avenue", 750
3, "Flat 43, Expensive Block", 1200
4, "Flat 44, Expensive Block", 1150
            
// When

affordableProperties = affordabilityService.Check(transactions, properties);
        
// Then

Assert.AreEqual(1, affordableProperties.Count)
Assert.AreEqual("1, Oxford Street", affordableProperties[0].address)      

Task 2

Write a program that takes in the provided bank_statement.csv and properties.csv files, and outputs which properties the tenant can afford.

Task 3

Implement a unit test suite to fully validate the service, including correct operation and graceful error handling.

Notes

Methodology

Assuming the tasks can be completed in any order, I will choose to follow TDD (Test Driven Development) methodology with a Red|Green|Refactor commit pattern, and adhere to SOLID and KISS principles. Some up-front thought is put into exploring and understanding the business rules, and defining sensible abstractions before committing to following TDD to develop the concretions.

Process

  • Unpack the business rules provided and try to derive some basic insights.
  • Define the abstractions.
  • Follow TDD methodology to implement a concretion for each abstraction.
  • Ensure the unit test suite contains a test based on the pseudocode from Task 1.

Business Rule Analysis

I am given the business rule "A tenant is able to afford a property if their monthly recurring income exceeds their monthly recurring expenses by the total of the monthly rent times 125%." This can be written as "Affordable = (Income - Expenses) > (Rent * 1.25)". Therefore, if Expenses >= Income, then the tenant cannot afford any property. This may be a useful shortcut later. I can also derive an "affordability" metric from this, by which a list of properties can be ranked from most affordable to least affordable for a given tenant. There is no specific requirement for this, but it might be useful to return the results ordered in this manner. While there is only one static rule at present, there may be other rules later, or amendments to the formula. This is not explicitly part of the requirements as written, but could be an opportunity to use the Strategy pattern if there are interchangeable rules, or Visitor pattern if there is a definable sequence of rules to be followed in order.

Assumptions

  • Tenants must provide at least two months of bank statements in order for us to determine reoccurring monthly transactions.
  • Bank transactions can be categorised, and certain transaction categories should not be included when determining reoccurring income and expenses.
  • For a transaction to be reoccurring it must share type and description on consecutive months. It must also not be an ignorable transaction type. For the purposed of this kata, the transaction must occur in all supplied bank statement months to be considered recurring. This could get fairly complex when considering reoccurring transactions that start or end part way through the bank statement period, or have a periodicity that is different to one month. There are some potential complexities here that would make for an interesting extension - pay variance, ignorable transaction types, etc
  • Bank statements and properties have a standard document format.

Abstractions

IAffordabilityService Based on the pseudocode example, we get an expected method Check that takes a collection of bank statement transactions and a collection of properties, returning a collection of properties that are affordable.

Further abstractions may fall out of the TDD methodology in time.

Example Program

I chose to implement a Function App for Task 2 - these have been my bread and butter for the last three years, although I have somehow avoided file uploads. The CSVs have been processed using the CsvHelper library. I am not sure if the expectation was for me to hand craft a parser for this or not. Ultimately that felt like re-inventing the wheel - (most) libraries exist for a reason, after all. I have provided a Postman collection for sending a POST request to the Function App with files in the form. The example files have also been added to the repo.

Conclusion

I freely admit I spent more time on this than suggested, as I enjoyed digging into the complexities of what at first glance may have been a trivial exercise. I still feel there is more to explore. I definitely abandoned the TDD approach when it came to the end and I was rushing to put together the Function App as an example program. Strict TDD is a coding philosophy, an ideal we strive towards but one we don't always fulfil. I would have liked to convert my validation to FluentValidation, and migrate from throwing Exceptions to a ProblemDetails response model.

Thanks for reading!

About

A Kata for a service that can determine affordability of a collection of properties for a given tenant

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages