Hablemos
Todos los textos
ousterhout principios arquitectura ingeniería 13 min

Ousterhout vs. Uncle Bob: el libro que tomó Clean Code y dijo "espera, así no"

Autor
Jesús E
Publicado
26 de abril de 2026

Hay una cosa peculiar que pasa cada cierto tiempo en los libros de software: alguien con mucha experiencia escribe un libro corto y pragmático que disputa de frente lo que se enseña como verdad. Pasó cuando Fred Brooks escribió No Silver Bullet en 1986 contra la fe en las metodologías. Y pasó otra vez en abril de 2018, cuando un profesor de Stanford autoeditó por Amazon 190 páginas que tranquilamente contradicen a Uncle Bob.

Ese libro se llama A Philosophy of Software Design. El profesor se llama John Ousterhout. Y si vas a leer un libro técnico este año, probablemente sea este.

Quién es Ousterhout (y por qué hay que escucharlo)

John Ousterhout lleva más de 40 años en computación. Pasó 14 años de profesor en UC Berkeley (1980s y comienzos de los 90s), después estuvo en Sun Microsystems Laboratories, fundó Scriptics y luego Electric Cloud (que CloudBees compró en 2019), y desde 2008 es profesor en Stanford —con la cátedra “Bosack-Lerner Professor of Engineering”— donde sigue enseñando.

Y entre todo eso, en 1988, mientras estaba en Berkeley, creó Tcl (Tool Command Language) y poco después Tk (su toolkit gráfico). Si nunca usaste Tcl/Tk directamente, no importa: los principios de diseño de aquellos lenguajes —embebibilidad, simplicidad de la sintaxis, control vs. configuración— marcaron a una generación entera de scripts y herramientas Unix. Ousterhout no es un teórico que nunca compiló nada. Construyó un lenguaje que se usó por décadas en astronomía, electrónica e instrumentación científica.

Logo de Tcl/Tk, el lenguaje creado por John Ousterhout en 1988
Logo Tcl/Tk · Diseño Laurent Demailly, 1998 · Tcl/Tk License

El libro nació en un salón de clases

A Philosophy of Software DesignAPoSD para los amigos— no salió del aire. Es el libro de texto del curso CS 190: Software Design Studio que Ousterhout imparte en Stanford. La estructura es la siguiente: los alumnos entregan código todas las semanas, Ousterhout lo lee personalmente, anota los problemas de diseño, y los discute en clase. Después de varios años haciendo eso, los patrones se volvieron evidentes y los puso por escrito.

Por eso el libro se siente distinto a otros tratados de diseño:

  • Es corto (190 páginas en la primera edición de 2018, 180 en la segunda de 2021).
  • Está autoeditado (Yaknyam Press, exclusivo en Amazon) — sin la maquinaria de una editorial grande.
  • Es muy concreto — cada idea viene con ejemplos sacados literalmente de proyectos de alumnos.

Y cuesta ~30 dólares. Es el mejor 30 que vas a gastar en software este año.

La idea central: la complejidad es la enemiga

Ousterhout abre el libro con una definición operativa que vale la pena memorizar:

“Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system.”

(Complejidad es cualquier cosa relacionada con la estructura de un sistema de software que lo hace difícil de entender o modificar.)

A Philosophy of Software Design, capítulo 2 (2018).

Ojo con la definición. No habla de líneas de código, ni de tamaño, ni de cantidad de clases. Habla de estructura — y de la estructura respecto a un humano que lo va a leer y modificar. Si un sistema es difícil de entender, es complejo, sin importar si es chico o grande.

Esa definición tiene tres síntomas concretos, que aparecen en distintos capítulos:

SíntomaQué significaEjemplo
Change amplificationUn cambio simple requiere tocar muchos lugaresCambiar el formato de una fecha y hay que tocar 17 archivos
Cognitive loadCuánto tiene que cargar tu cerebro para hacer un cambio”Tengo que recordar que esta función modifica un global y otra captura una lambda y…”
Unknown unknownsNo sabes que no sabes algo críticoCambias una función inocente y rompes un endpoint que jamás miraste

Si un sistema te tortura con cualquiera de estos tres, está complejo. Y la complejidad se acumula incrementalmente — no llega de golpe. Por eso es tan peligrosa: ningún cambio individual la justifica, pero la suma de cambios la genera.

El programador táctico vs el programador estratégico

Esta es probablemente la distinción más útil de todo el libro. Y aplica desde el primer día que cobras por escribir código:

Tactical programmer: “Their main focus is to get something working, such as a new feature or a bug fix. (…) You can’t avoid thinking about design issues at all, but minimizing them is the goal.”

(Su enfoque principal es hacer que algo funcione — un feature, un fix. No puedes evitar pensar en diseño del todo, pero minimizarlo es la meta.)

Strategic programmer: “Their primary goal is to produce a great design, which also happens to work.”

(Su meta principal es producir un gran diseño, que además funciona.)

Lo importante: ningún equipo es 100% táctico ni 100% estratégico. La pregunta es el ratio. Ousterhout recomienda invertir entre 10% y 20% del tiempo de desarrollo en mejoras estructurales — refactoring, eliminación de redundancias, mejor nombramiento, simplificación de APIs.

Argumenta con un cálculo crudo y demoledor: si dedicas 10% de cada feature a mejorar diseño, tu velocidad crece después de 6–12 meses, porque la base se vuelve más fácil de modificar. Si dedicas 0%, tu velocidad decrece trimestre a trimestre, porque cada cambio cuesta más que el anterior.

“Working code isn’t enough.”

(Que funcione no es suficiente.)

A Philosophy of Software Design, capítulo 3.

Esa frase es para tatuársela cuando tu PM te apura. Sí, funciona. Pero si en tres meses nadie puede tocarlo sin romper algo, no funcionó: lo cargaste a la cuenta del próximo trimestre con intereses.

La idea más útil del libro: módulos profundos

Si Ousterhout aporta una sola idea original al canon de diseño de software, es esta:

Los módulos deben ser profundos.

Un módulo profundo es uno que tiene una interfaz pequeña (poca superficie expuesta hacia afuera) y mucha funcionalidad escondida (mucha sustancia adentro). Un módulo shallow (superficial) es lo contrario: interfaz grande, poca funcionalidad — pasas más tiempo entendiendo cómo llamarlo que el trabajo que hace.

Módulo shallow — malo

Interfaz enorme

(15 funciones)

Poca funcionalidad

(50 líneas)

Módulo profundo — bueno

Interfaz pequeña

(2-3 funciones)

Mucha funcionalidad

(500+ líneas)

Ejemplo del libro: la función open() de Unix. Recibe 3 argumentos (un path, unas flags, un mode). Internamente: maneja permisos, cache, file descriptors, locking, semánticas de NFS, etc. Eso es un módulo profundo — la complejidad está adentro, contenida.

Contraejemplo del libro: las clases BufferedInputStream, FileInputStream, DataInputStream de Java. Cada una hace muy poco. Para leer un entero de un archivo binario tienes que componer tres clases, cada una agregando una capita. La interfaz total se vuelve enorme, y la funcionalidad agregada es modesta. Eso es shallow.

“The best modules are those whose interfaces are much simpler than their implementations.”

(Los mejores módulos son aquellos cuyas interfaces son mucho más simples que sus implementaciones.)

Información oculta (information hiding) es el principio que produce módulos profundos. Esconde el máximo posible detrás de la interfaz. Si un detalle se “filtra” (information leakage) — si dos módulos saben del mismo detalle de implementación — es un smell de mal diseño.

Donde Ousterhout discute con Uncle Bob

Aquí viene la parte más entretenida del libro, y la razón por la que conviene leerlo justo después de Clean Code. Hay al menos cuatro puntos donde Ousterhout disiente abiertamente:

1. Funciones pequeñas

Uncle Bob (Clean Code, 2008)Ousterhout (APoSD, 2018)
“The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.""Length by itself is rarely a good reason to split up a method. (…) Splitting up a method introduces additional interfaces, which add to complexity.”

Traducción: Bob dice que las funciones de 4–5 líneas son la meta. Ousterhout dice que dividir una función produce interfaces nuevas, y cada interfaz nueva es complejidad adicional. Si una función es larga pero lineal y clara, partirla puede empeorar la lectura.

La sutileza: Ousterhout no defiende funciones de 500 líneas. Defiende partir cuando hay una abstracción real que ganar, no cuando la función “se siente larga”. El criterio no es la longitud, es la profundidad del módulo resultante.

2. Comentarios

Uncle BobOusterhout
”Comments are, at best, a necessary evil. (…) Every time you write a comment, you should grimace and feel the failure of your ability of expression.""Most software developers don’t write enough comments. (…) Comments make it possible to capture information that wasn’t obvious from the code, such as the developer’s intent.”

Bob: los comentarios son fracasos del nombramiento. Ousterhout: el código nunca puede expresar todo — la intención del autor, las restricciones que se descartaron, los porqués no obvios. Para eso son los comentarios. Bien hechos, son irreemplazables.

Ousterhout dedica un capítulo entero (capítulo 13) a cómo escribir comentarios útiles. Dos reglas:

  • No repitas el código. Si el comentario dice lo mismo que el nombre de la función, sobra.
  • Comenta lo que el código no puede decir. Razones de diseño, invariantes, decisiones descartadas, advertencias.

Ejemplo de comentario malo: // incrementa i arriba de i++. Ejemplo bueno: // nota: este orden importa porque liberación del lock debe ocurrir antes de notificar al consumer; lo opuesto causa deadlock con TaskQueue. Eso, código no lo dice solo.

3. Clases pequeñas, muchas

Uncle Bob defiende clases chicas, una responsabilidad por clase, y descomponer agresivamente. Ousterhout llama a este patrón —cuando se exagera— classitis:

“Classitis: the mistaken view that ‘classes are good, so more classes are better’.”

(Classitis: la idea equivocada de que ‘las clases son buenas, así que más clases es mejor’.)

Es probablemente el término técnico más sarcástico del libro. La crítica es directa: dividir un dominio en 30 clases chicas no lo hace más fácil de entender — lo hace más fácil de fragmentar. Cada clase es una interfaz nueva. Cada interfaz es complejidad. La pregunta correcta no es “¿esta clase tiene una sola responsabilidad?” sino “¿esta abstracción es lo suficientemente profunda para justificar su existencia?“

4. Diseño emergente vs diseño deliberado

Uncle Bob —y la tradición XP/TDD— defiende que el diseño emerge de seguir SOLID + tests + refactoring. Ousterhout es más prescriptivo: hay que diseñar deliberadamente, sentarse a pensar la abstracción antes de escribirla, y revisar el diseño cuando se vuelve oscuro.

Su técnica más concreta para esto: Design It Twice (capítulo 11):

“For any major design decision, consider at least two different approaches. (…) The second design will almost certainly be better than the first.”

(Para cualquier decisión mayor de diseño, considera al menos dos enfoques distintos. El segundo casi siempre va a ser mejor que el primero.)

Cuando él diseñó Tk en los 90s, dice abiertamente que el primer diseño que pensó era inferior al segundo. Lo verificó él mismo. Y desde entonces lo aplica en cada API que diseña.

El debate entre los dos es público. Ousterhout y Robert C. Martin lo discutieron por escrito de forma colaborativa entre septiembre 2024 y febrero 2025 en un repositorio público de GitHub: johnousterhout/aposd-vs-clean-code. Si te interesa el tema, esa es lectura obligatoria — son dos figuras tope del oficio explicando dónde están de acuerdo y dónde no, sin sangre, con respeto mutuo. Spoiler: cada uno cede en algo, y los dos siguen pensando que el otro está parcialmente equivocado.

Otras dos ideas grandes del libro

Define errors out of existence

Capítulo 10. Idea principal: muchas excepciones en software se podrían eliminar diseñando mejor las APIs. En vez de manejar el error, arregla la API para que el error no exista.

Ejemplo del libro, sacado de su trabajo en Tcl: el comando unset de Tcl originalmente lanzaba error si la variable no existía. Pero ¿cuál es la consecuencia útil de pedir borrar algo que ya no existe? Ninguna — el resultado deseado ya está logrado. Decisión de diseño: hacer que unset sea idempotente y silencioso. Decenas de líneas de manejo de errores eliminadas, en miles de scripts.

Otros ejemplos prácticos:

  • En vez de tener findUser() que lanza UserNotFoundException, retorna null (o Optional.empty()) — el caller decide.
  • En vez de exigir que cierres un recurso explícitamente y manejar el error si no, usa try-with-resources / defer y elimina la categoría completa.
  • En vez de validar input en 17 lugares, valida una vez en la frontera y de ahí adentro confía.

“Exceptions are one of the worst sources of complexity in software systems.”

A Philosophy of Software Design, capítulo 10.

Es una afirmación fuerte y, otra vez, contraintuitiva. Pero si llevas años escribiendo software, sabes que es verdad: la rama feliz es 20% del código, el manejo de errores es el otro 80%. Reducir ese 80% por diseño te ahorra fortunas.

Pull complexity downward

Si la complejidad es inevitable —y casi siempre lo es—, hazte cargo tú adentro del módulo, no la pases hacia los usuarios. Un módulo bien diseñado es uno que absorbe complicación para que sus clientes vivan en un mundo más simple.

Ejemplo: configuración por defecto. Una API mal diseñada exige que el cliente especifique 9 parámetros. Una API bien diseñada los tiene defaults sensatos y deja que el cliente sobreescriba sólo lo que necesita.

El playbook pragmático

Si tuvieras que aplicar Ousterhout sin volverte el opuesto insoportable de Uncle Bob, esto es lo que vale conservar:

IdeaCuándo aplicar
Estratégico ~15% del tiempoSiempre. No es lujo, es interés compuesto
Módulos profundos > muchos shallowSiempre que estés diseñando una abstracción
Funciones largas pero claras > muchas chiquitas con interfaces extraCuando la división no produce abstracción real
Comentarios sobre el “por qué”Decisiones, restricciones, invariantes, advertencias
Define errors out of existenceCada vez que una API tenga 3+ casos de error
Design it twiceDecisiones de diseño que afectan más de 1 archivo
Pull complexity downwardAPIs públicas — absorbe adentro lo difícil
Cuidado con classitisCuando empieces a sentir que necesitas factory para tu factory

El balance honesto: Bob + Ousterhout, no Bob vs. Ousterhout

Escribir esto como “Ousterhout demolió a Uncle Bob” sería tan malo como pretender que Bob es la última palabra. La verdad es más útil: los dos son correctos en distintos contextos, y es trabajo del programador entender cuándo cuál.

  • Si tu equipo nunca refactoriza y produce funciones de 400 líneas con cinco niveles de anidamiento, Uncle Bob te hace falta. Las reglas de Bob son medicina para equipos sin disciplina.
  • Si tu equipo ya internalizó “funciones chicas + clases con SRP” y empieza a producir código fragmentado en 80 archivos para hacer cualquier cosa, Ousterhout te hace falta. APoSD es medicina para equipos sobre-disciplinados que confunden granularidad con calidad.

Conozco equipos que necesitan exactamente lo opuesto entre sí. Es el mismo oficio, en distintas etapas. Bob es el libro que cura el desorden; Ousterhout es el que cura el orden mal entendido.

La frase de Ousterhout que vale guardar

Si me piden quedarme con una sola frase del libro:

“The greatest limitation in writing software is our ability to understand the systems we are creating.”

(La mayor limitación al escribir software es nuestra capacidad de entender los sistemas que creamos.)

A Philosophy of Software Design, capítulo 1.

Esa frase es más cierta cada año. Los sistemas crecen, los equipos rotan, las dependencias se multiplican, y nuestra cabeza sigue siendo la misma. Cualquier práctica que reduzca lo que tu cerebro tiene que cargar para hacer un cambio vale la pena. Eso es Ousterhout en una línea.

Lecturas que sí valen la pena

  • John Ousterhout (2018, 2ª ed. 2021), A Philosophy of Software Design (Yaknyam Press, autoeditado en Amazon) — el libro de este post. 190 páginas. Cómpralo.
  • John Ousterhout & Robert C. Martin (2024-2025), aposd-vs-clean-code — el debate público entre los dos, en GitHub, organizado por temas. Lectura obligatoria si te interesa el oficio.
  • Stanford CS 190: Software Design Studio (curso público) — el curso de donde nació el libro, con notas y materiales abiertos.
  • John Ousterhout (1998), “Scripting: Higher-Level Programming for the 21st Century” — su paper clásico sobre la división entre lenguajes de sistema y lenguajes de scripting. Sigue siendo relevante 28 años después.
  • Fred Brooks (1986), “No Silver Bullet” — el ensayo de 30 años antes que dice esencialmente lo mismo: la complejidad es esencial, no accidental.
  • David Parnas (1972), “On the Criteria to Be Used in Decomposing Systems into Modules” — el paper donde nace el concepto de information hiding. 12 páginas, todavía cita-de-fuente directa.

Y si te llevas una sola idea de todo el post: diseñar buen software no es escribir poco código, ni escribir muchas clases pequeñas. Es reducir la cantidad de cosas que la próxima persona tiene que cargar en su cabeza para hacer un cambio. Bob te enseña parte de eso. Ousterhout te enseña la parte que a Bob se le escapó.

Devolvámosle tiempo a su equipo.

Si alguna operación de su organización le está costando horas que podrían invertirse mejor, conversémoslo.