- The Copy-Paste Disaster
- Functions: Your Code’s Bento Box Maker
- Function Anatomy: Like Making Bubble Tea
- Parameters vs Arguments: The Coffee Order Analogy
- Return Values: Getting Something Back
- Scope: The Coffee Shop WiFi Password
- Pure Functions: The Consistent Barista
- Higher-Order Functions: The Coffee Shop Manager
- Callbacks: The “Text Me When Ready” Pattern
- Real-World Function Patterns
- Common Function Mistakes (I’ve Made Them All)
- Functions in Different Paradigms
- Debugging Functions: My Survival Kit
- Final Thoughts: Functions Changed Everything
Functions: Why I Stopped Copy-Pasting Code at 3 AM
It’s midnight at Victrola Coffee on 15th Ave. My screen is filled with what looks like the same 20 lines of code repeated eight times with tiny variations. My bubble tea is warm (gross), my eyes are burning, and I’m questioning my life choices. Then my mentor at Microsoft walked by, took one look, and said: “Maya, ever heard of functions?”
That night changed how I write code forever. Let me share what I learned about functions, minus the warm bubble tea experience.
The Copy-Paste Disaster
Here’s what my code looked like before I understood functions:
// Calculating order total for user 1
let user1Subtotal = 89.99;
let user1Tax = user1Subtotal * 0.101; // Seattle tax rate
let user1Shipping = 5.99;
let user1Total = user1Subtotal + user1Tax + user1Shipping;
// Calculating order total for user 2
let user2Subtotal = 134.50;
let user2Tax = user2Subtotal * 0.101;
let user2Shipping = 5.99;
let user2Total = user2Subtotal + user2Tax + user2Shipping;
// ... and on and on for 50 users
See the problem? I was basically a human copy machine. Worse, when Seattle changed the tax rate, I had to update it in 50 places. I missed three. Customers were not happy.
Functions: Your Code’s Bento Box Maker
Remember how I explained variables as labeled boxes? Functions are like the machine that makes those boxes. You define the process once, then use it whenever you need it.
# Python - clean and readable
def calculate_order_total(subtotal, tax_rate=0.101, shipping=5.99):
"""Calculate total with Seattle's tax rate"""
tax = subtotal * tax_rate
total = subtotal + tax + shipping
return total
# Use it anywhere!
user1_total = calculate_order_total(89.99)
user2_total = calculate_order_total(134.50)
user3_total = calculate_order_total(45.00, shipping=0) # Free shipping promo!
// JavaScript - flexible and everywhere
function calculateOrderTotal(subtotal, taxRate = 0.101, shipping = 5.99) {
const tax = subtotal * taxRate;
const total = subtotal + tax + shipping;
return total;
}
// Or as an arrow function (my preference)
const calculateOrderTotal = (subtotal, taxRate = 0.101, shipping = 5.99) => {
const tax = subtotal * taxRate;
return subtotal + tax + shipping;
};
// TypeScript - type-safe (saved me at the fintech startup)
function calculateOrderTotal(
subtotal: number,
taxRate: number = 0.101,
shipping: number = 5.99
): number {
const tax = subtotal * taxRate;
return subtotal + tax + shipping;
}
Function Anatomy: Like Making Bubble Tea
I always explain functions using bubble tea making:
- Function Name: What you’re making (
makeBubbleTea
) - Parameters: Ingredients you need (
teaBase
,sweetness
,toppings
) - Function Body: The recipe steps
- Return Value: The finished drink
function makeBubbleTea(teaBase, sweetnessLevel = 50, toppings = ['pearls']) {
// The recipe (function body)
const tea = brewTea(teaBase);
const sweetenedTea = addSweetness(tea, sweetnessLevel);
const finalDrink = addToppings(sweetenedTea, toppings);
// What you get back (return value)
return finalDrink;
}
// Using the function
const myUsualOrder = makeBubbleTea('oolong', 50, ['pearls', 'pudding']);
const healthyVersion = makeBubbleTea('green', 25, ['aloe']);
Parameters vs Arguments: The Coffee Order Analogy
This confused me until I thought of it like ordering coffee:
- Parameters: The menu options (size, type, milk)
- Arguments: Your actual order (grande, latte, oat milk)
# Parameters are in the function definition
def order_coffee(size, type, milk='whole'): # size, type, milk are parameters
return f"{size} {type} with {milk} milk"
# Arguments are what you pass in
my_order = order_coffee('grande', 'latte', 'oat') # 'grande', 'latte', 'oat' are arguments
Return Values: Getting Something Back
Functions without return values are like ordering food and walking away without it:
// No return - just does something
function logUserActivity(action) {
console.log(`User performed: ${action}`);
// No return statement - returns undefined
}
// With return - gives you something back
function calculateTip(billAmount, tipPercent = 20) {
const tipAmount = billAmount * (tipPercent / 100);
return tipAmount; // This comes back to you
}
const tip = calculateTip(45.50); // tip = 9.10
Scope: The Coffee Shop WiFi Password
Scope in functions is like WiFi passwords at coffee shops - what’s available inside stays inside:
def coffee_shop_coding():
wifi_password = "FlatWhite2025" # Only exists in this function
coffee_count = 3
def take_break():
# Can access parent function's variables
print(f"On coffee #{coffee_count}, wifi: {wifi_password}")
take_break()
# print(wifi_password) # Error! Not accessible outside
# Real example from my fintech work
def process_payment(amount):
transaction_id = generate_id() # Only this function knows this ID
def log_transaction():
# Nested function can access transaction_id
database.log(transaction_id, amount)
log_transaction()
return transaction_id # Now the outside world can have it
Pure Functions: The Consistent Barista
My favorite coffee shop has this one barista who makes the perfect flat white every single time. Same ingredients, same result. That’s a pure function:
// Pure function - predictable, no surprises
const calculateDiscount = (price, discountPercent) => {
return price * (1 - discountPercent / 100);
};
// Always same input = same output
calculateDiscount(100, 20); // Always 80
calculateDiscount(100, 20); // Always 80
// Impure function - depends on external state
let globalDiscount = 20;
const calculateDiscountImpure = (price) => {
return price * (1 - globalDiscount / 100); // Uses external variable
};
Higher-Order Functions: The Coffee Shop Manager
Higher-order functions are like managers - they work with other functions:
# Function that takes another function
def repeat_action(action, times):
"""Like hitting snooze multiple times"""
for i in range(times):
action()
def drink_coffee():
print("*sips coffee*")
# Pass function as argument
repeat_action(drink_coffee, 3) # *sips coffee* x3
# Function that returns a function
def create_multiplier(factor):
"""Factory for multiplication functions"""
def multiplier(number):
return number * factor
return multiplier
double = create_multiplier(2)
triple = create_multiplier(3)
print(double(10)) # 20
print(triple(10)) # 30
Callbacks: The “Text Me When Ready” Pattern
Callbacks are like giving the barista your number to text when your order’s ready:
// Callback example - common in JavaScript
function processPayment(amount, onSuccess, onError) {
// Simulate payment processing
setTimeout(() => {
if (amount > 0) {
onSuccess(`Payment of $${amount} processed`);
} else {
onError('Invalid amount');
}
}, 1000);
}
// Using callbacks
processPayment(
99.99,
(message) => console.log('Success:', message),
(error) => console.log('Error:', error)
);
Real-World Function Patterns
The Validation Pattern
From my fintech days - validate everything:
interface ValidationResult {
isValid: boolean;
errors: string[];
}
function validatePaymentAmount(amount: number): ValidationResult {
const errors: string[] = [];
if (amount <= 0) {
errors.push('Amount must be positive');
}
if (amount > 10000) {
errors.push('Amount exceeds maximum limit');
}
if (!Number.isFinite(amount)) {
errors.push('Amount must be a valid number');
}
return {
isValid: errors.length === 0,
errors
};
}
The Factory Pattern
Creating similar objects with functions:
// User factory function
function createUser(name, email, role = 'user') {
return {
id: Date.now(),
name,
email,
role,
createdAt: new Date(),
isActive: true,
login() {
console.log(`${this.name} logged in`);
}
};
}
const maya = createUser('Maya Chen', '[email protected]', 'developer');
The Memoization Pattern
Caching expensive calculations:
def memoize(func):
cache = {}
def wrapper(*args):
if args in cache:
print(f"Cache hit for {args}")
return cache[args]
result = func(*args)
cache[args] = result
return result
return wrapper
@memoize
def expensive_calculation(n):
print(f"Calculating for {n}...")
# Simulate expensive operation
return sum(i ** 2 for i in range(n))
Common Function Mistakes (I’ve Made Them All)
Forgetting to Return
The number of times I’ve done this at 2 AM:
function calculateTotal(items) {
const total = items.reduce((sum, item) => sum + item.price, 0);
// Forgot to return! Function returns undefined
}
const orderTotal = calculateTotal(cartItems); // undefined 😭
Modifying Parameters
Learned this the hard way at Amazon:
# Bad - modifies the original array
def add_tax_to_prices_bad(prices):
for i in range(len(prices)):
prices[i] *= 1.1 # Modifies original!
return prices
# Good - returns new array
def add_tax_to_prices_good(prices):
return [price * 1.1 for price in prices]
Too Many Parameters
My code review nightmare:
// Bad - too many parameters
function createOrder(userId, productId, quantity, price, discount,
shipping, tax, currency, paymentMethod, notes) {
// ...
}
// Good - use an object
function createOrder(orderDetails) {
const {
userId,
productId,
quantity,
price,
discount = 0,
shipping = 'standard',
// ... with defaults
} = orderDetails;
}
Functions in Different Paradigms
Functional Style (My Weekend Projects)
const prices = [29.99, 45.50, 12.00, 78.25];
// Functional approach - chain operations
const finalPrices = prices
.map(price => price * 1.1) // Add tax
.filter(price => price < 50) // Only affordable items
.reduce((sum, price) => sum + price, 0); // Total
Object-Oriented Style (My Day Job)
class PaymentProcessor:
def __init__(self, tax_rate=0.101):
self.tax_rate = tax_rate
def calculate_total(self, subtotal, shipping=5.99):
tax = subtotal * self.tax_rate
return subtotal + tax + shipping
def process_payment(self, amount, payment_method):
# Process the payment
pass
Debugging Functions: My Survival Kit
function debuggableFunction(input) {
console.log('Input:', input); // See what comes in
const step1 = processStep1(input);
console.log('After step 1:', step1);
const step2 = processStep2(step1);
console.log('After step 2:', step2);
const result = finalProcess(step2);
console.log('Final result:', result); // See what goes out
return result;
}
Final Thoughts: Functions Changed Everything
That night at Microsoft, learning about functions, was like discovering I’d been building houses with my bare hands when power tools existed. Functions transformed my code from a copy-paste nightmare into organized, reusable, testable pieces.
Now, whether I’m processing millions of transactions at the fintech startup or building a side project at a Capitol Hill coffee shop, functions are my foundation. They’re not just about avoiding repetition - they’re about thinking in terms of small, focused, composable pieces.
Start simple. Take that repeated code and wrap it in a function. Name it clearly. Make it do one thing well. Before you know it, you’ll be writing functions in your sleep (literally - I once dreamed in Python functions).
Remember: every expert was once a beginner who didn’t know what return
meant. Keep practicing, keep building, and definitely keep your bubble tea cold.
Currently writing this from Analog Coffee in Capitol Hill, where the wifi is fast and the cortado is perfect. If you’ve got function questions or want to share your “aha!” moment, find me @maya_codes_pnw. May your functions be pure and your callbacks always resolve! ☕
Add Comment
No comments yet. Be the first to comment!