What's the Point of Classes In Programming?
Why can't you just use functions for everything? The real story behind classes vs functions, and why this question kept me up at night for months.
I spent a week rewriting the same authentication system three different ways.
Not because I'm a masochist. Not because I had nothing better to do. But because I couldn't figure out why everyone kept telling me to use classes when functions seemed to work just fine.
"Just use a class," they said. "It's better organized," they said. Meanwhile, my functions were working perfectly, thank you very much. Why complicate things?
Then one day, everything clicked. And honestly? I felt like an idiot for not seeing it sooner.
The Night Everything Broke
Picture this: 2 AM, energy drink number four, and my "simple" function-based user system has turned into a nightmare. I had functions everywhere - createUser()
, updateUser()
, deleteUser()
, validateUser()
, authenticateUser()
. Seemed logical, right?
But then I needed to add user roles. And subscription tiers. And login history.
Suddenly I'm passing the same user data through fifteen different functions, each one slightly modifying it, and I have no idea what the user object looks like anymore. Is the password hashed yet? Did I already validate the email? Why does updateUser()
need seventeen parameters?
My friend looked at my code and just said, "Dude, this is exactly what classes are for."
I wanted to punch him. But he was right.
Functions Are Like Kitchen Tools
Think of functions like kitchen tools. A knife cuts. A whisk whisks. A pan fries. Each tool does one thing well.
function chopVegetables(vegetables) {
return vegetables.map(veg => veg.slice());
}
function boilWater(temperature) {
return heat(water, temperature);
}
function cookPasta(pasta, water) {
return combine(pasta, water);
}
Perfect for simple tasks. You grab the tool, use it, put it down. The tool doesn't need to remember what it did last time. It just does its job.
But what happens when you're cooking a complex meal?
Classes Are Like Having a Chef
Now imagine you hire a chef. The chef knows the recipe, keeps track of what's cooking, remembers which ingredients you've already used, and manages the entire process.
class Chef {
constructor() {
this.ingredientsUsed = [];
this.currentDish = null;
this.cookingTime = 0;
}
startDish(dishName) {
this.currentDish = dishName;
this.cookingTime = 0;
console.log(`Starting to cook ${dishName}`);
}
addIngredient(ingredient) {
this.ingredientsUsed.push(ingredient);
console.log(`Added ${ingredient} to ${this.currentDish}`);
}
cook(minutes) {
this.cookingTime += minutes;
console.log(`Cooked for ${minutes} minutes`);
}
serve() {
console.log(`${this.currentDish} is ready!`);
console.log(`Used: ${this.ingredientsUsed.join(', ')}`);
console.log(`Total cooking time: ${this.cookingTime} minutes`);
}
}
The chef (class) maintains state. They remember what they're cooking, what ingredients they've used, how long things have been cooking. You don't have to keep track of everything yourself.
The Difference Nobody Explains Properly
Here's what took me a while to understand: Functions transform things. Classes ARE things.
A function is a verb. A class is a noun.
When you write calculateTax(price)
, you're performing an action on data.
When you write new ShoppingCart()
, you're creating a thing that exists, has properties, and can do stuff.
When Your Functions Start Looking Suspicious
I learned to spot when I needed a class by watching for these red flags in my function-based code:
Red Flag 1: The Parameter Parade
// When your functions look like this...
function processOrder(
userId,
userName,
userEmail,
userAddress,
userPaymentMethod,
orderId,
orderItems,
orderTotal,
orderDiscount
) {
// You probably need a class
}
Red Flag 2: The Global Variable Explosion
let currentUser = null;
let isLoggedIn = false;
let loginAttempts = 0;
let lastLoginTime = null;
let sessionToken = null;
function login(username, password) {
// Modifying five global variables... yikes
}
Red Flag 3: The Function Family
function createUser() { }
function updateUser() { }
function deleteUser() { }
function validateUser() { }
function getUserById() { }
function getUserByEmail() { }
function resetUserPassword() { }
// When functions multiply like rabbits, they might belong together
The User System That Changed My Mind
Remember my 2 AM disaster? Here's how classes saved it:
class User {
constructor(email, password) {
this.id = generateId();
this.email = email;
this.passwordHash = hashPassword(password);
this.createdAt = Date.now();
this.loginHistory = [];
this.role = 'user';
}
login(password) {
if (verifyPassword(password, this.passwordHash)) {
this.loginHistory.push(Date.now());
return generateToken(this.id);
}
throw new Error('Invalid password');
}
updateEmail(newEmail) {
if (validateEmail(newEmail)) {
this.email = newEmail;
return true;
}
return false;
}
hasRole(role) {
return this.role === role;
}
}
Suddenly, everything made sense. The user wasn't just data being passed around - it was an entity with properties and behaviors. The class kept related data and functions together, maintaining its own state.
But Here's the Plot Twist
After falling in love with classes, I made another mistake. I started using them for EVERYTHING.
// Please don't do this
class TaxCalculator {
calculate(price) {
return price * 0.08;
}
}
const calculator = new TaxCalculator();
const tax = calculator.calculate(100);
This is ridiculous. You're creating an object that has no state, no properties to track, nothing that makes it a "thing." It's just a function wearing a class costume.
Just use a function:
function calculateTax(price) {
return price * 0.08;
}
const tax = calculateTax(100);
The Mental Model That Finally Worked
Here's how I decide now:
Use a function when:
- You're transforming data (input → output)
- There's no state to maintain
- It's a one-time operation
- You're doing math, formatting, or validation
Use a class when:
- You're modeling a real-world entity (User, Product, ShoppingCart)
- You need to maintain state between operations
- Multiple functions operate on the same data
- You want to create multiple instances with similar behavior
Real Examples That Made It Click
Example 1: Email Validator
Function approach (correct):
function isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
Why? It's stateless. It takes input, returns output. Done.
Example 2: Shopping Cart
Class approach (correct):
class ShoppingCart {
constructor() {
this.items = [];
this.discount = 0;
}
addItem(product, quantity) {
this.items.push({ product, quantity });
}
removeItem(productId) {
this.items = this.items.filter(item => item.product.id !== productId);
}
getTotal() {
const subtotal = this.items.reduce((sum, item) =>
sum + (item.product.price * item.quantity), 0);
return subtotal * (1 - this.discount);
}
applyDiscount(percentage) {
this.discount = percentage / 100;
}
}
Why? The cart maintains state (items, discount), and multiple operations work on that same state.
What Actually Happens If You Pick Wrong?
I used to panic about this. What if I use functions when I should use classes? What if I use classes when I should use functions?
Here's the truth: Your code will still work. It might just be annoying to maintain.
If you use too many functions, you'll end up with:
- Parameter hell (functions with 10+ arguments)
- Global variable soup
- Duplicated logic
- Hard-to-track state
If you use too many classes, you'll end up with:
- Over-engineered simple operations
- Unnecessary complexity
- More boilerplate code
- Confused teammates wondering why
AddTwoNumbers
is a class
The Approach I Use Now
I start with functions. Always. They're simpler, easier to test, easier to understand.
When I notice I'm passing the same data structure through multiple functions, or when functions start needing to know about each other's results, I refactor to a class.
It's like starting with a toolbox and upgrading to a workshop when you need it. Not the other way around.
Your Code Doesn't Care
Here's the secret that took me too long to learn: Programming paradigms are for humans, not computers.
Your computer doesn't care if you use classes or functions. After compilation, it's all just memory addresses and instruction pointers anyway.
These patterns exist to help us humans organize our thoughts. Classes aren't "better" than functions. Functions aren't "simpler" than classes. They're different tools for different mental models.
So What's the Point?
Classes are organizational tools for when your data and the operations on that data belong together. They're a way to say "this stuff is related and should travel as a unit."
Can you exclusively use functions? Sure. People do it all the time in functional programming languages.
Can you exclusively use classes? Technically yes, but please don't. I've seen that code. It's not pretty.
The point isn't to pick a side. The point is to use the right tool for the job. And now you know how to tell which is which.
Start with functions. When they get awkward, consider classes. When classes feel forced, stick with functions. Your future self (at 2 AM, on energy drink number four) will thank you.
Still confused about when to use what? That's normal. It took me weeks to get comfortable with this. The best way to learn? Write the same thing both ways. You'll quickly feel which one fights you less. And that's your answer.