Unit 1 · Module 3
Why JavaScript Breaks Down
What happens when small-project trust meets big-project reality
Everything we've covered in this module works. Variables hold data. Functions do work. Types categorize data. Events trigger functions. For a small project — a calculator, a quiz, a single form — JavaScript is perfectly fine on its own.
The problems start when projects get big.
Problem 1: No one enforces the rules
Remember the "29.99" + "5.00" bug that produced "29.995.00" instead
of 34.99? In a small project with one developer, you might catch that. You wrote
the code, you know what price is supposed to be, you'd notice the output looks
wrong.
Now imagine an app with 50 files and three developers. Developer A writes a function that
expects price to be a number. Developer B calls that function and passes a string
because they got it from a form field — and form fields always give you strings, even when the
user types digits. Developer B doesn't know Developer A expected a number. JavaScript doesn't
flag it. The bug ships. Nobody catches it for two weeks.
JavaScript lets you connect pieces that don't fit, and it stays silent about it. In a small project, you can keep the whole thing in your head. In a big project, no one person knows every function's expectations. You need the language itself to catch mismatches. JavaScript won't.
Problem 2: You can't tell what shape data should be
Look at this function:
What does data need to look like?
function processLead(data) {
sendEmail(data.email)
assignCaseManager(data.caseType)
logIntake(data.firstName, data.lastName)
}
What is data? What fields does it need? Does it need email? Does it
need caseType? What if someone passes in an object that has emailAddress
instead of email?
JavaScript won't complain. It'll just see data.email is undefined and
pass undefined to sendEmail. Depending on how sendEmail
is written, it might silently fail, send an email to the word "undefined," or crash with a
confusing error that doesn't point to the real problem.
In a small project, you wrote processLead and the code that calls it, so you
know what shape data should be. In a big project, someone calls your function six
months after you wrote it. They look at processLead(data) and have to guess what
data needs to look like. They either guess right or they introduce a bug.
Problem 3: Refactoring becomes terrifying
Let's say you rename caseType to practiceArea across the app because
that's what the legal team actually calls it. In a small project — find and replace, done.
In a big project with 50 files? You rename it in the database. You rename it in the API. You
rename it in three components. But you missed one function buried in a utility file that still
says data.caseType. JavaScript doesn't care. That field is now
undefined. The feature silently breaks. Maybe in a page nobody checks often. Maybe
it takes a month to notice.
The root cause
All three problems have the same root cause: JavaScript doesn't check anything before it runs. It just trusts you. When a project is small enough that one person can hold it all in their head, that trust works. When a project is big enough that no one person knows every file, that trust becomes the number one source of bugs.
That's why TypeScript exists. Not because JavaScript is bad. Because JavaScript was built for a world of small scripts on simple web pages, and we're now using it to build massive applications it was never designed for. TypeScript adds the checking that JavaScript deliberately left out.
Quick reference: async and await
You saw async and await in the click lifecycle. Here's the short version
for now — we'll cover these properly in a later module.
asyncgoes on the function — it labels the function as one that does something that takes time (like talking to a server)awaitgoes inside the function — it marks the specific moment where JavaScript should pause and wait for a result- They're a pair. You can't use
awaitwithoutasyncon the function
Module 3 complete
You now understand:
- Variables — named containers that hold data in RAM.
letfor values that change,constfor values that don't. Automatic — you never choose to use RAM. - Functions — named sets of reusable instructions. Can take inputs (parameters) and return outputs. Can call other functions. Live in files and get imported where needed.
- Types — the categorization of what a variable holds. String, number, boolean, object, array. JavaScript is loose about enforcing them.
- The lifecycle of a click — event fires, handler runs, data is gathered, validated, sent to the server, server responds, UI updates.
- Code vs data — the code is the instructions (stays the same). The values are in RAM (change every time the code runs). Hardcoded values are developer decisions. Dynamic values come from users and databases.
- Why JavaScript breaks at scale — no enforcement, no shape definitions, refactoring is dangerous. TypeScript was the fix.
Next up: Module 4 — Enter TypeScript. JavaScript with a safety net.