Programación Funcional: El Valor de la Inmutabilidad
La programación funcional disciplina la asignación. La inmutabilidad elimina condiciones de carrera, deadlocks y problemas de actualización concurrente.
Por qué importa
La característica definitoria de la programación funcional es la disciplina de no asignar valores. En un lenguaje puramente funcional, las variables no son variables — son valores nombrados que nunca cambian después de la asignación. Esto no es una limitación; es una garantía.
La visión arquitectónica de Martin es que todos los problemas más difíciles en sistemas concurrentes — condiciones de carrera, interbloqueos, bugs de actualización concurrente — surgen de múltiples hilos que mutan estado compartido. Si ningún estado se muta jamás, estos problemas no pueden ocurrir. La arquitectura se beneficia incluso en código no puramente funcional: las funciones que nunca modifican los datos que reciben son seguras de llamar desde cualquier hilo, en cualquier momento, cualquier número de veces. Son los bloques de construcción de sistemas que escalan sin miedo. La disciplina de la inmutabilidad no es solo una preferencia de estilo; es una estrategia de concurrencia integrada en la arquitectura.
✗El problema
Mutating shared data in place silently destroys the original state. In concurrent scenarios, two callers modifying the same list simultaneously produce unpredictable results.
Bad
def add_tax(items: list[dict], rate: float) -> None:
for item in items:
item["price"] = item["price"] * (1 + rate) # mutates caller's list!
cart = [{"name": "Book", "price": 20.0}, {"name": "Pen", "price": 5.0}]
add_tax(cart, 0.20)
# cart is permanently modified — original prices are gone
print(cart) # [{"name": "Book", "price": 24.0}, ...]
function addTax(items: CartItem[], rate: number): void {
items.forEach(item => {
item.price = item.price * (1 + rate); // mutates original array in place
});
}
const cart = [{ name: "Book", price: 20 }, { name: "Pen", price: 5 }];
addTax(cart, 0.20);
console.log(cart); // original prices destroyed — silent data loss
✓La solución
A pure function returns a new list without touching the original. The caller decides what to do with the result — the function makes no decisions for them.
Good
def add_tax(items: list[dict], rate: float) -> list[dict]:
return [
{**item, "price": round(item["price"] * (1 + rate), 2)}
for item in items
]
cart = [{"name": "Book", "price": 20.0}, {"name": "Pen", "price": 5.0}]
taxed = add_tax(cart, 0.20)
print(cart) # unchanged: [{"name": "Book", "price": 20.0}, ...]
print(taxed) # new list: [{"name": "Book", "price": 24.0}, ...]
interface CartItem { name: string; price: number; }
function addTax(items: CartItem[], rate: number): CartItem[] {
return items.map(item => ({
...item,
price: Math.round(item.price * (1 + rate) * 100) / 100,
}));
}
const cart = [{ name: "Book", price: 20 }, { name: "Pen", price: 5 }];
const taxed = addTax(cart, 0.20);
console.log(cart); // unchanged: [{ name: "Book", price: 20 }, ...]
console.log(taxed); // new array: [{ name: "Book", price: 24 }, ...]
💡Conclusión clave
Si una función modifica datos que no creó, pierdes la capacidad de razonar sobre el estado — y cada condición de carrera, interbloqueo y bug de actualización concurrente en la historia es consecuencia de esa pérdida.
🔧 Algunos ejercicios pueden tener errores. Si algo parece incorrecto, usa el botón Feedback (abajo a la derecha) para reportarlo — nos ayuda a corregirlo rápido.
Pista: Si una función modifica datos que no creó, pierdes la capacidad de razonar sobre el estado.
✗ Tu versión