Este artículo se publicó originalmente en el sitio web de David y se republica aquí con su permiso
El enero pasado, Exercism anunció un nuevo programa llamado 12in23, en el que retaba a los participantes a probar 12 lenguajes de programación nuevos en 2023. Cada mes tendría un tema (como «Abril analítico» u «Octubre orientado a objetos») y destacaría lenguajes concretos que probar. Me encanta aprender cosas nuevas y me he convertido en un poco de friki de los lenguajes (de programación), así que decidí intentarlo. ¡12 lenguajes, 12 meses!
Ahora que el año casi ha terminado, estoy increíblemente contento con cómo ha ido el proyecto. Conseguí probar 12 lenguajes nuevos, conocí a gente estupenda en la comunidad de Exercism y publiqué algunas contribuciones de código abierto muy chulas por el camino. En este artículo los repaso todos y cuento qué me aportó cada uno.
Elegir los lenguajes
Me marqué unas cuantas pautas para el año que me ayudaran a sacarle el máximo partido a la experiencia:
- Los lenguajes debían ser completamente nuevos para mí o, al menos, lo bastante desconocidos como para sentir que aprendía mucho.
- Los lenguajes elegidos debían ser (potencialmente) prácticos para seguir aprendiendo más sobre ellos en el futuro. Este proyecto era solo por diversión, pero quiero dedicar mi tiempo a aprender cosas (al menos en parte) útiles.
- Instalaría todas las herramientas locales y la extensión de VSCode de cualquier lenguaje que usara. Quería comparar lenguajes en igualdad de condiciones, con tantas anotaciones de tipo e IntelliSense como fuera posible. En la universidad hacía todos los deberes de programación en Sublime Text, sin ningún linter ni autocompletado. Me preocupaba que, si aprendía a programar usando todas esas herramientas, dependiera demasiado de ellas y no llegara a ser un buen programador. Sin embargo, ha pasado lo contrario. Cuanta más carga cognitiva puedo descargar en mis herramientas, más puedo pensar en el problema real que tengo delante. No recuerdes cosas, recuerda cómo encontrarlas.
¡Vamos allá!

Enero (sin tema)
Cuando empezó enero, el equipo de Exercism todavía estaba eligiendo los temas mensuales, así que el lenguaje de ese mes era a mi elección. Sin una dirección clara, arranqué el año con Go. Había hecho un curso intensivo del lenguaje a mediados de 2022, pero no lo había usado mucho desde entonces y no me sentía nada competente.
Go es un lenguaje interesante. Su estricto compilador hace que Tu Programa Será Correcto y no avanzas ni un milímetro hasta que él considera que puedes hacerlo.1 Su verboso enfoque del tratamiento de errores hace que nunca te lleves sorpresas (a cambio de escribir if err != nil { return err } tantísimas veces). Hace bien su trabajo a la hora de convertir cosas difíciles en fáciles (como el paralelismo mediante canales), pero también complica algunas cosas fáciles (la manipulación de strings). Tiene una biblioteca estándar robusta, lo que significa que puedes hacer la mayoría de las tareas sin módulos de terceros. Me gusta que gran parte del ecosistema (formateo, instalación, compilación, etc.) sea de primera parte y esté integrado en el comando go. El lenguaje tiene sus detractores, pero creo que en gran medida cumple sus objetivos de corrección y mantenibilidad.
No lo he disfrutado tanto como para elegirlo como primera opción, pero es una gran herramienta que tener a mano para programas sensibles al rendimiento, como mostrar la ruta anidada en el prompt de mi shell.
Febrero funcional

Febrero se tiró de cabeza a la piscina con los lenguajes funcionales, una rama matemática de los lenguajes imperativos más habituales. Los lenguajes funcionales son conocidos por sus funciones «puras» (sin efectos secundarios). Elegí Elixir, sobre todo porque mi amigo Caleb lo ha usado para el Advent of Code y habla maravillas de él.
Disfruté bastante mi tiempo con Elixir. Se inspiró en Ruby (lo cual tiene sentido; su creador, José Valim, fue un colaborador clave de Rails). Me resultó sencillo expresar conceptos funcionales como el encadenamiento de métodos. Me encantó todo el azúcar sintáctico que lo hacía fácil, como el operador de tubería (|>):
foo(bar(baz(new_function(other_function()))))
# becomes
other_function() |> new_function() |> baz() |> bar() |> foo()
También fue mi primera vez trabajando con macros, o código que escribe código. Como los programas de Elixir pueden expresarse en un AST que a su vez es código Elixir válido, es fácil escribir código que produzca otro código válido. Es un concepto genial que Elixir pone fácil. También me moló que las funciones pudieran hacer pattern matching según la forma de sus argumentos, de modo que las llamadas pudieran dirigirse a la implementación adecuada:
defmodule TuplePrinter do
def print({a}) do
IO.puts("single")
IO.puts(a)
end
def print({a, b}) do
IO.puts("double")
IO.puts(a)
IO.puts(b)
end
end
TuplePrinter.print({1})
TuplePrinter.print({2, 2})
# single
# 1
# double
# 2
# 2
Parece el tipo de funcionalidad que o es genial o convierte tu código en un espagueti total. En cualquier caso, ¡era un concepto muy chulo!
Elixir también se beneficia de ejecutarse dentro de la máquina virtual BEAM de Erlang, lo que le da un gran ecosistema con el que comunicarse. Es excelente para la concurrencia y es el núcleo del querido framework web Phoenix.
Aunque no tengo una necesidad inmediata de usar Elixir, me pareció muy divertido de manejar y sin duda algo que me apetece retomar. Además, fue un reto interesante abordar problemas conocidos de formas desconocidas (concretamente, de forma recursiva).
Marzo mecánico
Marzo se centró en los lenguajes «de sistemas», que se compilan a código máquina.
De todas las opciones, Go era el único lenguaje que me interesaba.2 Ahora bien, los lectores avispados se darán cuenta de que ya había hecho un mes de Go, así que repetirlo no contaría para mis 12. Bueno, cuando lo elegí para enero, todavía no habían anunciado los temas, así que no me di cuenta de que me estaba metiendo en un callejón sin salida.
Si hubiera sabido que iba a llegar Bun, probablemente habría probado Zig, pero por desgracia (todavía) no puedo ver el futuro. Así que, a falta de una opción más atractiva, opté por un mes extra de Go, con la idea de que tendría que hacer doblete en algún momento más adelante en el año.
Abril analítico
Abril giró en torno a lenguajes populares en ciencia de datos. Python ya lo conocía demasiado y en la universidad hice R en una clase de estadística (y no me gustó), así que ¡Julia!
Disfruté el tiempo que pasé con él, pero sobre todo porque se parecía mucho a Python. Era un poco desconcertante, como ser estadounidense en Canadá. Todo resulta muy familiar, pero está un poquito desviado de una forma difícil de precisar. De repente, alguien te ofrece una moneda de dos dólares (o una función que está realmente bien pensada para hacer cálculo matricial) y te das cuenta de que ya no estás en Kansas.
Lo que más me llamó la atención fue el sistema de tipos de Julia. Se anotaba (de forma opcional) como el sistema de tipos de Python, pero tenía comprobaciones en tiempo de ejecución para asegurar que los argumentos coincidían con sus tipos declarados. Creo que el sistema de Python logra el equilibrio adecuado entre integrarse con las herramientas y no interponerse en tu camino, pero admito que los errores en tiempo de ejecución de Julia para funciones mal tipadas también eran útiles.
En definitiva, Julia estaba bien, pero no creo que vaya a necesitarlo en el futuro.
Mayo de cambio de mentalidad
Mayo insistió en el «prueba algo nuevo» destacando lenguajes que hacen cosas muy poco habituales. Aproveché para probar el siempre popular Rust. Tengo que decir que entiendo el hype.
Aunque el infame borrow checker requiere acostumbrarse, me gustó cómo me obligaba a pensar mis programas con más cuidado. El compilador era ciertamente estricto, pero los mensajes de error me ayudaban muchísimo a corregir los problemas. No diré que fuera especialmente productivo la primera semana, pero siento que al menos veo la cima de la curva de aprendizaje.
cargo, el gestor de paquetes de Rust, también merece una mención especial. Aunque no instalé ningún paquete de terceros, su funcionalidad de compilación, pruebas y formateo era genial. Lo mismo digo de su extensión de VSCode, que tenía todas las comodidades que esperaría de un lenguaje de tipado estático como Rust. Una buena experiencia de desarrollador marca de verdad la diferencia.
Aunque a nivel de implementación son muy distintos, Rust se me antojó parecido a Go en aquello para lo que los usaría: hacer que los programas se ejecuten muy rápido. Muchas herramientas de lenguajes que uso a diario están empezando a recurrir a Rust por sus características de rendimiento, así que preveo verlo más en el futuro (aunque yo no escriba Rust).
El verano de los sexps (junio)
Junio fue el mes de las S-expressions, una forma sintáctica común en los lisps. Elegí Clojure, un lenguaje funcional que se ejecuta en la JVM.
Había escrito un poquito de Clojure hace muchos años. Acababa de salir de la universidad y me convertí en el único responsable de un script diario crítico para el negocio en mi primer trabajo. No hace falta decir que fue una época complicada. Tenía curiosidad por ver si, ahora que era mayor y más sabio, resultaba algo más accesible.
Me alegra poder decir que ¡sí lo era! La experiencia funcional de febrero me ayudó a pensar de forma recursiva, y la sintaxis no era tan mala cuando te ponías con ella. Su interoperabilidad con la JVM también sería útil si lo usara en un proyecto más grande.
No me veo usando Clojure para nada mientras haya alternativas disponibles, pero no fue una experiencia del todo desagradable.
Misión secundaria: ¡el Universal Test Runner!
Durante años he usado una pequeña función de bash para ejecutar las pruebas unitarias en el directorio en el que estoy. Como estaba trabajando con todos esos lenguajes nuevos, me vi añadiéndole líneas por comodidad; recordar que debía ejecutar t era mucho más fácil que volver a aprenderme una y otra vez el comando de pruebas específico de cada lenguaje.
Cuando la lógica necesaria superó mi nivel de comodidad con bash, dediqué un tiempo en junio a convertir el proyecto en algo propio: el Universal Test Runner.
Lo compartí en el foro de Exercism y tuvo una buena acogida. Les gustó tanto que decidimos incorporar una funcionalidad similar en la propia CLI de Exercism (que está escrita en Go, un tema que, por suerte, acababa de repasar). Así que durante la segunda mitad del año pude ejecutar exercism test para lanzar la suite de pruebas del lenguaje de ese mes (un comando que el Universal Test Runner admite de forma nativa).
Si quieres saber más sobre el proceso, escribí sobre ello con mucho más detalle cuando se lanzó.
En fin, ¡sigamos!
Julio jurásico
Julio puso el foco en lenguajes antiguos. La verdad es que este mes había poco donde elegir en cuanto a utilidad práctica. Empecé con el venerable COBOL, porque había oído que todavía mueve un montón de infraestructura crítica. Pero, con una boda a principios de agosto echándoseme encima, no tenía capacidad para sentarme a aprender un lenguaje tan distinto para mí. Así que, en su lugar, me pasé a Visual Basic como la opción que menos mala parecía.
No hay mucho que decir aquí. El lenguaje parecía un poco verboso, pero bastante fácil de usar. Según tengo entendido, se diseñó realmente para el desarrollo de interfaces de usuario en Windows, así que hacer ejercicios pequeños hace difícil hacerse una idea cabal de él.
Agosto de apps
Agosto estuvo inundado de lenguajes para crear apps. Como era de esperar, este mes había muchas opciones. Me decanté por Swift. Como alguien que usa muchos productos de Apple, su lenguaje hecho a medida me resulta bastante relevante. No era del todo nuevo para mí: en 2016 publiqué una única app para iOS escrita enteramente en Swift. Pero no había vuelto a tocar el lenguaje desde entonces y ha evolucionado mucho, así que consideré que seguía contando.
Me sorprendió gratamente lo fácil que era trabajar con él. A diferencia de muchos de los otros lenguajes de esta lista, Swift es bastante nuevo. Se publicó por primera vez en 2014 y está claro que se ha beneficiado de las lecciones del diseño moderno de lenguajes. Tiene un gestor de paquetes propio, encadenamiento opcional, funciones de primera clase y una interpolación de strings sensata. Se sentía ergonómico de leer y escribir, incluso sin usar Xcode.
Dicho todo esto, Swift es sobre todo útil en el contexto de apps para plataformas de Apple, que actualmente no desarrollo. Aunque funcionó bien para los ejercicios, no creo que vuelva a él en un futuro próximo. ¡Aunque sí me encanta poder escribirlo en mi iPad!
Septiembre minimalista
Septiembre exploró lenguajes muy concisos o pequeños. Me decanté por jq, una herramienta que llevo años usando y adorando.
Aunque siempre lo había considerado solo una herramienta para trabajar con JSON, no un lenguaje de programación de propósito general. Me sorprendió gratamente ver que tiene todos los elementos habituales (funciones, variables, bucles, etc.), así que pude escribir programas bastante complejos:
# input: { "series": "1", "sliceLength": 1 }
. as {series: $series, sliceLength: $sliceLength} |
if
$series == "" then
"series cannot be empty" | halt_error
elif $sliceLength > ($series | length) then
"slice length cannot be greater than series length" | halt_error
elif $sliceLength == 0 then
"slice length cannot be zero" | halt_error
elif $sliceLength < 0 then
"slice length cannot be negative" | halt_error
else
.
end
| [range(0; $series | length)]
| map($series[. : . + $sliceLength])
| map(select(. | length == $sliceLength))
Fue divertido probar todas las funciones de jq que nunca había necesitado para transformaciones de datos sencillas. Aunque las herramientas en este caso dejaban algo que desear (sin integración con el editor, etc.), mereció la pena entender mejor la amplitud de la funcionalidad de jq.
editado: DJ Adams en Mastodon me dio a conocer el proyecto jq-lsp y su correspondiente extensión de VSCode. Esta vez se me pasó, pero le echaré un vistazo en el futuro.
Octubre orientado a objetos
Octubre ahondó en los lenguajes orientados a objetos. Tengo debilidad por los diseños orientados a objetos, que reflejan muy bien cómo visualizo los programas en mi cabeza. Me decanté por Ruby, que puede sonar como una elección rara.
Trabajo en Stripe, donde está la mayor base de código Ruby del mundo. ¿Seguro que no contaría como un lenguaje «desconocido»? Aunque todo eso es cierto, nuestro monolito de Ruby está muy lejos del Ruby «estándar»: todo tiene comprobación de tipos con Sorbet, hay mucha generación de código y hacemos un montón de magia para que todo funcione junto y escale. Aunque el Ruby de dentro y de fuera de Stripe es, al fin y al cabo, el mismo lenguaje, trabajar a escalas tan distintas ofrece experiencias enormemente diferentes; quería saber cómo era la vida en el exterior (en los años transcurridos desde que usé Ruby intensamente).
En gran medida, ¡fue bueno! Ruby en sí es genial y cita la «felicidad del programador» como uno de sus objetivos principales, algo que me llegó. Me gusta lo a menudo que puedo adivinar el nombre de funciones de la biblioteca estándar que nunca he usado. Me gusta lo fácil que es construir código funcional y lo ergonómica y expresiva que es la sintaxis.
Dicho esto, me sorprendió lo atrasadas que estaban las herramientas de desarrollo en comparación con Python. Puede que me hayan malacostumbrado, pero tener anotaciones de tipo en el editor y un linting y formateo extremadamente rápidos es más importante para mí de lo que creía. Para un lenguaje tan popular como lo fue Ruby en su mejor momento, me sorprendió lo atrasado que se sentía en ese aspecto.3 Tampoco me acostumbré del todo a los paréntesis opcionales en las llamadas a funciones, lo que hacía que pasar funciones como argumentos fuera menos directo.
Ruby sigue siendo un gran lenguaje y lo seguiré usando en el trabajo, pero no hace por mí nada que Python no haga, al menos ahora mismo.
Noviembre de los nibbles
Noviembre fue el mes más difícil hasta la fecha: los lenguajes ensambladores. Aunque ya no es habitual escribirlos a mano, es un tema útil e interesante que conocer. Elegí WebAssembly por su importancia para la web moderna y futura. Aunque normalmente se usa como destino de compilación (y no es algo que se escriba a mano), existen herramientas para los sickos que hay por ahí.
Me sentí sorprendentemente bien preparado para este mes. La sintaxis se parecía a la de Clojure y la estructura del lenguaje recordaba al TIS-100 de Zachtronics. Disfruté de forma extraña teniendo que empezar desde cero para cada operación; resultaba pintoresco. Odiaría tener que hacer algo de verdad así, pero mientras tanto fue una curiosidad divertida. Con comentarios generosos, conseguí escribir algo casi legible:
(module
(func (export "eggCount") (param $number i32) (result i32)
(local $res i32) ;; result
(local $remainder i32) ;; loop counter
(loop $loop
;; $res =
(local.set $res
;; $res +
(i32.add
(local.get $res)
;; $number % 2
(i32.rem_u
(local.get $number)
(i32.const 2)
)
)
)
;; $number //= 2
;; (keep on stack)
(local.tee $number
(i32.div_u
(local.get $number)
(i32.const 2)
)
)
;; this will keep looping until remainder is 0
br_if $loop
)
local.get $res
)
)
El mayor obstáculo fue la falta de documentación y recursos. Era difícil incluso saber qué funciones globales había disponibles. Pero como en realidad no voy a usar esto, una vez que arranqué no me molestó demasiado.
Diciembre cerró el año con lenguajes que no encajaban en otras categorías. Como había hecho doblete en marzo, necesitaba completar dos lenguajes este mes.
Empecé con Wren. Creado por Bob Nystrom, famoso, entre otras cosas, por Crafting Interpreters. Me cautivó su atención al detalle, su huella reducida y su diseño de arriba abajo; todo parece muy bien pensado. Ese nivel de cuidado se nota en los detalles del scope de las variables y las reglas de privacidad. Su compilador es pequeño y está profusamente comentado, así que es un gran recurso de aprendizaje si te interesan las implementaciones de lenguajes.
Wren está un poco sin pulir y parece estar mayormente abandonado, pero creo que para un lenguaje de juguete está bien. Nadie se acerca a esto esperando que esté listo para producción. Sin duda hay sitio en el mundo para lenguajes que no son para producción.
También: Lua
Mi segunda elección este mes fue Lua. A diferencia de Wren, es increíblemente práctico. Su facilidad para incrustarse hace que aparezca en un montón de sitios, como el scripting de Redis y los mods de Factorio. El modelo de objetos requería algo de acostumbramiento, pero veo cómo podría ser productivo enseguida. Me aficioné enseguida a las tablas como estructura para todo. Las herramientas eran buenas: el gestor de paquetes funcionaba sin más y la extensión de VSCode admitía anotaciones de tipo basadas en comentarios sin complicaciones.
Aunque no tengo nada para lo que necesite Lua de inmediato, es otra gran herramienta que tener a mano por su uso tan extendido.
Para terminar

Disfruté este recorrido por los lenguajes más de lo que esperaba. No solo aprendí algunas habilidades prácticas nuevas: siento que mis horizontes se han ampliado de verdad.
En cuanto a lo que viene después, creo que será aprender mucho más Rust. Su importancia en el panorama de las herramientas de desarrollo es evidente a estas alturas y quiero asegurarme de poder leer y contribuir a las cosas en las que me apoyo.
No tengo un objetivo concreto en mente, pero tengo todo el libro de Rust por leer, un curso de Rust para desarrolladores de JS que me costeé un año y un track completo de Exercism por terminar. Me gustaría contribuir al menos a un proyecto de código abierto (probablemente Just, uno de mis programas favoritos del momento), pero ya veremos adónde me lleva el año.
Mientras tanto, ¡felices fiestas y que tengas un buen resto de 2023!
-
¿¿Que las variables sin usar son un error del compilador?? Venga ya ↩
-
En realidad probé primero C++ (que no había tocado desde la universidad). No era divertido, así que lo dejé ↩
-
Esta es otra forma en que el Ruby «real» se diferencia de mi experiencia dentro de Stripe, así que me alegro de haber podido probarlo de las dos maneras ↩