Hace poco me encontré revisando algunos de los proyectos en los que trabajé durante los últimos años. Algunos siguen activos, otros cambiaron bastante respecto de la idea original y unos cuantos nunca llegaron a ver la luz. Mientras recorría código viejo, notas de producto y capturas de pantallas de versiones anteriores, me llamó la atención algo curioso: casi no recordaba los detalles técnicos. Había funciones, clases y componentes enteros que había olvidado por completo. Sin embargo, recordaba perfectamente muchas de las decisiones que terminaron dando forma al producto.

Cuando pienso en proyectos como Founder, AppGrid o Blest, mi memoria no vuelve al código. Vuelve a las iteraciones. Recuerdo ideas que parecían fundamentales y que terminaron desapareciendo pocas semanas después. Recuerdo funcionalidades que llevaban días de trabajo y que eliminé sin demasiada ceremonia porque agregaban complejidad sin aportar suficiente valor. También recuerdo conversaciones, observaciones y pequeños descubrimientos que cambiaron la dirección del producto mucho más que cualquier decisión técnica importante.

Durante mucho tiempo pensé que construir software consistía principalmente en implementar cosas. Es una idea bastante natural cuando uno empieza su carrera como desarrollador. Hay una tendencia a asociar el progreso con lo que se agrega: una nueva pantalla, una nueva integración, una nueva capacidad. Sin embargo, después de participar en suficientes proyectos, empecé a notar que una parte importante del trabajo ocurre antes de escribir una sola línea de código y otra parte igual de importante ocurre cuando uno decide qué no construir.

En Founder, por ejemplo, hubo varias mecánicas que parecían interesantes cuando las imaginaba. Algunas incluso llegaron a funcionar técnicamente. El problema era que hacían el juego más difícil de entender y no necesariamente más divertido de jugar. Algo parecido me ocurrió en AppGrid con ciertas ideas relacionadas con la organización y distribución de aplicaciones. Sobre el papel tenían sentido. En la práctica agregaban pasos, conceptos y explicaciones que terminaban alejándose del objetivo principal. El desafío no era lograr que funcionaran. El desafío era reconocer que el producto estaba mejor sin ellas.

Esa es una parte del trabajo que pocas veces resulta visible. Los usuarios solamente ven la versión final. No ven las alternativas que existieron antes, los caminos descartados o las discusiones internas que llevaron a una determinada decisión. Cuando una experiencia se siente simple, normalmente hay una gran cantidad de trabajo escondida detrás de esa simplicidad. No porque la implementación haya sido particularmente difícil, sino porque alguien dedicó tiempo a cuestionar cada elemento y a preguntarse si realmente era necesario.

Quizás por eso me cuesta medir el progreso de un producto por la cantidad de código escrito. Hay semanas en las que escribo mucho código y siento que apenas avancé. También hay días en los que elimino funcionalidades, simplifico un flujo o replanteo una idea y termino el día con la sensación de haber mejorado significativamente el producto. La diferencia está en que el verdadero trabajo no siempre consiste en construir más cosas. Muchas veces consiste en entender mejor el problema.

A medida que pasan los años, recuerdo cada vez menos las implementaciones específicas y cada vez más el proceso que llevó a ciertas decisiones. Recuerdo cambios de dirección, hipótesis equivocadas, simplificaciones importantes y momentos en los que algo finalmente hizo clic después de varias iteraciones. Tal vez sea porque, al final, los productos no son solamente una colección de funcionalidades. Son el resultado acumulado de miles de pequeñas decisiones tomadas a lo largo del camino.

Y cuando miro hacia atrás, son esas decisiones las que permanecen mucho después de haber olvidado el código que las hizo posibles.