featured image

Haz que funcione, entonces hazlo hermoso, entonces si real, realmente tienes que hacerlo, hazlo rápido. El 90% del tiempo, si lo haces hermoso, será rápido. Así que realmente, ¡tan solo hazlo hermoso! Fue una de las frases que nos dejó Joe Armstrong pero, ¿sabes a qué se refiere?

Joe Armstrong era un programador bastante concienzudo. Le gustaba el código bien escrito. Esto puede sonar algo extraño teniendo en cuenta que a todo el mundo le gusta leer código bien escrito. Más aún teniendo en cuenta que Robert C. Martín decía que la relación entre lectura y escritura era 10 a 1. Es decir, lo que escribimos una vez lo leeremos unas diez veces. Si vamos a tener que leerlo tantas veces, ¿por qué no escribirlo de forma que sea más rápido y placentero de leer?

Pero además, un buen código debe ser aburrido tal y como decía en un antiguo artículo sobre Calidad Interna. Un momento, ¿hemos dicho código aburrido? Pues sí, el buen código debe ser hermoso y aburrido. Un código aburrido es aquel que al leerlo resulta obvio. No sobresalta. No tiene giros argumentales ni cambios de guión. No es el tipo de código que no te dice qué sucede hasta el final sino que lo va avanzando y se deja leer de forma intuitiva, sabes qué viene a continuación. Es predecible. Es claro. Es aburrido pero es un buen código.

Además, lenguajes como Python, Erlang o Elixir intentan hacer hincapié en no esconder nada. Ser lo más explícitos posible. Emplear la menor cantidad de magia negra como sea posible. Y aún dispongan de construcciones que oculten código, siempre aconsejan emplearlos de forma predecible, con un uso intuitivo como es el caso de SQLAchemy, Phoenix Framework o cualquier software que puedas realizar con Erlang, realmente es un lenguaje muy explícito, con reducción de efectos colaterales gracias a la inmutabilidad y la carencia de estado global y fácil de leer por su reducido número de estructuras.

En mis charlas siempre he puesto de ejemplo este código:

factorial(0) -> 1;
factorial(N) -> factorial(N - 1) * N.

Es un ejemplo muy conciso de algo que en lenguaje C podríamos escribir así:

int factorial_i1(int n) {
    for (int i = n - 1; i > 0; i --)
        n *= i;
    return n;
}

O incluso se podría dejar en una sola línea como:

int factorial_i2(int n) {
    for (int i = n - 1; i > 0; i --, n *= i);
    return n;
}

Si te dijese que he cometido un error en alguno de los ejemplos, ¿te diste cuenta del error? ¿has tenido que comprobarlo con una ejecución? y sobre todo, ¿cuál te ha costado menos revisar? En verdad hay uno con un error, si lo encuentras, deja un comentario.

Los ejemplos de lenguaje C cuestan mucho más ser revisados por los motivos que enunciábamos antes, combinan demasiadas expresiones juntas, demasiados símbolos y trucos y las variables mutan, cambian su valor dentro de la misma función.

Grace Hopper lo decía también en base a la complejidad de los lenguajes de programación:

Yo había sido profesora de matemáticas. En aquél tiempo encontré un cierto número de estudiantes que no podían aprender matemáticas. Entonces me impuse el trabajo de hacer fáciles nuestros computadores para la gente de negocios. Encontré que no era cuestión de si podían o no aprender matemáticas, sino más bien si ellos querían o no. Ellos decían: 'Quita esos símbolos, no sé lo que significan y no tengo tiempo para aprender símbolos'. Sugiero a aquellos que desean que las personas procesen datos a través de símbolos matemáticos que intenten enseñar esos símbolos a vice-presidentes, coroneles o almirantes. Te aseguro que yo lo intenté.

Si esto además lo mezclamos con una escritura poco clara o incluso agregando elementos propios como macros para esconder la complejidad de la vista pero no del compilador, podemos caer en errores solo vistos por el compilador o peor aún en tiempo de ejecución variando la lógica de ejecución con respecto a la prevista.

Joe Armstrong nos dejó el pasado 20 de abril de 2019 pero su legado aún permanece con nosotros. Aunque un poco tarde he querido rendir homenaje a este gran desarrollador escribiendo sobre una de las mejores frases que nos dejó. Podéis ver aquí una de sus grandes intervenciones hablando sobre programación, frustración, límites físicos de los equipos informáticos y Erlang (desgraciadamente el vídeo está en inglés y sin subtítulos):

Antes de despedir el artículo, como no, toca mención a la Programación Orientada a Objetos. Leí recientemente un artículo de Ilya Suzdalnitski titulado ¿Por qué la Programación Orientada a Objetos es un Desperdicio? (en inglés, Why is OOP Such a Waste?) donde se desprenden algunas buenas anotaciones al respecto. De nuevo y de Joe Armstrong tenemos:

Creo que la carencia de reutilizar viene de los lenguajes orientados a objetos, y no de lenguajes funcionales. Porque el problema con los lenguajes orientados a objetos es que todos tienen un entorno implícito que llevan siempre consigo. Tú quieres una banana pero lo que obtienes es un gorila sujetando la banana y la jungla al completo.

A lo largo del artículo menciona la existencia de los patrones de diseño como una serie de prácticas para solventar un problema, algo que está roto y que intentan corregir con disciplina. Programar en lenguajes orientados a objetos se vuelve tan difícil como intentar mantener una piedra redonda sobre una colina no aplicando mucha fuerza para que no se despeñe hacia adelante pero sin liberar la fuerza necesaria para que no vaya colina abajo por detrás. Es siempre un gasto de energía hagas lo que hagas.

Completaba el discurso Joe Armstrong:

Si tienes código referencialmente transparente, si tienes funciones puras - todos los datos entran como argumentos y todo sale en el retorno sin dejar un estado entre medias - eso es increíblemente reutilizable.

Además, podemos sumar las frases de Alan Kay, quien acuñó el término de programación orientada a objetos que decía:

Inventé el término Orientado a Objetos y puedo decirte que no tenía en mente C++.

La idea de Alan se basaba en la interacción desacoplada de elementos dentro del sistema. En realidad, cualquier implementación de Orientación a Objetos actual no se basa en el intercambio de mensajes sino en la llamada de funciones referenciadas localmente. Sobre este aspecto Alan Kay decía:

Siento cuando acuñé hace tiempo el término "objetos" para este tema porque hace que mucha gente se enfoque en la idea menor. La idea mayor era la mensajería.

Podemos decir que la Orientación a Objetos fue una idea lanzada por Alan Key que se malinterpretó por muchos diseñadores de lenguajes implementando lo que entendieron pero sin perder el foco de cómo se hacía todo en los lenguajes de programación en esos días y se popularizó arrastrando los problemas que Ilya menciona más detalladamente en su artículo.

¿Es entonces la Programación Funcional la solución o una moda pasajera? En verdad la programación funcional llegó hace mucho más tiempo del que se cree. Cuando Haskell Curry interpeló en una charla a John von Neumann por incitar a desarrollar empleando solo estructuras y diagramas de flujo, Curry indicó que la composición y el uso de funciones era mucho más preciso y menos propenso a fallos, permitía mejor reutilización del código y era un concepto más cercano a todos los científicos de la computación por sus raíces matemáticas.

La programación funcional siempre ha sido una contra partida, siempre se ha empleado para desarrollar y especificar problemas de alto nivel y siempre se ha empleado en Inteligencia Artificial desde IPL en los años 50 cuando Herbert Simon, AlLen Newell y Clifford Shaw desarrollaron el lenguaje, después con Lisp, con Prolog y todos los lenguajes que siguieron.

No obstante, como dice Joe Armstrong, no es cuestión de emplear solo programación funcional o rechazar completamente la orientación a objetos, siempre podemos encontrar un balance y el uso del Modelo Actor en Erlang, aunque Erlang parece concebido con esas ideas en mente, Robert Virding ha dicho muchas veces que toda similitud es completamente casual. Ellos no tenían ese modelo en mente pero sus desarrollos casaron completamente con él.

En base a considerar una evolución de la Programación Orientada a Objetos hacia el Modelo Actor, que se escribió posteriormente y que ha mostrado capacidades superiores para desarrollar software de manera mucho más simple y fácil en entornos distribuidos y se ha empleado no solo en Erlang, sino también en Elixir y Scala entre otros, cabe pensar que realmente la evolución de lenguajes como JavaScript, Python, PHP o Java incluyendo cada vez más aspectos funcionales y librerías similares a lo que permiten hacer estos lenguajes como Erlang se convierta en la forma de trabajar en poco tiempo.

También decían los creadores de Erlang que cada intento de implementar un sistema distribuido y basado en mensajes en otros lenguajes pasa por la implementación parcial de un sistema Erlang. ¿Queremos seguir construyendo la rueda una y otra vez?

Programa bien, programa aburrido, haz programas hermosos. Gracias Joe.