The Problem
You write a 500-line script that does everything. When requirements change, you rewrite half of it. When a bug appears, you debug the whole thing. When you want to reuse one piece of logic, you copy-paste it — and now there are two copies that slowly drift apart.
Professional code is modular: each function does one job, each file groups related jobs, and changes stay local. This lesson builds that skill on a concrete task you'll do constantly in ML — computing model evaluation metrics — so the abstractions stay grounded.
Why this is a hiring signal
Anyone can make code that runs once. Engineers are trusted with code that others reuse and change safely. "One function, one job, clearly named, with a docstring" is the habit interviewers look for.
The Concept
Why Functions Exist
A function is a named, reusable block of code that takes inputs (arguments) and returns an output. But that definition misses the point. The real purpose of a function is abstraction through naming: when you write calculate_f1(precision, recall), you're telling the reader "this chunk of logic has a name and a purpose — you don't need to read the implementation to understand what it does." This is how you manage complexity in a 10,000-line codebase: you name things well, compose them, and hide details behind clear interfaces.
A module is just a .py file full of functions you can import elsewhere. It groups related functions so they can be found, tested, and reused as a unit. Together, functions and modules let you tackle a big problem by breaking it into small, testable pieces:
big problem
→ split into sub-problems
→ write one function per sub-problem (each independently testable)
→ group related functions into a module
→ import and compose them at a higher level
Pure Functions: The Easiest Kind to Trust
A pure function is one where the output depends only on the inputs — same input always produces the same output, and the function has no side effects (no modifying global state, no writing to files, no network calls). Pure functions are the easiest to test (just assert input → output), the easiest to reason about (no hidden dependencies), and the easiest to parallelize (no shared mutable state).
In ML engineering, most metric calculations, data transformations, and mathematical operations should be pure functions. The impure parts — loading data from disk, calling an API, logging metrics — should be isolated to the edges of your system, not mixed into the core logic.
What's the core principle of a well-designed function?
Single responsibility: one job, clear inputs, predictable output. Small focused functions are the ones you can test, name, reuse, and change without fear.
Unlock the full lesson
You've read the first 2 sections. The rest of this lesson covers Build It, Use It, Ship It, Exercises, Evaluation, Key Terms, Common Pitfalls, Interview Framing — plus a hands-on lab, quiz, and project artifact.
Create a free account to unlock Phase 0 and Phase 1 of every course — no credit card.