Skip to Content
5. ExtrasRefactoring

Refactoring

By Nael Shiab

Last updated on

Coding is like a journey. You know where you start and where you want to go (in theory 😅). But you don’t know which road to take. So you start exploring, try one way, then go back, take a shortcut, hit dead ends, and follow longer roads until… you finally arrive at your destination. And that’s totally okay.

It’s the same with your code. This means you’ll write a lot of code, make mistakes, find workarounds, and eventually get your first results. Your code will be messy and long. And that’s fine.

This is why refactoring is an important step. It means restructuring your code to improve its readability, maintainability, and sometimes performance, while keeping the same output.

A key aspect of refactoring is breaking down long scripts into modular functions.

In this lesson, we will take the final code from the Savings calculator 💸 and refactor it. If you haven’t done this project, do it first!

I assume you’ve completed the previous lessons, especially the Setup lesson, before diving into this one.

Want to know when new lessons are available? Subscribe to the newsletter ✉️ and give a ⭐ to the GitHub repository to keep me motivated! Click here to get in touch.

Setup

Create a new, empty folder on your computer, open it with VS Code, and create a file named main.ts inside it.

We’ll start with the final code from the savings calculator project. This script calculates the gains or losses of a savings account over 10 years. Add it to main.ts and save the file:

main.ts
const initialAmount = 5000; const interestRate = 2; const interestRateRange = 20; const startingYear = 2025; const years = 10; let balance = initialAmount; const results = []; for (let year = startingYear; year < startingYear + years; year++) { const randomNumber = Math.random() - 0.5; const randomFluctuation = randomNumber * interestRateRange; const randomInterestRate = Math.round(interestRate + randomFluctuation); const gainsOrLosses = Math.round(balance * (randomInterestRate / 100)); balance += gainsOrLosses; results.push({ year, interestRate: randomInterestRate, gainsOrLosses, balance, }); } const lastResult = results[results.length - 1]; const finalGainsOrLosses = lastResult.balance - initialAmount; const perc = Math.round( (finalGainsOrLosses / initialAmount) * 100, ); if (finalGainsOrLosses > 0) { console.log(` Congratulations! You've made money! Initial amount: $${initialAmount} Final amount: $${lastResult.balance} Gains: $${finalGainsOrLosses} (+${perc}%) `); } else if (finalGainsOrLosses < 0) { console.log(` Sorry! You've lost money! Initial amount: $${initialAmount} Final amount: $${lastResult.balance} Losses: $${finalGainsOrLosses} (${perc}%) `); } else { console.log("\nYou've neither lost nor gained money!\n"); } console.table(results);

Open the terminal (Command + J on Mac or Control + J on Windows) and run this command:

node --watch main.ts

This runs our code and automatically runs it again each time we save a change, so we can see the results as we work.

This is what you should see in your terminal, with different values.

The terminal showing the savings calculator summary and yearly results.

Helper functions

The script works well, but reading all of this at once can be a bit intimidating. It could be refactored into something easier to read and understand.

We can do that by moving parts of the code into helper functions.

In the Explorer in VS Code (the tab on the left), right-click on your project folder and select New Folder. Name it helpers and press Enter.

It looks like lines 12-14 could easily be encapsulated in a function. These lines compute a random interest rate. Let’s create a new file named getRandomInterestRate.ts in the helpers folder (right-click on helpers in the Explorer, select New File, enter the file name, and press Enter) and move these lines into a function.

helpers/getRandomInterestRate.ts
export default function getRandomInterestRate( interestRate: number, interestRateRange: number, ) { const randomNumber = Math.random() - 0.5; const randomFluctuation = randomNumber * interestRateRange; const randomInterestRate = Math.round(interestRate + randomFluctuation); return randomInterestRate; }

Lines 28-50 are also great candidates for refactoring. These lines log a message based on the gains or losses. Let’s move them into a function named logAnswer.

I also removed the console.table(results) since we don’t really need it.

helpers/logAnswer.ts
export default function logAnswer( initialAmount: number, results: { balance: number }[], ) { const lastResult = results[results.length - 1]; const finalGainsOrLosses = lastResult.balance - initialAmount; const perc = Math.round( (finalGainsOrLosses / initialAmount) * 100, ); if (finalGainsOrLosses > 0) { console.log(` Congratulations! You've made money! Initial amount: $${initialAmount} Final amount: $${lastResult.balance} Gains: $${finalGainsOrLosses} (+${perc}%) `); } else if (finalGainsOrLosses < 0) { console.log(` Sorry! You've lost money! Initial amount: $${initialAmount} Final amount: $${lastResult.balance} Losses: $${finalGainsOrLosses} (${perc}%) `); } else { console.log("\nYou've neither lost nor gained money!\n"); } }

You might be confused by the results type in the code above.

{ balance: number } describes an object with a key balance and an associated number value. The [] at the end indicates that we expect results to be an array of such objects.

This type description is important. In our code, we rely on the balance. This type ensures it’s there. If you try to pass an array of objects without a balance as a number, you’ll get a type error.

To find the proper type, I just hovered over results in main.ts and copied the inferred type. No need to write it yourself! I removed the year, interestRate, and gainsOrLosses keys, since we don’t use them in the function.

VS Code showing the inferred type of results.

Now, we can update our main.ts. We import our new functions and use them. Our script is now simpler and easier to understand.

main.ts
import getRandomInterestRate from "./helpers/getRandomInterestRate.ts"; import logAnswer from "./helpers/logAnswer.ts"; const initialAmount = 5000; const interestRate = 2; const interestRateRange = 20; const startingYear = 2025; const years = 10; let balance = initialAmount; const results = []; for (let year = startingYear; year < startingYear + years; year++) { const randomInterestRate = getRandomInterestRate( interestRate, interestRateRange, ); const gainsOrLosses = Math.round(balance * (randomInterestRate / 100)); balance += gainsOrLosses; results.push({ year, interestRate: randomInterestRate, gainsOrLosses, balance, }); } logAnswer(initialAmount, results);

The updated main.ts importing and using getRandomInterestRate and logAnswer.

We could even go one step further by wrapping everything in main.ts inside a function named runSimulation.

Let’s create another file named runSimulation.ts in the helpers folder and move all of this code into it.

Since we are now in the helpers folder, we need to update the import paths for getRandomInterestRate.ts and logAnswer.ts.

Additionally, the constant variables initialAmount, interestRate, interestRateRange, startingYear, and years will now become parameters for the runSimulation function.

helpers/runSimulation.ts
import getRandomInterestRate from "./getRandomInterestRate.ts"; import logAnswer from "./logAnswer.ts"; export default function runSimulation( initialAmount: number, interestRate: number, interestRateRange: number, startingYear: number, years: number, ) { let balance = initialAmount; const results = []; for (let year = startingYear; year < startingYear + years; year++) { const randomInterestRate = getRandomInterestRate( interestRate, interestRateRange, ); const gainsOrLosses = Math.round(balance * (randomInterestRate / 100)); balance += gainsOrLosses; results.push({ year, interestRate: randomInterestRate, gainsOrLosses, balance, }); } logAnswer(initialAmount, results); }

Now, we can update main.ts and make it… incredibly simple.

main.ts
import runSimulation from "./helpers/runSimulation.ts"; runSimulation(5000, 2, 20, 2025, 10);

VS Code running a single simulation from main.ts.

Our code is now very modular. While our original script could only run one simulation at a time, we can now easily run a thousand or more!

main.ts
import runSimulation from "./helpers/runSimulation.ts"; for (let i = 1; i <= 1000; i++) { console.log(`Simulation ${i}`); runSimulation(5000, 2, 20, 2025, 10); }

VS Code running a thousand simulations in a loop.

💡

You might think that creating multiple files makes it more difficult to navigate your code. But if you press CMD on Mac or CTRL on PC and click on a function in your code, VS Code will automatically take you to the function’s file by opening a new tab.

Conclusion

You don’t always have the luxury of time to refactor your code. But if you plan on reusing, sharing, or maintaining your code for a long time, it’s a worthwhile investment, especially if you add tests (but tests will be another lesson).

Enjoyed this? Want to know when new lessons are available? Subscribe to the newsletter ✉️ and give a ⭐ to the GitHub repository to keep me motivated! Get in touch if you have any questions.