Mi método personal para desarrollar software rápido
(evanhahn.com)- Encontrar el equilibrio entre la perfección y la velocidad no es fácil, pero lo importante es lograr una calidad adecuada según el contexto y cumplir con los plazos
- Suele ser efectivo avanzar primero con un borrador inicial y luego mejorar la calidad del código
- Relajar los requisitos o reducir exigencias excesivas puede mejorar la velocidad y la eficiencia
- Hace falta el hábito de evitar distracciones y hacer commits frecuentes en unidades pequeñas, manteniendo el foco en lo esencial
- Hay habilidades concretas que ayudan a desarrollar más rápido, como leer código, modelado de datos, scripting, debugging y preferencia por funciones puras
“¿Qué tan bueno debe ser el código?” – Criterios de calidad y decisiones realistas
- Al principio, quería que todo el código fuera perfecto
- Soñaba con funciones completamente probadas, nombres de variables elegantes, abstracciones claras y código sin ningún bug
- Pero con el tiempo aprendí la realidad de que “no existe una única respuesta correcta”
- La calidad de código necesaria cambia según la situación
- Game jam de 24 horas: no hace falta que el código terminado sea impecable ni esté libre de errores
- Lo más importante es sacar algo funcional dentro del tiempo limitado
- Software para marcapasos: un solo error puede poner en riesgo la vida de una persona
- La máxima confiabilidad y seguridad son indispensables
- La mayoría de los proyectos están entre esos dos extremos
- Algunas empresas exigen entregas rápidas y toleran ciertos bugs
- Algunos proyectos exigen alta calidad, pero tienen cronogramas holgados
- En el trabajo real, es importante saber identificar ese equilibrio
- Primero hay que entender qué considera el equipo como “suficientemente bueno (good enough)”
- Revisar juntos criterios prácticos, como el rango de bugs aceptables o qué cosas pueden no ser perfectas
- Mi criterio personal es
- “Alcanzar una calidad de 8 sobre 10 dentro del plazo”
- El código cumple bien su propósito y no tiene problemas críticos, aunque puede conservar detalles menores
- Lo más importante es entregar a tiempo
- Aun así, este criterio también se ajusta de forma flexible según el contexto del proyecto
- A veces vale la pena buscar la perfección aunque se retrase el calendario,
- y otras veces tiene más valor terminar rápido aunque el nivel de acabado sea menor
- “Alcanzar una calidad de 8 sobre 10 dentro del plazo”
Rough drafts – uso práctico y ventajas de los borradores y prototipos
- En desarrollo de software, igual que en escritura, hacer un borrador inicial (
rough draft,spike,walking skeleton) es muy útil - La idea es implementar el borrador lo más rápido posible y después pulirlo hasta convertirlo en una solución terminada
- Mi código de borrador está lleno de bugs: pruebas fallando, comentarios TODO por todas partes, excepciones sin manejar, abuso de print/log,
sin considerar rendimiento, mensajes de commit WIP, paquetes innecesarios, código repetido, hardcoding, advertencias del linter y más; es un desastre - Puede parecer un proceso ineficiente, pero el objetivo es llegar a “un estado donde al menos se pueda entender la esencia del problema”
- Obviamente, ese código en borrador no se manda a producción; antes del despliegue real siempre se depura
(a veces en el equipo presionan para enviar el borrador tal cual, pero intento resistirme lo más posible) -
Ventajas principales del enfoque de borrador
- Hace visibles rápidamente los “unknown unknowns”
- Es mucho mejor descubrir obstáculos desconocidos temprano, en la fase de prototipo, que después de haber construido algo que luego habrá que desechar
- Muchos problemas desaparecen naturalmente mientras se hace el prototipo
- Funciones lentas o estructuras equivocadas muchas veces dejan de ser necesarias más adelante, así que se evita desperdiciar tiempo
- No hace falta invertir demasiado pronto en optimización o testing
- Mejora la concentración
- Evita distracciones como refactors innecesarios, dudas de naming o arreglar otras partes del código,
y permite enfocarse solo en el problema actual
- Evita distracciones como refactors innecesarios, dudas de naming o arreglar otras partes del código,
- Evita la abstracción prematura innecesaria
- Al intentar producir rápido una solución que funcione, se reduce la tentación de crear abstracciones innecesarias para el futuro
- El foco se mantiene en el problema inmediato y se evita un diseño innecesariamente complejo
- Facilita comunicar claramente el progreso
- Con un borrador es posible estimar con más precisión cuánto falta
- Mostrar algo funcionando desde temprano acelera el feedback de las partes interesadas y los cambios de dirección
- Hace visibles rápidamente los “unknown unknowns”
-
Cómo operar este enfoque en la práctica
- Las decisiones difíciles de revertir (
binding decision) deben probarse sí o sí en la etapa de borrador- Ej.: lenguaje, framework, esquema de DB y otras decisiones de alto nivel deben validarse al inicio
- Toda solución temporal o hack debe registrarse obligatoriamente con comentarios TODO o similares
- En la etapa de
polish, se revisa todo con cosas comogit grep TODOpara corregirlo
- En la etapa de
- Desarrollar en orden Top-Down (de arriba hacia abajo)
- Empezar por el scaffold de UI, API y formas de uso; para la lógica interna se permiten hardcoding o implementaciones temporales
- En la práctica, la lógica de capas inferiores suele cambiar cuando se define la UI o la experiencia de uso, así que conviene empezar por la capa superior
- Implementar todo perfecto desde abajo para luego adaptarlo arriba es ineficiente
- Separar los cambios pequeños en parches distintos
- Si durante el borrador aparece la necesidad de mejorar el codebase o actualizar dependencias,
conviene separar esa parte en un PR/commit aparte y aplicarla rápido - Así se reduce la complejidad del cambio total y se acelera la revisión e integración
- Si durante el borrador aparece la necesidad de mejorar el codebase o actualizar dependencias,
- Las decisiones difíciles de revertir (
Referencia: “Tira tu primer borrador de código”, “El mejor sistema simple por ahora”, “YAGNI (You Aren’t Gonna Need It)”
Intentar cambiar los requisitos
- Se enfatiza el principio de que hacer menos es más rápido y más fácil
- En el trabajo real, siempre pienso si es posible relajar los requisitos de una tarea dada
- Preguntas de ejemplo:
- ¿Se pueden unir varias pantallas en una sola?
- ¿De verdad hace falta cubrir todos los edge cases complicados?
- Si hay que soportar 1000 entradas, ¿bastaría con soportar solo 10?
- ¿Se puede reemplazar por un prototipo en vez de una versión terminada?
- ¿Se puede simplemente eliminar esta funcionalidad?
- Preguntas de ejemplo:
- Este enfoque mejora la velocidad y la eficiencia del desarrollo
- También intento que la cultura organizacional avance poco a poco hacia un ritmo más lento y razonable
- Los pedidos de cambios repentinos y grandes no suelen funcionar bien
- El ambiente cambia poco a poco con propuestas graduales y nuevas formas de discusión
Evitar la distracción en el código (Distraction)
- No solo el entorno externo (notificaciones, reuniones), sino también desviarse hacia cosas irrelevantes mientras se programa es una gran fuente de interrupción
- A mí también me pasa: empiezo arreglando un bug, termino desarmando algo totalmente ajeno, y la tarea original se pospone
- Dos prácticas concretas:
- Poner un temporizador: darle un límite de tiempo a cada tarea y, cuando suene la alarma, revisar el estado actual
- Sirve para llamar la atención cuando algo está tomando más tiempo del esperado
- Si además haces un
git commital sonar la alarma, también se siente una pequeña sensación de logro - (Este método también ayuda a practicar la estimación de tiempos)
- Pair programming: trabajar con otra persona reduce los desvíos innecesarios y ayuda a mantener el foco
- Poner un temporizador: darle un límite de tiempo a cada tarea y, cuando suene la alarma, revisar el estado actual
- Para algunos desarrolladores evitar estas distracciones es algo natural, pero para mí requiere concentración consciente y formar el hábito
Cambios pequeños, dividir en partes pequeñas
- Antes tuve un jefe que promovía parches grandes y cambios extensos, pero
en la práctica descubrí que eso es muy ineficiente - Siento que un diff pequeño y enfocado casi siempre es mejor
- Cuesta menos escribirlo
- El code review es más fácil y más rápido, baja el cansancio de los compañeros y mis errores se detectan con más facilidad
- Si surge un problema, hacer rollback es más fácil y más seguro
- Como el alcance del cambio es pequeño, también baja el riesgo de introducir bugs nuevos
- Incluso las funciones grandes o nuevas se construyen como acumulación de cambios pequeños
- Ej.: si hace falta agregar una pantalla, separar por parches distintos la corrección de bugs, el upgrade de dependencias y la funcionalidad nueva
- Se enfatiza que los cambios pequeños ayudan a desarrollar software más rápido y con mejor calidad
Habilidades concretas que realmente me ayudaron a desarrollar más rápido
Lo anterior puede sonar un poco abstracto, pero también existen habilidades prácticas muy efectivas para desarrollar rápido
-
Leer código (
Reading code): es la habilidad de desarrollo más importante que he adquirido hasta ahora- Si puedes interpretar bien código existente, el debugging se vuelve mucho más fácil
- Los bugs o la mala documentación en librerías open source o de terceros dejan de dar tanto miedo
- Lo que se aprende leyendo código ajeno es enorme y ayuda directamente a mejorar la capacidad general de resolver problemas
-
Modelado de datos (
Data modeling): aunque tome tiempo, es importante diseñar bien el modelo de datos- Un esquema de base de datos mal diseñado termina provocando muchos problemas y costos de corrección complejos
- Diseñar de forma que los estados inválidos ni siquiera puedan representarse reduce bugs desde la raíz
- Si los datos se almacenan o se intercambian con sistemas externos, esto importa todavía más
-
Scripting (
Scripting): la capacidad de escribir rápidamente scripts cortos en Bash, Python, etc. maximiza la eficiencia- Varias veces por semana lo uso para automatizar tareas como ordenar Markdown, limpiar datos o encontrar archivos duplicados
- En Bash, herramientas como Shellcheck ayudan a prevenir errores de sintaxis por adelantado
- Para trabajos que no necesitan ser robustos, también se puede terminar rápido con ayuda de un LLM
-
Uso de debuggers (
Debuggers): usar el debugger es esencial para diagnosticar problemas rápido y entender el flujo del código de una manera imposible solo con print/log- Encontrar la causa raíz de bugs complejos se vuelve mucho más rápido
-
Saber cuándo descansar: tener el hábito de tomar un descanso sin dudar cuando te atoras
- Pasa seguido que un problema imposible tras mucho tiempo se resuelve enseguida después de una pausa de 5 minutos
- También es importante para la eficiencia de la concentración
-
Preferencia por funciones puras y datos inmutables: programación funcional; si prefieres funciones puras e
immutable data,- se reducen los bugs, baja la carga de seguir estados y aumenta la claridad y previsibilidad del código
- muchas veces es más simple y efectivo que diseñar jerarquías complejas de clases
- no siempre es posible, pero por defecto intento considerar primero este enfoque
-
Uso de LLM (modelos de lenguaje grandes): los LLM (por ejemplo, ChatGPT) tienen desventajas, pero pueden acelerar mucho tareas de desarrollo repetitivas o automatizables
- Después de entender bien cómo incorporar un LLM a mi código y cuáles son sus límites, lo uso de manera activa
- También tomo como referencia experiencias, tips y casos de la comunidad
Todas estas habilidades las he practicado repetidamente durante mucho tiempo, y en la práctica se han vuelto un gran activo para desarrollar rápido
Resumen
- Estas son las lecciones clave que he obtenido al desarrollar software rápido
- Entender claramente qué nivel de calidad de código necesita cada tarea
- Hacer rápido un borrador (
rough draft) para definir la forma general - Buscar siempre margen para relajar requisitos
- Mantener el foco sin dejarse arrastrar por distracciones
- Hacer cambios pequeños y commits frecuentes, evitando parches grandes
- Practicar de forma constante habilidades concretas (leer código, modelado de datos, debugging, scripting, etc.)
- Todo esto puede parecer obvio, pero me tomó mucho tiempo llegar realmente a estas conclusiones
2 comentarios
Hay muchas cosas con las que es fácil identificarse.
Los comentarios también son buenos, pero cuando alguien lo organiza y lo expresa así, o sea, cuando pone la mesa para la discusión, siento que se vuelve algo más completo a través de las objeciones, el apoyo y los aportes adicionales al respecto.
Posdata: últimamente veo seguido la expresión "tecnología aburrida"; en inglés sería boring technology.
Opinión de Hacker News
En los últimos años he aprendido a construir sistemas rápido y con suficiente solidez
Aprendí que es importante dominar a fondo una sola herramienta. Es mucho más eficiente usar algo que conozco bien que una herramienta que superficialmente parezca más adecuada. En la práctica, para la mayoría de los proyectos Django resulta ser la elección correcta
A veces empecé proyectos preocupado de que Django fuera demasiado pesado, pero al final el proyecto terminó creciendo mucho más allá de la intención inicial. Por ejemplo, hice una app de página de estado y enseguida me di cuenta de que intentar esquivar las limitaciones de Django era ineficiente
En la mayoría de las apps que encajan bien con el modelo de Django, el modelo de datos es lo central. Incluso en un prototipo, si postergas el refactor del modelo de datos, después el costo y la dificultad crecen de forma exponencial
La mayoría de las apps no necesitan una SPA ni un framework pesado de frontend. Algunas sí, pero en el 80% de las páginas basta con vistas tradicionales de Django. Para el resto se puede considerar AlpineJS o HTMX
En la mayoría de los casos, desarrollarlo uno mismo es más fácil. Con Django se pueden crear rápido un CRM, una página de estado, un sistema de soporte, procesos de ventas y más. Es mucho más rápido que integrar un CRM comercial.
Elige tecnologías tan comunes que hasta aburran. Con la combinación Python/Django/Postgres se resuelve casi todo. Puedes olvidarte de Kubernetes, Redis, RabbitMQ, Celery, etc. Alpine/HTMX es la excepción, porque permite evitar gran parte del stack de JS
Para mí, Redis y Kubernetes sí son “tecnologías aburridas” en 2025. Ambas son extremadamente estables, sus casos de uso están claros y sus desventajas ya son bien conocidas, así que inspiran confianza. Personalmente soy fan de las dos. Confío en ellas porque hacen exactamente lo que necesito
A mí también me encanta Django. Permite arrancar y desplegar proyectos rapidísimo
Si de verdad vas a elegir “tecnologías aburridas”, incluso Postgres merece una segunda reflexión
Uso Celery con bastante frecuencia en proyectos de Django. No me gusta su complejidad, pero en entornos PaaS suele ser la opción menos dolorosa
La idea de que “la mayoría de las apps no necesitan una SPA ni un framework pesado de frontend” parece entrar en conflicto con el consejo de “domina una sola herramienta”
Cuando dejas el código como un borrador tosco, muchas veces la gerencia termina desplegándolo tal cual como “versión final”
Por eso escribo código robusto desde el principio. Incluso hago el test harness casi con nivel de producción
La clave es crear módulos de altísima calidad. Las partes que tienen muy poca probabilidad de cambiar, o que causarían problemas enormes si cambian, las aíslo como módulos independientes y las importo como dependencias
Gracias a esos módulos se pueden desarrollar apps nuevas muy rápido y mantener la calidad alta de forma constante
Ejemplos que he usado directamente son RVS_Checkbox, ambiamara, RVS_Generic_Swift_Toolbox y otros
Tengo una pregunta: ¿es estándar en Swift usar patrones de comentarios como
* ##################################################################?El enfoque cambia bastante según el tamaño del proyecto
Si es un proyecto personal o de un equipo pequeño, desarrollar “rápido y tosco” suele ser lo óptimo. Esa es una de las fortalezas del desarrollo a pequeña escala
En equipos pequeños, si aparece un bug se corrige rápido, y además todos entienden casi por completo todo el código
Cuando la escala crece, el costo de errores de arquitectura o de corregir bugs se dispara. La arquitectura inevitablemente se vuelve compleja y los refactors grandes prácticamente dejan de ser posibles. En ese entorno, la precisión paso a paso tiene que ser la máxima prioridad
El contexto realmente importa. “Grande” puede significar cosas distintas, pero por mi experiencia, acordar temprano las APIs entre apps para que frontend y backend puedan trabajar rápido siempre fue lo correcto
En situaciones así, hay que reducir el sistema. Todo el mundo quiere un sistema enorme, pero en realidad no lo necesita
Se suele decir que “en un game jam de 24 horas no hace falta preocuparse por la calidad del código”, pero por la mayoría de los hackatones y revisiones de código que he vivido, los equipos con mejores resultados también cuidaban la calidad del código y hasta un entorno básico de pruebas
En realidad, esas dos afirmaciones (que para ir rápido hay que sacrificar calidad del código vs. que los equipos con mejor desempeño tienen mayor calidad) no se contradicen. Los equipos buenos no necesariamente estaban obsesionados solo con que el código se viera prolijo
En el caso de los game jams, si te obsesionas demasiado con la limpieza del código, el resultado final puede empeorar. Sistemas como UE blueprint muestran por qué a veces hay que priorizar el resultado por encima de la “pulcritud” del código
Algunas personas evalúan la “limpieza” del código de manera global, mientras que otras evalúan el costo/beneficio detallado de mejoras de código innecesarias
A diferencia de la idea de que “al prototipar salen a la luz unknown unknowns inesperados”, cuando yo toco algo por primera vez siempre veo primero las ventajas y no tanto las desventajas
En la práctica, los problemas reales (unknown unknowns) aparecen recién cuando estás completando la funcionalidad de verdad: manejar edge cases, mensajes de error amigables para el usuario, eliminar efectos secundarios, etc.
Probablemente los unknown unknowns que yo experimento vienen de la herramienta/framework/librería en sí, mientras que el autor se refiere a unknown unknowns del propio dominio del problema
También es cierto que un rough draft no puede ser demasiado tosco. Si haces las cosas por encima en partes donde no deberías, los problemas reales terminan explotando.
Cuando hago herramientas para uso propio, puedo hacerlas de forma bastante improvisada y aun así usarlas sin problema, incluso si están llenas de huecos
En la industria tecnológica actual, donde los recortes son tan frecuentes, eso es la mayor amenaza para la calidad del software y la productividad de ingeniería
La ansiedad por los despidos y la presión por mostrar resultados rápidos matan la creatividad y el espíritu de experimentación, y además provocan burnout
Todo el mundo termina arrastrado por la mentalidad de rebaño detrás de temas de moda como la IA, en un entorno donde ya ni siquiera se puede criticar
Es un problema más urgente que la programación automática con LLM
La mayor amenaza para la calidad del software siempre ha sido que los consumidores no pagan por la calidad
El vendor lock-in a nivel de programación en realidad es mucho más destructivo que el lock-in de SaaS
En ciclos rápidos como un game jam de 24 horas, siento que el mal código en realidad es letal
Cuanto más limpio está el código, menos errores se cometen, menor es la carga sobre la memoria de trabajo, y mucho más fácil es hacer cambios de último minuto, agregar funciones o corregir problemas
En un proyecto de 24 horas, lo que más arruina el trabajo no es escribir el código despacio, sino acorralarse uno mismo o descarrilarse por problemas impredecibles
Claro, eso no significa que haya que corregir todos los bugs. Pero si la calidad base es baja, toda la experiencia del proyecto se vuelve mucho más difícil
Este principio también aplica a proyectos con más tiempo. Tener más tiempo no significa que convenga escribir todo de cualquier manera
Si conviertes el buen código en un hábito, puedes asegurar calidad sin costo extra. Y aunque tomara más tiempo, igual valdría la pena
Pienso igual. He participado en varios game jams, y el “código desprolijo” solo lo tolero en las últimas 1-2 horas antes del cierre, y únicamente en archivos que nadie más vaya a tocar
Para escribir código rápido y bueno, al final la respuesta es simplemente escribir mucho
Cuando hay prisa, no me preocupo por cosas como un asset loader sofisticado y simplemente uso archivos estáticos
Creo que la idea de que “escribir buen código toma más tiempo” es un malentendido. Una vez que necesitas cumplir cierto nivel de exigencia, el buen código no es un obstáculo para la velocidad
El criterio de cuánto es “good enough” cambia mucho de un equipo a otro, y esa ha sido una de las mayores fuentes de conflicto en mi carrera
La gente de big tech se queja de que faltan pruebas, y la gente de startups se queja de que todo va demasiado lento
Sería útil documentar con claridad qué significa “good enough” y compartirlo dentro del equipo
Justamente para eso está el team charter, es decir, el documento de “cómo trabajamos”
Uno de los factores importantes que no se menciona en el artículo es la desaceleración de la velocidad de desarrollo con el paso del tiempo
A medida que crecen el proyecto y el equipo, la velocidad de desarrollo naturalmente se vuelve más lenta
Es decir, aunque implique sacrificar un poco de velocidad inmediata, conviene preparar desde el inicio cosas como pruebas, documentación, registros de decisiones y reuniones Agile para evitar que la velocidad se deteriore demasiado a largo plazo
Si no preparas desde antes cosas como observability o una estructura de código fácil de probar, después el impacto negativo puede ser enorme
Aunque trabajo solo, también siento la importancia de tres cosas: registro de decisiones, pruebas y documentación
También me resulta familiar ese patrón. Empiezo con un rough draft o un código pequeño que une otro lenguaje de scripting o ejecuciones manuales para validar una idea