Functional programming isn't just academic — it makes code more predictable, testable, and maintainable. Here's how we apply FP principles at Google.
Core Principles
- Pure Functions: Same input → same output, no side effects
- Immutability: Never mutate data, create new copies
- Function Composition: Build complex operations from simple functions
Higher-Order Functions
// Map: transform each element
const prices = [10, 20, 30];
const withTax = prices.map(p => p * 1.18);
// Filter: select elements
const expensive = prices.filter(p => p > 15);
// Reduce: accumulate to single value
const total = prices.reduce((sum, p) => sum + p, 0);
// Chaining
const result = users
.filter(u => u.active)
.map(u => u.name)
.sort();Composition
const compose = (...fns) => (x) => fns.reduceRight((acc, fn) => fn(acc), x);
const pipe = (...fns) => (x) => fns.reduce((acc, fn) => fn(acc), x);
const processUser = pipe(
validateEmail,
normalizeUsername,
hashPassword,
createUser
);
const user = processUser(rawInput);Currying
const multiply = (a) => (b) => a * b;
const double = multiply(2);
const triple = multiply(3);
double(5); // 10
triple(5); // 15
// Practical currying
const hasPermission = (role) => (action) => (resource) =>
permissions[role]?.[resource]?.includes(action) ?? false;
const canAdminDelete = hasPermission("admin")("delete");
canAdminDelete("posts"); // trueImmutable Updates
// Array operations
const added = [...items, newItem];
const removed = items.filter(i => i.id !== targetId);
const updated = items.map(i => i.id === targetId ? { ...i, ...changes } : i);
// Nested object updates
const updatedState = {
...state,
user: {
...state.user,
address: { ...state.user.address, city: "Mumbai" }
}
};When NOT to Use FP
- Performance-critical loops (for loop > reduce for large datasets)
- When mutation is clearer (sorting in place)
- When the team isn't familiar with FP concepts