- El gusto técnico es un concepto distinto de la habilidad técnica: alguien puede tener una gran capacidad y aun así mal gusto, o poca capacidad y buen gusto
- En un ingeniero de software, el gusto se refiere a la capacidad de elegir los valores de ingeniería adecuados para el proyecto
- Se manifiesta en la sensibilidad para percibir qué código se ve bien o mal, qué decisiones de diseño resultan satisfactorias y con qué problemas uno se obsesiona; todo eso refleja el conjunto de valores de ingeniería que la persona prioriza
- Todas las decisiones en ingeniería de software son una secuencia de trade-offs; un ingeniero inmaduro toma cierto enfoque como una verdad absoluta, mientras que uno maduro ajusta los valores con flexibilidad según el contexto
- El buen gusto es la capacidad de elegir la prioridad de los valores que mejor encajan en un proyecto específico, mientras que el mal gusto aparece como una rigidez obsesionada con estándares absolutos como las «best practices»
- El gusto se construye con experiencias en proyectos diversos y con una mentalidad abierta, y al final la presencia o ausencia de buen gusto se hace evidente en el éxito o fracaso del proyecto
La diferencia entre gusto técnico y habilidad
- El gusto técnico no coincide necesariamente con una gran habilidad
- Así como cualquiera puede distinguir entre comida buena y mala sin que eso implique saber cocinar bien, en software el gusto se forma antes que la capacidad
- El gusto del ingeniero se refleja en qué código «parece bueno» o «parece flojo»
- Sentir satisfacción con ciertas decisiones de diseño y preocuparse más por ciertos problemas también forma parte del gusto
- La capacidad técnica puede crecer con práctica y aprendizaje, pero el gusto se desarrolla de una manera más ambigua e intuitiva
-
Indicadores del gusto de ingeniería
- Sentir que «este código se ve bien/mal»
- Una fuerte satisfacción o indiferencia ante ciertas decisiones de diseño
- Problemas de software que te siguen rondando la cabeza después del trabajo, y otros que no
- El gusto puede entenderse como la capacidad de adoptar los valores de ingeniería adecuados para el proyecto actual
La distinción entre habilidad y gusto
- Surge la duda de si el «código que se ve bien» realmente tiene que ser mejor código
- Ejemplo: quien prefiere
map/filter puede priorizar la legibilidad y las funciones puras, mientras que quien prefiere los bucles for puede priorizar el rendimiento y una extensión simple
- No es un asunto de correcto o incorrecto, sino una diferencia en los valores priorizados
- Como cada lenguaje y contexto tiene ventajas y desventajas, una elección no es necesariamente mejor que otra
- Cada ingeniero valora cosas distintas, y por eso sus preferencias cambian
Qué es el gusto de ingeniería
- Casi todas las decisiones de la ingeniería de software son un equilibrio entre valores en conflicto (trade-offs)
- Un ingeniero inexperto se aferra demasiado a su propio gusto
- Un ingeniero maduro entiende las ventajas desde múltiples perspectivas y prioriza la elección adecuada para la situación actual
- Lo importante no es si X (tecnología) o Y (tecnología) es mejor, sino juzgar si en el proyecto actual se necesitan más las ventajas de X que las de Y
-
Ejemplos de valores de ingeniería
- Resiliency: si el sistema sigue funcionando bien incluso con fallas o problemas de red
- Speed: si logra un rendimiento cercano al límite teórico, o si realiza demasiado trabajo innecesario
- Readability: si un ingeniero nuevo puede entenderlo y adaptarse rápido, y si las funciones son cortas y claras
- Correctness: si se modelan estados inválidos, si hay suficientes pruebas, tipos y
assert, e incluso si se aplica verificación formal
- Flexibility: si es fácil ampliar el sistema y aplicar cambios de manera simple
- Portability: si depende de un entorno específico, y si cambiar el entorno de despliegue es sencillo
- Scalability: si puede ampliarse o escalar automáticamente ante aumentos de tráfico de 10x o 100x, y dónde están los cuellos de botella
- Development speed: qué tan rápido puede expandirse el sistema y si la mayoría de los ingenieros puede trabajar en él
- Además, existen otros valores como elegance, modern-ness, uso de open source, costo de mantenimiento, etc.
- No todos los ingenieros muestran el mismo nivel de interés por cada valor
- Según los valores que cada persona considere más importantes, cambian el lenguaje, framework o patrón de diseño que utiliza
Características del mal gusto
- El mal gusto aparece cuando los valores que una persona prefiere no encajan con el proyecto actual
- El problema es la falta de flexibilidad para imponer sistemáticamente a su proyecto las ventajas de una tecnología o metodología específica
- Las posturas que siempre apelan a las «best practices» muestran una falta de criterio adaptado a la situación
- Un ingeniero sin flexibilidad puede encajar bien en ciertos proyectos, pero provocar problemas graves cuando cambian el entorno o el trabajo
Características del buen gusto
- El buen gusto es la capacidad de elegir bien los valores de ingeniería correctos según la situación del problema
- A diferencia de la simple habilidad técnica, solo puede comprobarse en el contexto de proyectos reales y complejos
- Si un proyecto avanza bien después de adoptar una decisión de diseño con la que estabas de acuerdo, puedes medir qué tan adecuado era tu gusto
- La experiencia en proyectos diversos y una actitud abierta hacia nuevos valores en ciertos momentos son elementos importantes de aprendizaje
- Mantener la flexibilidad y evitar ideas fijas sobre una tecnología o método ayuda a formar buen gusto
Cierre
- El buen gusto es tan importante como la habilidad, y puede desarrollarse mediante la diversidad, la flexibilidad y la autorreflexión durante el proceso de crecimiento
- Algunas personas muestran un gusto excepcional más allá de su experiencia (como prodigios de la programación y de otros campos)
Discusión adicional
- En los comentarios de Hacker News también hubo opiniones escépticas sobre la existencia misma del «gusto»
- Algunas personas afirmaron que para cada problema existe una sola solución correcta, pero el autor respondió que en la práctica pueden existir varias soluciones, y que al final los valores personales y el contexto determinan la elección
- Otra opinión señalaba que el contexto del cliente y del negocio también forma parte del gusto
7 comentarios
Más que descartarlo como mal gusto, parece una mala tendencia que puede ser tóxica para el equipo y el proyecto.
Opinión de Hacker News
He visto que los ingenieros inmaduros tienden a aferrarse demasiado a sus propios gustos, y esa inmadurez también puede darse en ingenieros con experiencia. Antes, cuando ayudaba a mis amigos con el código de sus tareas de computación, sentía el impulso de reescribirlo todo solo porque no me gustaba. Pero al final me di cuenta de que si hacía eso tardaría demasiado y además mis amigos no entenderían el resultado. Así que los ayudé haciendo solo algunos ajustes a su enfoque, y quedaron más satisfechos. Gracias a esa experiencia conocí distintas perspectivas y mi propio código también mejoró. Sentí que más bien yo debía agradecerles a mis amigos. Incluso ahora me cuesta dejar de lado los prejuicios, pero intento comprender seriamente el punto de vista de la otra persona tanto como sea posible y, a veces, reconocer que ese enfoque es mejor. Los principios en realidad son bastante subjetivos, así que apoyarse siempre solo en principios significa un enfoque perezoso que evita pensar seriamente en la situación
Aunque un ingeniero junior esté haciendo algo de forma ineficiente, yo nunca le digo que está usando una manera menos optimizada. En cambio, siempre le pregunto por qué lo hizo así. Al final de cada conversación, uno de los dos aprende algo. O yo descubro una forma nueva o sus razones, o ellos aprenden por qué ese método no funciona a largo plazo. Sea como sea, estas conversaciones nunca terminan de forma confrontativa
Creo que el “buen gusto” surge de experimentar grandes API y buen código. El buen código se reconoce en cuanto lo ves y, con el tiempo, uno también debería poder escribir así. Pero cuando recién entras en este campo es difícil tener buen gusto para programar, y tener experiencia tampoco garantiza ese gusto, así que siempre hace falta el esfuerzo de buscarlo, reconocerlo e imitarlo
La solución para salir de los prejuicios, sesgos y formas rígidas de pensar es la educación y acumular experiencias diversas fuera de la perspectiva individual de cada quien. Solo si uno se esfuerza activamente por entender el mundo desde la mirada de otros puede crecer como persona y como profesional, y ampliar su perspectiva. Para ingenieros como yo, que se interesan en muchos campos, basta con saber que existen otras soluciones o puntos de vista para que cambie mi forma de resolver problemas y encuentre una mejor solución que mi primer impulso
Por eso es bueno experimentar con varios lenguajes de programación. Al retarte constantemente con lenguajes nuevos que cuestionan tu forma de ver las cosas, sigues teniendo momentos de “ajá”. Al principio pueden parecer incómodos o incorrectos, pero hace falta pasar por el proceso de aceptarlos como son hasta entender por completo por qué funcionan así
Excelente opinión. Esta forma de pensar es la que aplico con la gente que contrato directamente o con quienes trabajo en equipo. Si se logra el objetivo o el resultado, no es necesario que coincidan exactamente con mi proceso ni con mis detalles. Reconozco que hay muchas formas de hacerlo
Creo que el “buen gusto” en la moda no está tanto en cada prenda individual, sino en combinar prendas que por sí mismas parecen no significar gran cosa para crear una sensación fuerte y armoniosa. Esperaba que el artículo fuera en esa dirección. Quisiera explorar más si lo que un ingeniero de software decide por gusto realmente pertenece al terreno del gusto, y no solo a trade-offs técnicos. Dicho eso, el propio artículo se siente como un ejemplo de mal gusto. En contenido, cada parte está razonablemente bien escrita, pero no logra construir un “look” general, así que se siente disperso. No es un ataque al autor; al contrario, creo que el tema es excelente y por eso mismo quiero aportar una opinión para mejorarlo
No estoy de acuerdo con la idea de que una prenda no tenga significado por sí sola. La ropa tiene significado cultural, histórico y simbólico incluso antes de combinarse. La moda va más allá de la simple combinación. Además, en la moda también hay distintos trade-offs en la producción, el uso y la combinación de prendas
Eso que te intriga de “cómo percibimos la belleza y la elegancia” ha sido tema de filósofos desde la antigüedad, y es demasiado amplio como para resolverlo en un solo artículo. Christopher Alexander, del campo de la arquitectura, lo exploró a fondo, y sus ideas influyeron mucho en la arquitectura de software. Alexander sostenía que existe una belleza objetiva. Vale la pena revisar su charla magistral en OOPSLA o la tesis doctoral de Roy Fielding. Lo que aquí se menciona como “valores” está organizado de forma más sistemática en la tesis de Fielding como “propiedades arquitectónicas”
Curiosamente, yo considero que este artículo es un texto excepcional, de esos raros que cuesta encontrar, porque trata el tema con profundidad y de manera sistemática
Quisiera preguntar en qué momento, dentro de cierta combinación, el ingeniero realmente demuestra “gusto”, y cómo distinguir ese “terreno del gusto” de un simple trade-off técnico. Desde mi punto de vista, muchas decisiones se reducen a “es un trade-off técnico, pero no se puede demostrar de forma absoluta, o la diferencia es tan pequeña que en la práctica da igual”. Es decir, cuando es difícil decidir, simplemente se deja como una cuestión de gusto
La mayoría de los desarrolladores, en general, tienen poco sentido de la moda, así que tampoco entienden muy bien lo que es el buen gusto en general. Y la mayoría de las cosas del mundo tech no son para nada elegantes ni cool para la gente no técnica. Los lenguajes de programación no son cool. En el mundo del desarrollo, el punto de partida ni siquiera es “cool”, sino “no cool”, y de ahí va para abajo. Por ejemplo, Rust y C++ entrarían en la categoría de “no cool”, mientras que lenguajes funcionales poco conocidos o Bash y Linux caerían en la categoría de “realmente nada cool”
El buen gusto es escribir código poderosamente simple, de ese que parece que cualquiera pudo haber escrito
Comparto otro ejemplo. Al desarmar y volver a armar un Dodge Challenger modelo 72, siempre me sorprende lo increíblemente bien hecho que está este auto siendo simple, directo y barato. Por ejemplo, el tablero necesita 5 voltios aparte del voltaje general del auto (10~18V), y tiene una especie de zumbador (que usa un electroimán) que corta el circuito por encima de 5 voltios y lo cierra por debajo, encendiéndose y apagándose rápido para generar en promedio 5 voltios. La mayoría lo reemplaza por un regulador electrónico de voltaje, pero entonces el tablero deja de funcionar. En realidad, el tablero es mecánico, así que si no tiene ese pequeño ruido del voltaje de 5 voltios, las agujas se traban con frecuencia. Ese voltaje “tosco” de 5 voltios en realidad evita que se detengan. Si lo sustituyes por un sistema electrónico, tienes que agregarle “ruido” a propósito. Me impresiona lo sobresaliente que es un dispositivo mecánico tan simple tanto en efectividad como en simplicidad
El verdadero valor de este tipo de código simple, aunque ahorre mantenimiento o tiempo del equipo, por lo general no recibe el reconocimiento adecuado. Muchas veces el código que realmente aplica el principio KISS (Keep It Simple, Stupid) es menospreciado porque “no se ve valioso”. Por eso incluso existen equipos u organizaciones que básicamente solo administran complejidad innecesaria
A veces está bien que un ingeniero pueda hacer algo extraordinario, pero lo realmente importante es un ingeniero que, aunque al principio parezca difícil, termina encontrando con frecuencia una solución común y simple
Cuando ves ballet, todo el mundo dice “¡se ve facilísimo!”, pero en realidad lo logran porque practicaron decenas de miles de veces hasta hacerlo parecer fácil
Siempre he admirado más a la gente que logra resumir algo complejo de una forma verdaderamente simple. Tan claro como los ejemplos de K&R C, aunque me gustaría que dejaran comentarios un poco más cuidadosos
La pregunta de “¿se entiende el código de un vistazo y facilita el onboarding de ingenieros nuevos?” no es tan fácil como parece. No está claro si “nuevo” significa alguien con 0, 10 o 30 años de experiencia. La “legibilidad” también parece un concepto claro para algunas personas, pero en realidad es un espectro enorme, de 0 a infinito. Las ecuaciones de Maxwell son clarísimas para algunos y completamente opacas para otros. Por eso siempre me pregunto a quién va dirigida exactamente la frase “el código debe ser fácil de leer”
Un código fácil de leer es aquel que considera al lector y minimiza la carga cognitiva. Ese también es el objetivo de las abstracciones por capas y de los patrones de diseño. Claro, depende de la especialización del lector y de su familiaridad con la base de código, así que tiene algo de subjetivo. Pero negar la legibilidad solo porque es subjetiva ya me parece excesivo. No puedes decir que el 'Ulises' de Joyce y 'The Cat in the Hat' de Seuss son igual de fáciles de leer
No estoy de acuerdo con la afirmación de que “la legibilidad no es un concepto”. El código ilegible es código que nadie puede leer, ni siquiera su autor (o una IA). Y el código que solo su autor puede leer tampoco es un código fácil de leer
En la época de las ecuaciones de Maxwell sí eran realmente difíciles, pero la forma en que hoy las conocemos es el resultado de que Heaviside y otros las refinaran para hacerlas más legibles
Creo que la “legibilidad local” de una parte del código no significa mucho. Si ciertos patrones se aplican de manera consistente en toda la base de código, entonces incluso si ese patrón es algo complejo, en conjunto puede seguir siendo un código bastante fácil de leer. La complejidad temporal está bien si no afecta la calidad general del código
La legibilidad normalmente busca reducir la ‘complejidad accidental (accidental complexity)’. Incluso fórmulas como las de un guion cinematográfico, o algoritmos complejos, si tienen una mala notación se vuelven difíciles de entender. Al final, a la pregunta de “¿para quién debe ser fácil de leer el código?”, respondería que debe poder leerlo un ingeniero que conozca bien el dominio, aunque esté familiarizado con el problema pero no haya visto antes ese código en particular. Es similar a un paper: debería ser legible para el grupo de investigadores de esa área. Resumen de No Silver Bullet
Creo que la analogía de “un ingeniero con mal gusto termina señalando la dirección equivocada como una brújula rota” explica bien la esencia. A una persona así, ‘rota de forma predecible’, se le puede filtrar en una entrevista. Más peligroso es alguien como una ‘brújula parcialmente rota’. Parece desviarse un poco, pero en realidad siempre está exactamente 127 grados fuera de rumbo
Muchos textos como este confunden dos problemas. Primero, hay decisiones objetivamente malas sin importar gustos o principios, por ejemplo buscar en una lista con O(n) en lugar de usar un diccionario con O(1). Existen casos claramente técnicos donde una opción es mejor. Segundo, todo lo demás son trade-offs. Si usar map-reduce o un bucle normal, si pensar en rendimiento, legibilidad, compatibilidad, etc.; mientras haya razones, no me importa que no coincidan con lo que yo haría. El problema es cuando la respuesta es incorrecta o ni siquiera se consideró el trade-off. Ahí ya entramos al terreno del mantenimiento, y según el contexto —rendimiento, frecuencia de uso, etc.— quizá ni siquiera valga la pena tocarlo. Mientras el “por qué” de esa decisión esté claro, yo lo acepto. No sé si a eso realmente se le puede llamar “gusto”
El problema de este artículo es que trata de forma demasiado descontextualizada el hecho de que “cada persona valora cosas distintas”. En la práctica, un ingeniero debería poder detectar más o menos qué valores son los más importantes para el problema, es decir, cuáles son las hard constraints. Tiene sentido llamar “gusto” al margen de libertad que queda fuera de esas hard constraints. Sería como un artista que, además de los materiales y especificaciones fijadas, todavía tiene restricciones o libertades propias adicionales. El buen gusto de un ingeniero de software se parece a perseguir el máximo de minimalismo estético y el máximo de autocontrol. Para mí, un caso real de “mal gusto” es romper principios sin ninguna razón. Es decir, muchas veces se confundió la simplicidad con la familiaridad
La sección de “valores” del artículo se conecta con las propiedades de la arquitectura de software de la tesis doctoral de Roy Fielding. La tesis de Fielding es famosa sobre todo por REST, pero en realidad es una discusión mucho más amplia y sólida sobre arquitectura de software. Ayuda a pensar en el contexto de varias “propiedades arquitectónicas” (escalabilidad, legibilidad, mantenibilidad, etc.), y personalmente quiero enfatizar lo importante que es también entender las ‘restricciones arquitectónicas’
La ingeniería bien hecha (Principled engineering) debería darse por sentada. Encima de eso, se puede tener buen o mal gusto. Pero lo contrario no aplica. Si la ingeniería en sí es mala, el gusto no tiene importancia. El mal gusto puede perjudicar la eficiencia de la ingeniería, pero no vuelve imposible la ingeniería como tal. La ingeniería, en esencia, cumple el papel de sostener el gusto. Por ejemplo, algo puede estar perfectamente bien diseñado desde el punto de vista de la ingeniería, pero si nadie lo necesita ni lo quiere, no tiene sentido
El mal gusto al final nos lleva a esa situación incierta (X) que queremos evitar. Para mí, el buen gusto consiste en preparar una base sólida y mecanismos de seguridad en la base de código frente a la incertidumbre futura. Así es como se evita caer en riesgo
Realmente bueno
El artículo original es bueno, pero el contenido de los comentarios también es realmente bueno.
Cuando se habla de gusto, siempre me acuerdo del video TED de Torvalds:
https://www.ted.com/talks/linus_torvalds_the_mind_behind_linux
Desde el minuto 14:20, el buen gusto visto a través de la forma de implementar el código para eliminar una entrada de una linked list
Incluso las "decisiones objetivamente malas (por ejemplo, una búsqueda O(n) en una lista vs una búsqueda O(1) con un diccionario)" mencionadas en los comentarios de Hacker News pueden requerir decisiones distintas según el contexto.
Si la consulta se va a hacer una sola vez, el costo de construir una tabla hash puede ser mayor que simplemente hacer una búsqueda O(n) en una lista.
Es un buen comentario.