Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Improve types in Mortgage and FairholdLandPurchase #23

Merged
merged 2 commits into from
Aug 2, 2024

Conversation

DafyddLlyr
Copy link
Contributor

@DafyddLlyr DafyddLlyr commented Jul 26, 2024

What does this PR do

  • A pass through Mortgage and FairholdLandPurchase classes with the aim of removing properties marked as optional (?) which are actually always present.
  • Improvements to types
  • No logical changes, just tinkering around the edges!
  • I'll add comments alongside the code explaining my thoughts behind any changes

Copy link

vercel bot commented Jul 26, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
fairhold-dashboard ✅ Ready (Inspect) Visit Preview 💬 Add feedback Aug 2, 2024 7:06am

Comment on lines +3 to +5
const DEFAULT_INTEREST_RATE = 0.06;
const DEFAULT_MORTGAGE_TERM = 30;
const DEFAULT_INITIAL_DEPOSIT = 0.15;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defining constants like this make it clearer that these are constants and not magic numbers, it should also make them easier to find and update 👍

Comment on lines +7 to +18
type MortgageBreakdown = {
yearlyPayment: number;
cumulativePaid: number;
remainingBalance: number;
}[];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Types and interfaces can be defined once, applied to their respective classes, and then cascade down to where needed.

Comment on lines +16 to +24
* This value is given as a percentage. For example, 0.05 represents a 5% rate
*/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using JSDoc for meaningful comments leads to better DX as these are then accessible through most IDEs -

image

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's phenomenal! Super useful!

this.calculateMonthlyMortgagePayment(); // calculate the montly payment
this.calculateYearlyPaymentBreakdown(); // calculate the yearly breakdown;
this.termYears = mortgageTerm;
this.principal = this.calculateMortgagePrinciple();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I was forgetting from our call earlier - as opposed to marking properties with ! which isn't ideal, as long as we define them in the constructor they'll get picked up as required properties.

@@ -0,0 +1 @@
export const MONTHS_PER_YEAR = 12;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this is a bit redundant, discuss! For me it's a little easier to read and reason with than a mixture of numbers and variable names. If this isn't helpful we can revert to 12.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes sense! I imagine that saving this as a constant might help contextualise a * or / 12 more quickly. One less jump to make while reading over some code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed - I think that parsing word * word is generally easier than word * number 👍

Comment on lines -14 to -18
newBuildPrice, // new build price of the property
depreciatedBuildPrice, // depreciated building price
constructionPriceGrowthPerYear, // construction price growth per year
yearsForecast, // years forecast
maintenanceCostPercentage, // maintenance cost percentage
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of similar comments removed in this PR - mainly as they add a bit of noise without much value, they're often a rehash of the variable name.

A good aim with comments is to try to explain "why", not "what". Hopefully the code and variable names should cover the "what" 👍

Comment on lines +7 to +12
interface MortgageParams {
propertyValue: number;
interestRate?: number;
mortgageTerm?: number;
initialDeposit?: number;
}
Copy link
Contributor Author

@DafyddLlyr DafyddLlyr Jul 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting up a type for the constructor params allows us to avoid a fair amount of type repetition / boilerplate. Still a bit verbose but a little better I think?

Likely required until a solution for microsoft/TypeScript#5326 is in place.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I don't quite understand the ? in the interface. I thought that all these parameters need to exist (can't be undefined) to instantiate the mortgage class?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a much nice constructor, thanks for suggesting it!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I can explain this!

These variables are genuinely optional in the constructor. If I don't provide them, then we'll fall back to the default values within the constructor (e.g. this.initialDeposit = params.initialDeposit || DEFAULT_INITIAL_DEPOSIT).

This means we can easily construct a Mortgage instance with only the required variable propertyValue, and always have a class which has the required properties initialDepost, interestRate and termYears.

yearsForecast: number,
constructionPriceGrowthPerYear: number
) {
private calculateLifetime({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand why private is used here--I get that it means its properties aren't accessible elsewhere, but why is that useful? Is that to prevent them from being modified or something like that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep happy to explain this!

I'm using private here just to annotate how the class is currently being used in the codebase. These functions are just internal to the class and being used to construct it. They don't have a use case (currently) outside the scope of the constructor.

This just means that when we're using an instance of the Mortgage class downstream somewhere it won't be possible to call this function directly (mortgage.calculateLifetime(), but we will be able to access the property mortgage.lifetime.

/**
* Number of decimal places to use when rounding numerical values
*/
const PRECISION = 2
Copy link
Collaborator

@gabrielegranello gabrielegranello Jul 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these be moved into constants.ts ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question! If we're consistently using two decimal places across the codebase as a standard, yes we should move it. If this is particular to this class, it can stay here.

this.landToTotalRatio = this.landPrice / this.bedWeightedAveragePrice; // define the land to total ratio
}
}
// TODO: Reuse HouseType enum
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me see if got the logic right here. Since you previously defined the calculationSchema, can we add something like this?

import { calculationSchema } from './calculationSchema';
type HouseType = typeof calculationSchema.shape.houseType._type;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure of the exact syntax, but that's essentially the idea yes. We would like to define the enum once, so that we don't need to try and synchronise various variables and make sure they always match.

We might define this in Zod first (as I did in another PR), we we might define it here in the class and pull this into our Zod validation schema.

Once both PRs are merged I'll come back and pick up this TODO 👍

Base automatically changed from dp/split-up-models to main July 29, 2024 10:02
@DafyddLlyr DafyddLlyr force-pushed the dp/tidy-up-mortgage-and-fairholdlandpurchase branch from 15b606c to 82705f9 Compare July 29, 2024 10:04
Copy link
Collaborator

@zz-hh-aa zz-hh-aa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the super clear explanations! Changes make a lot of sense and really tidy things up.

@DafyddLlyr DafyddLlyr force-pushed the dp/tidy-up-mortgage-and-fairholdlandpurchase branch from 57ee5da to 5386b54 Compare August 2, 2024 07:05
@DafyddLlyr DafyddLlyr merged commit b0a4ef4 into main Aug 2, 2024
2 checks passed
@DafyddLlyr DafyddLlyr deleted the dp/tidy-up-mortgage-and-fairholdlandpurchase branch August 2, 2024 07:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants